diff --git a/src-web/components/DefaultLayout.tsx b/src-web/components/DefaultLayout.tsx
index e81341b6..2bb5e110 100644
--- a/src-web/components/DefaultLayout.tsx
+++ b/src-web/components/DefaultLayout.tsx
@@ -1,5 +1,4 @@
import classNames from 'classnames';
-import { motion } from 'framer-motion';
import { Outlet } from 'react-router-dom';
import { useOsInfo } from '../hooks/useOsInfo';
import { DialogProvider, Dialogs } from './DialogContext';
@@ -16,17 +15,14 @@ export function DefaultLayout() {
>
-
-
+
diff --git a/src-web/components/GlobalHooks.tsx b/src-web/components/GlobalHooks.tsx
index d7ac6e20..a804e297 100644
--- a/src-web/components/GlobalHooks.tsx
+++ b/src-web/components/GlobalHooks.tsx
@@ -25,7 +25,6 @@ import { useRecentRequests } from '../hooks/useRecentRequests';
import { useRecentWorkspaces } from '../hooks/useRecentWorkspaces';
import { useRequestUpdateKey } from '../hooks/useRequestUpdateKey';
import { settingsAtom, useSettings } from '../hooks/useSettings';
-import { useSyncThemeToDocument } from '../hooks/useSyncThemeToDocument';
import { useToggleCommandPalette } from '../hooks/useToggleCommandPalette';
import { workspacesAtom } from '../hooks/useWorkspaces';
import { useZoom } from '../hooks/useZoom';
@@ -39,6 +38,11 @@ import { rosePineDefault } from '../lib/theme/themes/rose-pine';
import { yaakDark } from '../lib/theme/themes/yaak';
import { getThemeCSS } from '../lib/theme/window';
+export interface ModelPayload {
+ model: AnyModel;
+ windowLabel: string;
+}
+
export function GlobalHooks() {
// Include here so they always update, even if no component references them
useRecentWorkspaces();
@@ -47,7 +51,6 @@ export function GlobalHooks() {
useRecentRequests();
// Other useful things
- useSyncThemeToDocument();
useNotificationToast();
useActiveWorkspaceChangedToast();
useEnsureActiveCookieJar();
@@ -61,11 +64,6 @@ export function GlobalHooks() {
const queryClient = useQueryClient();
const { wasUpdatedExternally } = useRequestUpdateKey(null);
- interface ModelPayload {
- model: AnyModel;
- windowLabel: string;
- }
-
const setSettings = useSetAtom(settingsAtom);
const setWorkspaces = useSetAtom(workspacesAtom);
const setPlugins = useSetAtom(pluginsAtom);
diff --git a/src-web/components/ResponsePane.tsx b/src-web/components/ResponsePane.tsx
index 1c21c13e..cf5e94a3 100644
--- a/src-web/components/ResponsePane.tsx
+++ b/src-web/components/ResponsePane.tsx
@@ -117,9 +117,11 @@ export const ResponsePane = memo(function ResponsePane({ style, className, activ
>
{activeResponse && (
{activeResponse.elapsed > 0 && (
diff --git a/src-web/components/Settings/SettingsAppearance.tsx b/src-web/components/Settings/SettingsAppearance.tsx
index cb41b176..443fe6c6 100644
--- a/src-web/components/Settings/SettingsAppearance.tsx
+++ b/src-web/components/Settings/SettingsAppearance.tsx
@@ -3,10 +3,10 @@ import { useActiveWorkspace } from '../../hooks/useActiveWorkspace';
import { useResolvedAppearance } from '../../hooks/useResolvedAppearance';
import { useResolvedTheme } from '../../hooks/useResolvedTheme';
import { useSettings } from '../../hooks/useSettings';
-import { useThemes } from '../../hooks/useThemes';
import { useUpdateSettings } from '../../hooks/useUpdateSettings';
import { trackEvent } from '../../lib/analytics';
import { clamp } from '../../lib/clamp';
+import { getThemes } from '../../lib/theme/themes';
import { isThemeDark } from '../../lib/theme/window';
import type { ButtonProps } from '../core/Button';
import { Checkbox } from '../core/Checkbox';
@@ -52,12 +52,13 @@ const icons: IconProps['icon'][] = [
'send_horizontal',
];
+const { themes } = getThemes();
+
export function SettingsAppearance() {
const workspace = useActiveWorkspace();
const settings = useSettings();
const updateSettings = useUpdateSettings();
const appearance = useResolvedAppearance();
- const { themes } = useThemes();
const activeTheme = useResolvedTheme();
if (settings == null || workspace == null) {
@@ -161,9 +162,10 @@ export function SettingsAppearance() {
space={3}
className="mt-3 w-full bg-surface p-3 border border-dashed border-border-subtle rounded overflow-x-auto"
>
-
- Theme Preview{' '}
+
+ {activeTheme.active.name}
+ (preview)
{buttonColors.map((c, i) => (
diff --git a/src-web/components/Settings/SettingsDesign.tsx b/src-web/components/Settings/SettingsDesign.tsx
index 58c96929..60f9d5e0 100644
--- a/src-web/components/Settings/SettingsDesign.tsx
+++ b/src-web/components/Settings/SettingsDesign.tsx
@@ -1,9 +1,9 @@
import { open } from '@tauri-apps/plugin-dialog';
import React, { useState } from 'react';
import { useLocalStorage } from 'react-use';
-import { useThemes } from '../../hooks/useThemes';
import { capitalize } from '../../lib/capitalize';
import { invokeCmd } from '../../lib/tauri';
+import { getThemes } from '../../lib/theme/themes';
import { yaakDark } from '../../lib/theme/themes/yaak';
import { getThemeCSS } from '../../lib/theme/window';
import { Banner } from '../core/Banner';
@@ -45,9 +45,9 @@ const icons: IconProps['icon'][] = [
'send_horizontal',
];
-export function SettingsDesign() {
- const themes = useThemes();
+const themes = getThemes();
+export function SettingsDesign() {
const [exportDir, setExportDir] = useLocalStorage('theme_export_dir', null);
const [loadingExport, setLoadingExport] = useState(false);
diff --git a/src-web/hooks/usePreferredAppearance.ts b/src-web/hooks/usePreferredAppearance.ts
index 50fa40f0..669f4b78 100644
--- a/src-web/hooks/usePreferredAppearance.ts
+++ b/src-web/hooks/usePreferredAppearance.ts
@@ -1,18 +1,9 @@
import { useEffect, useState } from 'react';
import type { Appearance } from '../lib/theme/appearance';
-import {
- getCSSAppearance,
- getWindowAppearance,
- subscribeToWindowAppearanceChange,
-} from '../lib/theme/appearance';
+import { getCSSAppearance, subscribeToPreferredAppearance } from '../lib/theme/appearance';
export function usePreferredAppearance() {
const [preferredAppearance, setPreferredAppearance] = useState(getCSSAppearance());
-
- useEffect(() => {
- getWindowAppearance().then(setPreferredAppearance);
- return subscribeToWindowAppearanceChange(setPreferredAppearance);
- }, []);
-
+ useEffect(() => subscribeToPreferredAppearance(setPreferredAppearance), []);
return preferredAppearance;
}
diff --git a/src-web/hooks/useResolvedAppearance.ts b/src-web/hooks/useResolvedAppearance.ts
index 7702fb02..92fc54ba 100644
--- a/src-web/hooks/useResolvedAppearance.ts
+++ b/src-web/hooks/useResolvedAppearance.ts
@@ -1,14 +1,9 @@
+import { resolveAppearance } from '../lib/theme/appearance';
import { usePreferredAppearance } from './usePreferredAppearance';
import { useSettings } from './useSettings';
export function useResolvedAppearance() {
const preferredAppearance = usePreferredAppearance();
-
const settings = useSettings();
- const appearance =
- settings == null || settings?.appearance === 'system'
- ? preferredAppearance
- : settings.appearance;
-
- return appearance;
+ return resolveAppearance(preferredAppearance, settings.appearance);
}
diff --git a/src-web/hooks/useResolvedTheme.ts b/src-web/hooks/useResolvedTheme.ts
index 47e79144..9b29099a 100644
--- a/src-web/hooks/useResolvedTheme.ts
+++ b/src-web/hooks/useResolvedTheme.ts
@@ -1,20 +1,14 @@
-import { isThemeDark } from '../lib/theme/window';
-import { useResolvedAppearance } from './useResolvedAppearance';
+import { getResolvedTheme } from '../lib/theme/themes';
+import { usePreferredAppearance } from './usePreferredAppearance';
import { useSettings } from './useSettings';
-import { useThemes } from './useThemes';
export function useResolvedTheme() {
- const appearance = useResolvedAppearance();
+ const preferredAppearance = usePreferredAppearance();
const settings = useSettings();
- const { themes, fallback } = useThemes();
-
- const darkThemes = themes.filter((t) => isThemeDark(t));
- const lightThemes = themes.filter((t) => !isThemeDark(t));
-
- const dark = darkThemes.find((t) => t.id === settings?.themeDark) ?? fallback.dark;
- const light = lightThemes.find((t) => t.id === settings?.themeLight) ?? fallback.light;
-
- const active = appearance === 'dark' ? dark : light;
-
- return { dark, light, active };
+ return getResolvedTheme(
+ preferredAppearance,
+ settings.appearance,
+ settings.themeLight,
+ settings.themeDark,
+ );
}
diff --git a/src-web/hooks/useSyncThemeToDocument.ts b/src-web/hooks/useSyncThemeToDocument.ts
deleted file mode 100644
index d7089456..00000000
--- a/src-web/hooks/useSyncThemeToDocument.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { emit } from '@tauri-apps/api/event';
-import { useEffect } from 'react';
-import type { YaakTheme } from '../lib/theme/window';
-import { addThemeStylesToDocument, setThemeOnDocument } from '../lib/theme/window';
-import { useResolvedTheme } from './useResolvedTheme';
-
-export function useSyncThemeToDocument() {
- const theme = useResolvedTheme();
-
- useEffect(() => {
- setThemeOnDocument(theme.active);
- emitBgChange(theme.active);
- }, [theme.active]);
-
- useEffect(() => {
- addThemeStylesToDocument(theme.active);
- }, [theme.active]);
-}
-
-function emitBgChange(t: YaakTheme) {
- if (t.surface == null) return;
- emit('yaak_bg_changed', t.surface.hexNoAlpha()).catch(console.error);
-}
diff --git a/src-web/hooks/useThemes.ts b/src-web/hooks/useThemes.ts
deleted file mode 100644
index eb2b7123..00000000
--- a/src-web/hooks/useThemes.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { defaultDarkTheme, defaultLightTheme, yaakThemes } from '../lib/theme/themes';
-
-export function useThemes() {
- const dark = defaultDarkTheme;
- const light = defaultLightTheme;
-
- const otherThemes = yaakThemes
- .filter((t) => t.id !== dark.id && t.id !== light.id)
- .sort((a, b) => a.name.localeCompare(b.name));
-
- const themes = [dark, light, ...otherThemes];
- return { themes, fallback: { dark, light } };
-}
diff --git a/src-web/index.html b/src-web/index.html
index 8cfafc4c..9dd320c5 100644
--- a/src-web/index.html
+++ b/src-web/index.html
@@ -26,6 +26,7 @@
+