mirror of
https://github.com/SlimeVR/SlimeVR-Server.git
synced 2026-04-06 02:01:58 +02:00
Fix config shenanigans (#836)
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
export default {
|
||||
"**/*.{ts,tsx}": () => "tsc -p tsconfig.json --noEmit",
|
||||
"**/*.{js,jsx,ts,tsx}": "eslint --cache --fix",
|
||||
"**/*.{js,jsx,ts,tsx}": "eslint --max-warnings=0 --cache --fix",
|
||||
"**/*.{js,jsx,ts,tsx,css,md,json}": "prettier --write"
|
||||
};
|
||||
|
||||
162
gui/src/App.tsx
162
gui/src/App.tsx
@@ -35,7 +35,6 @@ import { SerialDetectionModal } from './components/SerialDetectionModal';
|
||||
import { VRCOSCSettings } from './components/settings/pages/VRCOSCSettings';
|
||||
import { TopBar } from './components/TopBar';
|
||||
import { TrackerSettingsPage } from './components/tracker/TrackerSettings';
|
||||
import { useConfig } from './hooks/config';
|
||||
import { OSCRouterSettings } from './components/settings/pages/OSCRouterSettings';
|
||||
import { useLocalization } from '@fluent/react';
|
||||
import * as os from '@tauri-apps/plugin-os';
|
||||
@@ -52,6 +51,7 @@ import { useBreakpoint } from './hooks/breakpoint';
|
||||
import { VRModePage } from './components/vr-mode/VRModePage';
|
||||
import { InterfaceSettings } from './components/settings/pages/InterfaceSettings';
|
||||
import { error, log } from './utils/logging';
|
||||
import { AppLayout } from './AppLayout';
|
||||
|
||||
export const GH_REPO = 'SlimeVR/SlimeVR-Server';
|
||||
export const VersionContext = createContext('');
|
||||
@@ -59,92 +59,94 @@ export const DOCS_SITE = 'https://docs.slimevr.dev';
|
||||
export const SLIMEVR_DISCORD = 'https://discord.gg/slimevr';
|
||||
|
||||
function Layout() {
|
||||
const { loading } = useConfig();
|
||||
|
||||
if (loading) return <></>;
|
||||
|
||||
const { isMobile } = useBreakpoint('mobile');
|
||||
|
||||
return (
|
||||
<>
|
||||
<SerialDetectionModal></SerialDetectionModal>
|
||||
<VersionUpdateModal></VersionUpdateModal>
|
||||
<Routes>
|
||||
<Route
|
||||
path="/"
|
||||
element={
|
||||
<MainLayoutRoute isMobile={isMobile}>
|
||||
<Home />
|
||||
</MainLayoutRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/vr-mode"
|
||||
element={
|
||||
<MainLayoutRoute isMobile={isMobile}>
|
||||
<VRModePage />
|
||||
</MainLayoutRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/tracker/:trackernum/:deviceid"
|
||||
element={
|
||||
<MainLayoutRoute background={false} isMobile={isMobile}>
|
||||
<TrackerSettingsPage />
|
||||
</MainLayoutRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/settings"
|
||||
element={
|
||||
<SettingsLayoutRoute>
|
||||
<Outlet></Outlet>
|
||||
</SettingsLayoutRoute>
|
||||
}
|
||||
>
|
||||
<Route path="trackers" element={<GeneralSettings />} />
|
||||
<Route path="serial" element={<Serial />} />
|
||||
<Route path="osc/router" element={<OSCRouterSettings />} />
|
||||
<Route path="osc/vrchat" element={<VRCOSCSettings />} />
|
||||
<Route path="osc/vmc" element={<VMCSettings />} />
|
||||
<Route path="interface" element={<InterfaceSettings />} />
|
||||
<Route element={<AppLayout />}>
|
||||
<Route
|
||||
path="/"
|
||||
element={
|
||||
<MainLayoutRoute isMobile={isMobile}>
|
||||
<Home />
|
||||
</MainLayoutRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/vr-mode"
|
||||
element={
|
||||
<MainLayoutRoute isMobile={isMobile}>
|
||||
<VRModePage />
|
||||
</MainLayoutRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/tracker/:trackernum/:deviceid"
|
||||
element={
|
||||
<MainLayoutRoute background={false} isMobile={isMobile}>
|
||||
<TrackerSettingsPage />
|
||||
</MainLayoutRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/settings"
|
||||
element={
|
||||
<SettingsLayoutRoute>
|
||||
<Outlet />
|
||||
</SettingsLayoutRoute>
|
||||
}
|
||||
>
|
||||
<Route path="trackers" element={<GeneralSettings />} />
|
||||
<Route path="serial" element={<Serial />} />
|
||||
<Route path="osc/router" element={<OSCRouterSettings />} />
|
||||
<Route path="osc/vrchat" element={<VRCOSCSettings />} />
|
||||
<Route path="osc/vmc" element={<VMCSettings />} />
|
||||
<Route path="interface" element={<InterfaceSettings />} />
|
||||
</Route>
|
||||
<Route
|
||||
path="/onboarding"
|
||||
element={
|
||||
<OnboardingLayout>
|
||||
<Outlet />
|
||||
</OnboardingLayout>
|
||||
}
|
||||
>
|
||||
<Route path="home" element={<HomePage />} />
|
||||
<Route path="wifi-creds" element={<WifiCredsPage />} />
|
||||
<Route path="connect-trackers" element={<ConnectTrackersPage />} />
|
||||
<Route
|
||||
path="calibration-tutorial"
|
||||
element={<CalibrationTutorialPage />}
|
||||
/>
|
||||
<Route
|
||||
path="assign-tutorial"
|
||||
element={<AssignmentTutorialPage />}
|
||||
/>
|
||||
<Route path="trackers-assign" element={<TrackersAssignPage />} />
|
||||
<Route path="enter-vr" element={<EnterVRPage />} />
|
||||
<Route path="mounting/choose" element={<MountingChoose />}></Route>
|
||||
<Route path="mounting/auto" element={<AutomaticMountingPage />} />
|
||||
<Route path="mounting/manual" element={<ManualMountingPage />} />
|
||||
<Route path="reset-tutorial" element={<ResetTutorialPage />} />
|
||||
<Route
|
||||
path="body-proportions/choose"
|
||||
element={<ProportionsChoose />}
|
||||
/>
|
||||
<Route
|
||||
path="body-proportions/auto"
|
||||
element={<AutomaticProportionsPage />}
|
||||
/>
|
||||
<Route
|
||||
path="body-proportions/manual"
|
||||
element={<ManualProportionsPage />}
|
||||
/>
|
||||
<Route path="done" element={<DonePage />} />
|
||||
</Route>
|
||||
<Route path="*" element={<TopBar></TopBar>}></Route>
|
||||
</Route>
|
||||
<Route
|
||||
path="/onboarding"
|
||||
element={
|
||||
<OnboardingLayout>
|
||||
<Outlet></Outlet>
|
||||
</OnboardingLayout>
|
||||
}
|
||||
>
|
||||
<Route path="home" element={<HomePage />} />
|
||||
<Route path="wifi-creds" element={<WifiCredsPage />} />
|
||||
<Route path="connect-trackers" element={<ConnectTrackersPage />} />
|
||||
<Route
|
||||
path="calibration-tutorial"
|
||||
element={<CalibrationTutorialPage />}
|
||||
/>
|
||||
<Route path="assign-tutorial" element={<AssignmentTutorialPage />} />
|
||||
<Route path="trackers-assign" element={<TrackersAssignPage />} />
|
||||
<Route path="enter-vr" element={<EnterVRPage />} />
|
||||
<Route path="mounting/choose" element={<MountingChoose />}></Route>
|
||||
<Route path="mounting/auto" element={<AutomaticMountingPage />} />
|
||||
<Route path="mounting/manual" element={<ManualMountingPage />} />
|
||||
<Route path="reset-tutorial" element={<ResetTutorialPage />} />
|
||||
<Route
|
||||
path="body-proportions/choose"
|
||||
element={<ProportionsChoose />}
|
||||
/>
|
||||
<Route
|
||||
path="body-proportions/auto"
|
||||
element={<AutomaticProportionsPage />}
|
||||
/>
|
||||
<Route
|
||||
path="body-proportions/manual"
|
||||
element={<ManualProportionsPage />}
|
||||
/>
|
||||
<Route path="done" element={<DonePage />} />
|
||||
</Route>
|
||||
<Route path="*" element={<TopBar></TopBar>}></Route>
|
||||
</Routes>
|
||||
</>
|
||||
);
|
||||
|
||||
51
gui/src/AppLayout.tsx
Normal file
51
gui/src/AppLayout.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
import { useLayoutEffect } from 'react';
|
||||
import { useConfig } from './hooks/config';
|
||||
import { Outlet, useNavigate } from 'react-router-dom';
|
||||
|
||||
export function AppLayout() {
|
||||
const { loading, config } = useConfig();
|
||||
const navigate = useNavigate();
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (loading || !config) return;
|
||||
if (config.theme !== undefined) {
|
||||
document.documentElement.dataset.theme = config.theme;
|
||||
}
|
||||
|
||||
if (config.fonts !== undefined) {
|
||||
document.documentElement.style.setProperty(
|
||||
'--font-name',
|
||||
config.fonts.map((x) => `"${x}"`).join(',')
|
||||
);
|
||||
}
|
||||
|
||||
if (config.textSize !== undefined) {
|
||||
document.documentElement.style.setProperty(
|
||||
'--font-size',
|
||||
`${config.textSize}rem`
|
||||
);
|
||||
}
|
||||
}, [config, loading]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (config && !config.doneOnboarding) {
|
||||
navigate('/onboarding/home');
|
||||
}
|
||||
}, [config?.doneOnboarding]);
|
||||
|
||||
// const location = useLocation();
|
||||
// const navigationType = useNavigationType();
|
||||
// useEffect(() => {
|
||||
// if (import.meta.env.PROD) return;
|
||||
// console.log('The current URL is', { ...location });
|
||||
// console.log('The last navigation action was', navigationType);
|
||||
// }, [location, navigationType]);
|
||||
|
||||
if (loading) return <></>;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Outlet />
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -4,11 +4,9 @@ import {
|
||||
Reducer,
|
||||
useContext,
|
||||
useEffect,
|
||||
useLayoutEffect,
|
||||
useMemo,
|
||||
useReducer,
|
||||
} from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import {
|
||||
BoneT,
|
||||
DataFeedMessage,
|
||||
@@ -59,7 +57,6 @@ export function useProvideAppContext(): AppContext {
|
||||
useWebsocketAPI();
|
||||
const { config } = useConfig();
|
||||
const { dataFeedConfig } = useDataFeedConfig();
|
||||
const navigate = useNavigate();
|
||||
const [state, dispatch] = useReducer<Reducer<AppState, AppStateAction>>(reducer, {
|
||||
datafeed: new DataFeedUpdateT(),
|
||||
});
|
||||
@@ -72,12 +69,6 @@ export function useProvideAppContext(): AppContext {
|
||||
}
|
||||
}, [isConnected]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
if (config && !config.doneOnboarding) {
|
||||
navigate('/onboarding/home');
|
||||
}
|
||||
}, [config]);
|
||||
|
||||
const trackers = useMemo(
|
||||
() =>
|
||||
(state.datafeed?.devices || []).reduce<FlatDeviceTracker[]>(
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { BaseDirectory, readTextFile } from '@tauri-apps/plugin-fs';
|
||||
|
||||
import { createContext, useContext, useRef, useState } from 'react';
|
||||
import { createContext, useContext, useState } from 'react';
|
||||
import { DeveloperModeWidgetForm } from '../components/widgets/DeveloperModeWidget';
|
||||
import { error } from '../utils/logging';
|
||||
import { useDebouncedEffect } from './timeout';
|
||||
|
||||
export interface WindowConfig {
|
||||
width: number;
|
||||
@@ -50,42 +51,28 @@ function fallbackToDefaults(loadedConfig: any): Config {
|
||||
}
|
||||
|
||||
export function useConfigProvider(): ConfigContext {
|
||||
const debounceTimer = useRef<NodeJS.Timeout | null>(null);
|
||||
const [currConfig, set] = useState<Config | null>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
useDebouncedEffect(
|
||||
() => {
|
||||
if (!currConfig) return;
|
||||
|
||||
localStorage.setItem('config.json', JSON.stringify(currConfig));
|
||||
},
|
||||
[currConfig],
|
||||
100
|
||||
);
|
||||
|
||||
const setConfig = async (config: Partial<Config>) => {
|
||||
const newConfig = config
|
||||
? {
|
||||
...currConfig,
|
||||
...config,
|
||||
}
|
||||
: null;
|
||||
set(newConfig as Config);
|
||||
if (config.theme !== undefined) {
|
||||
document.documentElement.dataset.theme = config.theme;
|
||||
}
|
||||
|
||||
if (config.fonts !== undefined) {
|
||||
document.documentElement.style.setProperty(
|
||||
'--font-name',
|
||||
config.fonts.map((x) => `"${x}"`).join(',')
|
||||
);
|
||||
}
|
||||
|
||||
if (config.textSize !== undefined) {
|
||||
document.documentElement.style.setProperty(
|
||||
'--font-size',
|
||||
`${config.textSize}rem`
|
||||
);
|
||||
}
|
||||
|
||||
if (!debounceTimer.current) {
|
||||
debounceTimer.current = setTimeout(async () => {
|
||||
localStorage.setItem('config.json', JSON.stringify(newConfig));
|
||||
debounceTimer.current = null;
|
||||
}, 10);
|
||||
}
|
||||
set((curr) =>
|
||||
config
|
||||
? ({
|
||||
...curr,
|
||||
...config,
|
||||
} as Config)
|
||||
: null
|
||||
);
|
||||
};
|
||||
|
||||
return {
|
||||
@@ -112,15 +99,7 @@ export function useConfigProvider(): ConfigContext {
|
||||
|
||||
const loadedConfig = fallbackToDefaults(JSON.parse(json));
|
||||
set(loadedConfig);
|
||||
document.documentElement.dataset.theme = loadedConfig.theme;
|
||||
document.documentElement.style.setProperty(
|
||||
'--font-size',
|
||||
`${loadedConfig.textSize}rem`
|
||||
);
|
||||
document.documentElement.style.setProperty(
|
||||
'--font-name',
|
||||
loadedConfig.fonts.map((x) => `"${x}"`).join(',')
|
||||
);
|
||||
|
||||
setLoading(false);
|
||||
return loadedConfig;
|
||||
} catch (e) {
|
||||
|
||||
Reference in New Issue
Block a user