Files

53 lines
2.0 KiB
TypeScript

/// <reference path="./virtual-font.d.ts" />
import 'virtual:font'
import { CssBaseline, ThemeProvider, createTheme, type ThemeOptions } from '@mui/material'
import { StrictMode, type ReactNode } from 'react'
import { createRoot } from 'react-dom/client'
import Card from './Card.tsx'
import { REGULAR } from './fonts.ts'
/**
* The theme of the applications: light, dark and system modes, the choice stored in localStorage by MUI, the Regular
* font on every element and text fields of the small size. colorSchemes replaces the plain light and dark schemes,
* such as to add palette entries of a component.
*/
export function appTheme(colorSchemes: ThemeOptions['colorSchemes'] = { dark: true }) {
return createTheme({
colorSchemes,
cssVariables: { colorSchemeSelector: 'class' },
typography: { fontFamily: REGULAR },
components: { MuiTextField: { defaultProps: { size: 'small' } } },
})
}
/**
* Renders the application into #root with the theme and the fonts of the font plugin: app with what load answers,
* typically the backend's information. load is tried up to 20 times, 500 ms apart, showing Connecting, and then Not
* available with the last error.
*/
export async function renderApp<T>(options: { theme: ReturnType<typeof createTheme>; load: () => Promise<T>; app: (loaded: T) => ReactNode }) {
const root = createRoot(document.getElementById('root')!)
const render = (node: ReactNode) => {
root.render(
<StrictMode>
<ThemeProvider theme={options.theme}>
<CssBaseline />
{node}
</ThemeProvider>
</StrictMode>,
)
}
let lastError = ''
for (let attempt = 0; attempt < 20; attempt++) {
try {
render(options.app(await options.load()))
return
} catch (error) {
lastError = (error as Error).message
render(<Card title="Connecting" message="Waiting for the backend to answer." />)
await new Promise((resolve) => setTimeout(resolve, 500))
}
}
render(<Card title="Not available" message={lastError} />)
}