forked from open-webui/open-webui
		
	main #2
					 3 changed files with 59 additions and 41 deletions
				
			
		|  | @ -1,6 +1,7 @@ | ||||||
| <script lang="ts"> | <script lang="ts"> | ||||||
| 	import { toast } from 'svelte-sonner'; | 	import { toast } from 'svelte-sonner'; | ||||||
| 	import { createEventDispatcher, onMount } from 'svelte'; | 	import { createEventDispatcher, onMount } from 'svelte'; | ||||||
|  | 	import { theme, setTheme } from '../../../stores/index'; | ||||||
| 	const dispatch = createEventDispatcher(); | 	const dispatch = createEventDispatcher(); | ||||||
| 
 | 
 | ||||||
| 	import { models, user } from '$lib/stores'; | 	import { models, user } from '$lib/stores'; | ||||||
|  | @ -12,41 +13,29 @@ | ||||||
| 
 | 
 | ||||||
| 	// General | 	// General | ||||||
| 	let themes = ['dark', 'light', 'rose-pine dark', 'rose-pine-dawn light']; | 	let themes = ['dark', 'light', 'rose-pine dark', 'rose-pine-dawn light']; | ||||||
| 	let theme = 'dark'; | 	let selectedTheme = 'system'; | ||||||
|  | 	let actualTheme: string; | ||||||
|  | 	$: actualTheme = $theme; | ||||||
| 	let notificationEnabled = false; | 	let notificationEnabled = false; | ||||||
| 	let system = ''; | 	let system = ''; | ||||||
| 
 | 
 | ||||||
| 	let showAdvanced = false; | 	let showAdvanced = false; | ||||||
| 
 | 
 | ||||||
