53 lines
2.0 KiB
TypeScript
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} />)
|
|
}
|