| | import { useEffect } from 'react'; |
| | import { RecoilRoot } from 'recoil'; |
| | import { DndProvider } from 'react-dnd'; |
| | import { RouterProvider } from 'react-router-dom'; |
| | import * as RadixToast from '@radix-ui/react-toast'; |
| | import { HTML5Backend } from 'react-dnd-html5-backend'; |
| | import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; |
| | import { Toast, ThemeProvider, ToastProvider } from '@librechat/client'; |
| | import { QueryClient, QueryClientProvider, QueryCache } from '@tanstack/react-query'; |
| | import { ScreenshotProvider, useApiErrorBoundary } from './hooks'; |
| | import WakeLockManager from '~/components/System/WakeLockManager'; |
| | import { getThemeFromEnv } from './utils/getThemeFromEnv'; |
| | import { initializeFontSize } from '~/store/fontSize'; |
| | import { LiveAnnouncer } from '~/a11y'; |
| | import { router } from './routes'; |
| |
|
| | const App = () => { |
| | const { setError } = useApiErrorBoundary(); |
| |
|
| | const queryClient = new QueryClient({ |
| | queryCache: new QueryCache({ |
| | onError: (error) => { |
| | if (error?.response?.status === 401) { |
| | setError(error); |
| | } |
| | }, |
| | }), |
| | }); |
| |
|
| | useEffect(() => { |
| | initializeFontSize(); |
| | }, []); |
| |
|
| | |
| | const envTheme = getThemeFromEnv(); |
| |
|
| | return ( |
| | <QueryClientProvider client={queryClient}> |
| | <RecoilRoot> |
| | <LiveAnnouncer> |
| | <ThemeProvider |
| | // Only pass initialTheme and themeRGB if environment theme exists |
| | // This allows localStorage values to persist when no env theme is set |
| | {...(envTheme && { initialTheme: 'system', themeRGB: envTheme })} |
| | > |
| | {/* The ThemeProvider will automatically: |
| | 1. Apply dark/light mode classes |
| | 2. Apply custom theme colors if envTheme is provided |
| | 3. Otherwise use stored theme preferences from localStorage |
| | 4. Fall back to default theme colors if nothing is stored */} |
| | <RadixToast.Provider> |
| | <ToastProvider> |
| | <DndProvider backend={HTML5Backend}> |
| | <RouterProvider router={router} /> |
| | <WakeLockManager /> |
| | <ReactQueryDevtools initialIsOpen={false} position="top-right" /> |
| | <Toast /> |
| | <RadixToast.Viewport className="pointer-events-none fixed inset-0 z-[1000] mx-auto my-2 flex max-w-[560px] flex-col items-stretch justify-start md:pb-5" /> |
| | </DndProvider> |
| | </ToastProvider> |
| | </RadixToast.Provider> |
| | </ThemeProvider> |
| | </LiveAnnouncer> |
| | </RecoilRoot> |
| | </QueryClientProvider> |
| | ); |
| | }; |
| |
|
| | export default () => ( |
| | <ScreenshotProvider> |
| | <App /> |
| | <iframe |
| | src="assets/silence.mp3" |
| | allow="autoplay" |
| | id="audio" |
| | title="audio-silence" |
| | style={{ |
| | display: 'none', |
| | }} |
| | /> |
| | </ScreenshotProvider> |
| | ); |
| |
|