| 	window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => { | 	function applyTheme(theme: string) { // only apply visually | ||||||
|  |         let themeToApply = theme; | ||||||
|         if (theme === 'system') { |         if (theme === 'system') { | ||||||
| 			updateSystemTheme(); |             themeToApply = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; | ||||||
| 		} |  | ||||||
| 	}); |  | ||||||
| 
 |  | ||||||
| 	function updateSystemTheme() { |  | ||||||
| 		const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches; |  | ||||||
| 		const systemTheme = isDarkMode ? 'dark' : 'light'; |  | ||||||
| 		applyTheme(systemTheme); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	function applyTheme(theme: string) { |  | ||||||
| 		localStorage.theme = theme; |  | ||||||
| 
 |  | ||||||
| 		if (theme === 'system') { |  | ||||||
| 			updateSystemTheme(); |  | ||||||
| 			return; |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         themes |         themes | ||||||
| 			.filter((e) => e !== theme) |             .filter((e) => e !== themeToApply) | ||||||
|             .forEach((e) => { |             .forEach((e) => { | ||||||
|                 e.split(' ').forEach((e) => { |                 e.split(' ').forEach((e) => { | ||||||
|                     document.documentElement.classList.remove(e); |                     document.documentElement.classList.remove(e); | ||||||
|                 }); |                 }); | ||||||
|             }); |             }); | ||||||
| 
 | 
 | ||||||
| 		theme.split(' ').forEach((e) => { |         themeToApply.split(' ').forEach((e) => { | ||||||
|             document.documentElement.classList.add(e); |             document.documentElement.classList.add(e); | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|  | @ -98,9 +87,11 @@ | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	onMount(async () => { | 	onMount(async () => { | ||||||
|  | 		selectedTheme = localStorage.getItem('theme') ?? 'system'; | ||||||
|  | 		applyTheme(selectedTheme); | ||||||
|  | 
 | ||||||
| 		let settings = JSON.parse(localStorage.getItem('settings') ?? '{}'); | 		let settings = JSON.parse(localStorage.getItem('settings') ?? '{}'); | ||||||
| 
 | 
 | ||||||
| 		theme = localStorage.theme ?? 'dark'; |  | ||||||
| 		notificationEnabled = settings.notificationEnabled ?? false; | 		notificationEnabled = settings.notificationEnabled ?? false; | ||||||
| 		system = settings.system ?? ''; | 		system = settings.system ?? ''; | ||||||
| 
 | 
 | ||||||
|  | @ -116,6 +107,13 @@ | ||||||
| 		options = { ...options, ...settings.options }; | 		options = { ...options, ...settings.options }; | ||||||
| 		options.stop = (settings?.options?.stop ?? []).join(','); | 		options.stop = (settings?.options?.stop ?? []).join(','); | ||||||
| 	}); | 	}); | ||||||
|  | 
 | ||||||
|  | 	function handleThemeChange(newTheme: string) { | ||||||
|  |         selectedTheme = newTheme; | ||||||
|  |         setTheme(newTheme); // Update the store | ||||||
|  |         localStorage.setItem('theme', newTheme); // Persist the theme selection | ||||||
|  |         applyTheme(newTheme); // Apply the selected theme | ||||||
|  |     } | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <div class="flex flex-col h-full justify-between text-sm"> | <div class="flex flex-col h-full justify-between text-sm"> | ||||||
|  | @ -127,7 +125,7 @@ | ||||||
| 				<div class=" self-center text-xs font-medium">Theme</div> | 				<div class=" self-center text-xs font-medium">Theme</div> | ||||||
| 				<div class="flex items-center relative"> | 				<div class="flex items-center relative"> | ||||||
| 					<div class=" absolute right-16"> | 					<div class=" absolute right-16"> | ||||||
| 						{#if theme === 'dark'} | 						{#if actualTheme === 'dark'} | ||||||
| 							<svg | 							<svg | ||||||
| 								xmlns="http://www.w3.org/2000/svg" | 								xmlns="http://www.w3.org/2000/svg" | ||||||
| 								viewBox="0 0 20 20" | 								viewBox="0 0 20 20" | ||||||
|  | @ -140,7 +138,7 @@ | ||||||
| 									clip-rule="evenodd" | 									clip-rule="evenodd" | ||||||
| 								/> | 								/> | ||||||
| 							</svg> | 							</svg> | ||||||
| 						{:else if theme === 'light'} | 						{:else if actualTheme === 'light'} | ||||||
| 							<svg | 							<svg | ||||||
| 								xmlns="http://www.w3.org/2000/svg" | 								xmlns="http://www.w3.org/2000/svg" | ||||||
| 								viewBox="0 0 20 20" | 								viewBox="0 0 20 20" | ||||||
|  | @ -156,9 +154,9 @@ | ||||||
| 
 | 
 | ||||||
| 					<select | 					<select | ||||||
| 						class="w-fit pr-8 rounded py-2 px-2 text-xs bg-transparent outline-none text-right" | 						class="w-fit pr-8 rounded py-2 px-2 text-xs bg-transparent outline-none text-right" | ||||||
| 						bind:value={theme} | 						bind:value={selectedTheme} | ||||||
| 						placeholder="Select a theme" | 						placeholder="Select a theme" | ||||||
| 						on:change="{() => applyTheme(theme)}" | 						on:change="{() => handleThemeChange(selectedTheme)}" | ||||||
| 					> | 					> | ||||||
| 						<option value="system">System</option> | 						<option value="system">System</option> | ||||||
| 						<option value="dark">Dark</option> | 						<option value="dark">Dark</option> | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| import { APP_NAME } from '$lib/constants'; | import { APP_NAME } from '$lib/constants'; | ||||||
| import { writable } from 'svelte/store'; | import { writable, derived } from 'svelte/store'; | ||||||
| 
 | 
 | ||||||
| // Backend
 | // Backend
 | ||||||
| export const WEBUI_NAME = writable(APP_NAME); | export const WEBUI_NAME = writable(APP_NAME); | ||||||
|  | @ -7,7 +7,27 @@ export const config = writable(undefined); | ||||||
| export const user = writable(undefined); | export const user = writable(undefined); | ||||||
| 
 | 
 | ||||||
| // Frontend
 | // Frontend
 | ||||||
| export const theme = writable('dark'); | const rawThemeSetting = writable('system'); | ||||||
|  | export const theme = derived(rawThemeSetting, ($rawThemeSetting) => { | ||||||
|  | 	if ($rawThemeSetting === 'system') { | ||||||
|  | 		return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; | ||||||
|  | 	} | ||||||
|  | 	return $rawThemeSetting; | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => { | ||||||
|  | 	rawThemeSetting.update((currentTheme) => { | ||||||
|  | 		if (currentTheme === 'system') { | ||||||
|  | 			return e.matches ? 'dark' : 'light'; | ||||||
|  | 		} | ||||||
|  | 		return currentTheme; | ||||||
|  | 	}); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | export function setTheme(theme){ | ||||||
|  | 	rawThemeSetting.set(theme); | ||||||
|  | 	localStorage.setItem('theme', theme); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| export const chatId = writable(''); | export const chatId = writable(''); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| <script> | <script> | ||||||
| 	import { onMount, tick } from 'svelte'; | 	import { onMount, tick } from 'svelte'; | ||||||
| 	import { config, user, theme, WEBUI_NAME } from '$lib/stores'; | 	import { config, user, setTheme, WEBUI_NAME } from '$lib/stores'; | ||||||
| 	import { goto } from '$app/navigation'; | 	import { goto } from '$app/navigation'; | ||||||
| 	import { Toaster, toast } from 'svelte-sonner'; | 	import { Toaster, toast } from 'svelte-sonner'; | ||||||
| 
 | 
 | ||||||
|  | @ -15,7 +15,7 @@ | ||||||
| 	let loaded = false; | 	let loaded = false; | ||||||
| 
 | 
 | ||||||
| 	onMount(async () => { | 	onMount(async () => { | ||||||
| 		theme.set(localStorage.theme); | 		setTheme(localStorage.theme) | ||||||
| 		// Check Backend Status | 		// Check Backend Status | ||||||
| 		const backendConfig = await getBackendConfig(); | 		const backendConfig = await getBackendConfig(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue