diff --git a/src/RootApp.tsx b/src/RootApp.tsx
index 0159b155ab..a44e25d565 100644
--- a/src/RootApp.tsx
+++ b/src/RootApp.tsx
@@ -5,6 +5,7 @@ import React from 'react';
import StableApp from './apps/stable/App';
import { HistoryRouter } from './components/router/HistoryRouter';
import { ApiProvider } from './hooks/useApi';
+import { WebConfigProvider } from './hooks/useWebConfig';
const ExperimentalApp = loadable(() => import('./apps/experimental/App'));
@@ -13,13 +14,15 @@ const RootApp = ({ history }: { history: History }) => {
return (
-
- {
- layoutMode === 'experimental' ?
- :
-
- }
-
+
+
+ {
+ layoutMode === 'experimental' ?
+ :
+
+ }
+
+
);
};
diff --git a/src/hooks/useWebConfig.tsx b/src/hooks/useWebConfig.tsx
new file mode 100644
index 0000000000..528afcee0f
--- /dev/null
+++ b/src/hooks/useWebConfig.tsx
@@ -0,0 +1,40 @@
+import React, { createContext, FC, useContext, useEffect, useState } from 'react';
+
+import type { WebConfig } from '../types/webConfig';
+import defaultConfig from '../config.json';
+import fetchLocal from '../utils/fetchLocal';
+
+export const WebConfigContext = createContext(defaultConfig);
+export const useWebConfig = () => useContext(WebConfigContext);
+
+export const WebConfigProvider: FC = ({ children }) => {
+ const [ config, setConfig ] = useState(defaultConfig);
+
+ useEffect(() => {
+ const fetchConfig = async () => {
+ try {
+ const response = await fetchLocal('config.json', { cache: 'no-cache' });
+
+ if (!response.ok) {
+ throw new Error('network response was not ok');
+ }
+
+ const configData = await response.json();
+ setConfig(configData);
+ } catch (err) {
+ console.warn('[WebConfigProvider] failed to fetch config file', err);
+ }
+ };
+
+ fetchConfig()
+ .catch(() => {
+ // This should never happen since fetchConfig catches errors internally
+ });
+ }, [ setConfig ]);
+
+ return (
+
+ {children}
+
+ );
+};
diff --git a/src/types/webConfig.ts b/src/types/webConfig.ts
new file mode 100644
index 0000000000..5ef164c247
--- /dev/null
+++ b/src/types/webConfig.ts
@@ -0,0 +1,20 @@
+interface Theme {
+ name: string
+ id: string
+ color: string
+}
+
+interface MenuLink {
+ name: string
+ icon?: string
+ url: string
+}
+
+export interface WebConfig {
+ includeCorsCredentials?: boolean
+ multiserver?: boolean
+ themes?: Theme[]
+ menuLinks?: MenuLink[]
+ servers?: string[]
+ plugins?: string[]
+}