mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-21 10:50:14 +01:00
* chore: fix logging for illegal target endpoints in getEndpointFromSetup * fix: prevent querying agent by ID for ephemeral agents * refactor: reorder variable declarations in MessagesView for clarity * fix: localize 'nothing found' message in MessagesView * refactor: streamline navigation logic and enhance loading spinner component in ChatView * refactor: simplify loading spinner logic in ChatView component * fix: ensure message queries are invalidated after new conversation creation in HeaderNewChat, MobileNav, and NewChat components * 🐛 First run dev mode will have error occur. 🐛 First run dev mode will have error occur. * fix font-size localstorage presist bug * Don't ping meilisearch if the search is disabled via env var * simplify logic in search/enable endpoint * refactor: simplify enable endpoint condition check * feat: add useIdChangeEffect hook and integrate it into ChatRoute --------- Co-authored-by: Ne0 <20765145+zeeklog@users.noreply.github.com> Co-authored-by: TinyTin <garychangcn@hotmail.com> Co-authored-by: Denis Palnitsky <denis.palnitsky@zendesk.com>
82 lines
2.4 KiB
TypeScript
82 lines
2.4 KiB
TypeScript
//ThemeContext.js
|
|
// source: https://plainenglish.io/blog/light-and-dark-mode-in-react-web-application-with-tailwind-css-89674496b942
|
|
import { useSetRecoilState } from 'recoil';
|
|
import React, { createContext, useState, useEffect } from 'react';
|
|
import { getInitialTheme, applyFontSize } from '~/utils';
|
|
import store from '~/store';
|
|
|
|
type ProviderValue = {
|
|
theme: string;
|
|
setTheme: React.Dispatch<React.SetStateAction<string>>;
|
|
};
|
|
|
|
const defaultContextValue: ProviderValue = {
|
|
theme: getInitialTheme(),
|
|
setTheme: () => {
|
|
return;
|
|
},
|
|
};
|
|
|
|
export const isDark = (theme: string): boolean => {
|
|
if (theme === 'system') {
|
|
return window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
}
|
|
return theme === 'dark';
|
|
};
|
|
|
|
export const ThemeContext = createContext<ProviderValue>(defaultContextValue);
|
|
|
|
export const ThemeProvider = ({ initialTheme, children }) => {
|
|
const [theme, setTheme] = useState(getInitialTheme);
|
|
const setFontSize = useSetRecoilState(store.fontSize);
|
|
|
|
const rawSetTheme = (rawTheme: string) => {
|
|
const root = window.document.documentElement;
|
|
const darkMode = isDark(rawTheme);
|
|
|
|
root.classList.remove(darkMode ? 'light' : 'dark');
|
|
root.classList.add(darkMode ? 'dark' : 'light');
|
|
|
|
localStorage.setItem('color-theme', rawTheme);
|
|
};
|
|
|
|
useEffect(() => {
|
|
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
const changeThemeOnSystemChange = () => {
|
|
rawSetTheme(mediaQuery.matches ? 'dark' : 'light');
|
|
};
|
|
|
|
mediaQuery.addEventListener('change', changeThemeOnSystemChange);
|
|
|
|
return () => {
|
|
mediaQuery.removeEventListener('change', changeThemeOnSystemChange);
|
|
};
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
const fontSize = localStorage.getItem('fontSize');
|
|
if (fontSize == null) {
|
|
setFontSize('text-base');
|
|
applyFontSize('text-base');
|
|
localStorage.setItem('fontSize', JSON.stringify('text-base'));
|
|
return;
|
|
}
|
|
try {
|
|
applyFontSize(JSON.parse(fontSize));
|
|
} catch (error) {
|
|
console.log(error);
|
|
}
|
|
// Reason: This effect should only run once, and `setFontSize` is a stable function
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, []);
|
|
|
|
if (initialTheme) {
|
|
rawSetTheme(initialTheme);
|
|
}
|
|
|
|
useEffect(() => {
|
|
rawSetTheme(theme);
|
|
}, [theme]);
|
|
|
|
return <ThemeContext.Provider value={{ theme, setTheme }}>{children}</ThemeContext.Provider>;
|
|
};
|