LibreChat/client/src/App.jsx
Danny Avila 43c2c20dd7
Some checks are pending
Docker Dev Branch Images Build / build (Dockerfile, lc-dev, node) (push) Waiting to run
Docker Dev Branch Images Build / build (Dockerfile.multi, lc-dev-api, api-build) (push) Waiting to run
Docker Dev Images Build / build (Dockerfile, librechat-dev, node) (push) Waiting to run
Docker Dev Images Build / build (Dockerfile.multi, librechat-dev-api, api-build) (push) Waiting to run
Sync Locize Translations & Create Translation PR / Sync Translation Keys with Locize (push) Waiting to run
Sync Locize Translations & Create Translation PR / Create Translation PR on Version Published (push) Blocked by required conditions
🛜 feat: Enable Network Requests in Offline Mode (#11107)
2025-12-26 09:01:27 -05:00

92 lines
3.1 KiB
JavaScript

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({
defaultOptions: {
queries: {
// Always attempt network requests, even when navigator.onLine is false
// This is needed because localhost is reachable without WiFi
networkMode: 'always',
},
mutations: {
networkMode: 'always',
},
},
queryCache: new QueryCache({
onError: (error) => {
if (error?.response?.status === 401) {
setError(error);
}
},
}),
});
useEffect(() => {
initializeFontSize();
}, []);
// Load theme from environment variables if available
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>
);