@mui/material#CssBaseline TypeScript Examples

The following examples show how to use @mui/material#CssBaseline. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: App.tsx    From GTAV-NativeDB with MIT License 6 votes vote down vote up
export default function App() {
  return (
    <StoreProvider store={store}>
      <PersistGate loading={null} persistor={persistor}>
        <OnlineStatusProvider>
          <BrowserRouter>
            <Theme>
              <CssBaseline />
              <NativeLoader />
              <LoadGate />
            </Theme>
          </BrowserRouter>
        </OnlineStatusProvider>
      </PersistGate>
    </StoreProvider>
  )
}
Example #2
Source File: theme-provider.component.tsx    From master-frontend-lemoncode with MIT License 6 votes vote down vote up
ThemeProviderComponent = (props) => {
  const { children } = props;

  return (
    <CacheProvider value={cache}>
      <ThemeProvider theme={theme}>
        <CssBaseline />
        {children}
      </ThemeProvider>
    </CacheProvider>
  );
}
Example #3
Source File: index.tsx    From example with MIT License 6 votes vote down vote up
ReactDOM.render(
  <React.StrictMode>
      <CssBaseline />
      <ThemeProvider theme={appTheme}>
          <BrowserRouter>
              <App />
          </BrowserRouter>
      </ThemeProvider>
  </React.StrictMode>,
  document.getElementById('root')
);
Example #4
Source File: _app.tsx    From bouncecode-cms with GNU General Public License v3.0 6 votes vote down vote up
function MyApp(props) {
  const {Component, pageProps, req} = props;
  const getLayout = Component.getLayout ?? (page => page);
  const apolloClient = useApollo(pageProps, req);

  React.useEffect(() => {
    // Remove the server-side injected CSS.
    const jssStyles = document.querySelector('#jss-server-side');
    if (jssStyles) {
      jssStyles.parentElement.removeChild(jssStyles);
    }
  }, []);

  return (
    <React.Fragment>
      <Head>
        <title>BounceCode CMS</title>
        <meta
          name="viewport"
          content="minimum-scale=1, initial-scale=1, width=device-width"
        />
      </Head>
      <ApolloProvider client={apolloClient}>
        <ThemeProvider theme={theme}>
          {/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}
          <CssBaseline />
          <PageLoading />
          <SnackbarProvider>
            {getLayout(<Component {...pageProps} />)}
          </SnackbarProvider>
        </ThemeProvider>
      </ApolloProvider>
    </React.Fragment>
  );
}
Example #5
Source File: main.tsx    From rewind with MIT License 6 votes vote down vote up
ReactDOM.render(
  <StrictMode>
    <AppInfoProvider appInfo={appInfo}>
      <TheaterProvider theater={theater}>
        <ThemeProvider theme={RewindTheme}>
          <CssBaseline />
          <WebTestApp />
        </ThemeProvider>
      </TheaterProvider>
    </AppInfoProvider>
  </StrictMode>,

  document.getElementById("root"),
);
Example #6
Source File: App.tsx    From abrechnung with GNU Affero General Public License v3.0 5 votes vote down vote up
export default function App() {
    const darkModeSystem = useMediaQuery("(prefers-color-scheme: dark)");
    const userThemeSettings = useRecoilValue(themeSettings);

    const useDarkMode: PaletteMode =
        userThemeSettings.darkMode === "browser" ? (darkModeSystem ? "dark" : "light") : userThemeSettings.darkMode;

    const theme = useMemo(
        () =>
            createTheme({
                palette: {
                    mode: useDarkMode,
                },
            }),
        [useDarkMode]
    );

    return (
        <StyledEngineProvider injectFirst>
            <ThemeProvider theme={theme}>
                <CssBaseline />
                <LocalizationProvider dateAdapter={DateAdapter}>
                    <ToastContainer
                        position="top-right"
                        autoClose={5000}
                        hideProgressBar={false}
                        newestOnTop={false}
                        closeOnClick
                        rtl={false}
                        pauseOnFocusLoss
                        draggable
                        pauseOnHover
                    />
                    <Router>
                        <Switch>
                            {routes.map((route) => {
                                const authRoute = route.auth ? (
                                    <AuthenticatedRoute>{route.component}</AuthenticatedRoute>
                                ) : (
                                    route.component
                                );

                                const layoutRoute =
                                    route.layout === undefined || route.layout ? (
                                        <Layout>
                                            <Suspense fallback={<Loading />}>{authRoute}</Suspense>
                                        </Layout>
                                    ) : (
                                        <Suspense fallback={<Loading />}>{authRoute}</Suspense>
                                    );

                                return (
                                    <Route
                                        key={route.path}
                                        exact={route.exact !== undefined && route.exact}
                                        path={route.path}
                                    >
                                        {layoutRoute}
                                    </Route>
                                );
                            })}
                        </Switch>
                    </Router>
                </LocalizationProvider>
            </ThemeProvider>
        </StyledEngineProvider>
    );
}
Example #7
Source File: ToolpadApp.tsx    From mui-toolpad with MIT License 5 votes vote down vote up
export default function ToolpadApp({ basename, appId, version, dom }: ToolpadAppProps) {
  const root = appDom.getApp(dom);
  const { pages = [], themes = [] } = appDom.getChildNodes(dom, root);

  const theme = themes.length > 0 ? themes[0] : null;

  const appContext = React.useMemo(() => ({ appId, version }), [appId, version]);

  const queryClient = React.useMemo(
    () =>
      new QueryClient({
        defaultOptions: {
          queries: {
            retry: false,
          },
        },
      }),
    [],
  );

  const [resetNodeErrorsKey, setResetNodeErrorsKey] = React.useState(0);

  React.useEffect(() => setResetNodeErrorsKey((key) => key + 1), [dom]);

  return (
    <AppRoot id={HTML_ID_APP_ROOT}>
      <NoSsr>
        <DomContextProvider value={dom}>
          <AppThemeProvider node={theme}>
            <CssBaseline />
            <ErrorBoundary FallbackComponent={AppError}>
              <ResetNodeErrorsKeyProvider value={resetNodeErrorsKey}>
                <React.Suspense fallback={<AppLoading />}>
                  <JsRuntimeProvider>
                    <AppContextProvider value={appContext}>
                      <QueryClientProvider client={queryClient}>
                        <BrowserRouter basename={basename}>
                          <Routes>
                            <Route path="/" element={<Navigate replace to="/pages" />} />
                            <Route path="/pages" element={<AppOverview dom={dom} />} />
                            {pages.map((page) => (
                              <Route
                                key={page.id}
                                path={`/pages/${page.id}`}
                                element={
                                  <ComponentsContext dom={dom} page={page}>
                                    <RenderedPage nodeId={page.id} />
                                  </ComponentsContext>
                                }
                              />
                            ))}
                          </Routes>
                        </BrowserRouter>
                      </QueryClientProvider>
                    </AppContextProvider>
                  </JsRuntimeProvider>
                </React.Suspense>
              </ResetNodeErrorsKeyProvider>
            </ErrorBoundary>
          </AppThemeProvider>
        </DomContextProvider>
      </NoSsr>
    </AppRoot>
  );
}
Example #8
Source File: App.tsx    From genshin-optimizer with MIT License 5 votes vote down vote up
function App() {
  const [database, setDatabase] = useState(() => new ArtCharDatabase(new DBLocalStorage(localStorage)))
  const dbContextObj = useMemo(() => ({ database, setDatabase }), [database, setDatabase])
  return <React.StrictMode>
    {/* https://mui.com/guides/interoperability/#css-injection-order-2 */}
    <StyledEngineProvider injectFirst>
      <ThemeProvider theme={theme}>
        <CssBaseline />
        <DatabaseContext.Provider value={dbContextObj}>
          <HashRouter basename="/">
            <MatchTitle />
            <Grid container direction="column" minHeight="100vh">
              <Grid item >
                <Header anchor="back-to-top-anchor" />
              </Grid>
              <Container maxWidth="xl" sx={{ px: { xs: 0.5, sm: 1, md: 2 } }}>
                <Suspense fallback={<Skeleton variant="rectangular" sx={{ width: "100%", height: "100%" }} />}>
                  <Routes>
                    <Route index element={<PageHome />} />
                    <Route path="/artifacts" element={<PageArtifact />} />
                    <Route path="/weapons" element={<PageWeapon />} />
                    <Route path="/characters/*"  >
                      <Route index element={<PageCharacter />} />
                      <Route path=":characterKey/*" element={<CharacterDisplay />} />
                    </Route>
                    <Route path="/tools" element={<PageTools />} />
                    <Route path="/setting" element={<PageSettings />} />
                    <Route path="/doc/*" element={<PageDocumentation />} />
                    <Route path="/scanner" element={<PageScanner />} />
                  </Routes>
                </Suspense>
              </Container>
              {/* make sure footer is always at bottom */}
              <Grid item flexGrow={1} />
              <Grid item >
                <Footer />
              </Grid>
            </Grid>
            <ScrollTop >
              <Fab color="secondary" size="small" aria-label="scroll back to top">
                <KeyboardArrowUp />
              </Fab>
            </ScrollTop>
          </HashRouter>
        </DatabaseContext.Provider>
      </ThemeProvider>
    </StyledEngineProvider>
  </React.StrictMode>
}
Example #9
Source File: main.tsx    From rewind with MIT License 5 votes vote down vote up
async function initialize() {
  let api: FrontendPreloadAPI;
  if (window.api) {
    api = window.api;
  } else {
    api = {
      getAppVersion: () => Promise.resolve(environment.appVersion),
      getPlatform: () => Promise.resolve(environment.platform),
      reboot: () => console.log("Rebooting ..."),
      selectDirectory: () => Promise.resolve("C:\\Mocked\\Path"),
      selectFile: () => Promise.resolve("C:\\Mocked\\File.osr"),
      onManualReplayOpen: (listener) => console.log(`Registered a listener for opening replay files manually`),
    };
  }
  const [appVersion, platform] = await Promise.all([api.getAppVersion(), api.getPlatform()]);
  const appInfo = { appVersion, platform };

  console.log(`Initializing with version=${appVersion} on platform=${platform}`);

  api.onManualReplayOpen((file) => {
    // todo: refactor
    // Changes to the analyzer page
    store.dispatch(push("/analyzer"));
    theater.analyzer.loadReplay(`local:${file}`);
  });

  ReactDOM.render(
    <StrictMode>
      <AppInfoProvider appInfo={appInfo}>
        <Provider store={store}>
          <ConnectedRouter history={history}>
            <ThemeProvider theme={RewindTheme}>
              <CssBaseline />
              <TheaterProvider theater={theater}>
                <RewindApp />
              </TheaterProvider>
            </ThemeProvider>
          </ConnectedRouter>
        </Provider>
      </AppInfoProvider>
    </StrictMode>,
    document.getElementById("root"),
  );

  // This starts off with /splash -> Maybe do it somewhere else?
  store.dispatch(push("/splash"));
}
Example #10
Source File: AppTheme.tsx    From airmessage-web with Apache License 2.0 5 votes vote down vote up
export default function AppTheme(props: {children: React.ReactNode}) {
	const prefersDarkMode = useMediaQuery("(prefers-color-scheme: dark)");
	
	const theme = React.useMemo(() => createTheme({
		typography: {
			fontFamily: [
				"-apple-system",
				"BlinkMacSystemFont",
				'"Segoe UI"',
				"Roboto",
				'"Helvetica Neue"',
				"Arial",
				"sans-serif",
				'"Apple Color Emoji"',
				'"Segoe UI Emoji"',
				'"Segoe UI Symbol"',
			].join(","),
		},
		palette: {
			mode: prefersDarkMode ? "dark" : "light",
			primary: {
				main: "#448AFF",
				dark: "#366FCC",
				light: "#52A7FF",
			},
			messageIncoming: prefersDarkMode ? {
				main: "#393939",
				contrastText: "#FFF"
			} : {
				main: "#EDEDED",
				contrastText: "rgba(0, 0, 0, 0.87)"
			},
			messageOutgoing: {
				main: "#448AFF",
				contrastText: "#FFF",
			},
			messageOutgoingTextMessage: {
				main: "#2ECC71",
				contrastText: "#FFF",
			},
			divider: prefersDarkMode ? "rgba(255, 255, 255, 0.1)" : "#EEEEEE",
			background: {
				default: prefersDarkMode ? "#1E1E1E" : "#FFFFFF",
				sidebar: prefersDarkMode ? "#272727" : "#FAFAFA"
			}
		},
		components: {
			MuiCssBaseline: {
				styleOverrides: {
					"@global": {
						html: {
							scrollbarColor: prefersDarkMode ? "#303030 #424242" : undefined
						}
					}
				}
			}
		}
	}), [prefersDarkMode]);
	
	return (
		<ThemeProvider theme={theme}>
			<CssBaseline />
			{props.children}
		</ThemeProvider>
	);
}
Example #11
Source File: _app.tsx    From fluttertemplates.dev with MIT License 5 votes vote down vote up
function MyApp({ Component, pageProps }: AppProps) {
  const [darkMode, setDarkMode] = useState<boolean>(false);

  useEffect(() => {
    const _item = localStorage.getItem("darkMode") ?? "false";
    setDarkMode(JSON.parse(_item));

    // Remove the server-side injected CSS.
    const jssStyles = document.querySelector("#jss-server-side");
    if (jssStyles) {
      jssStyles.parentElement?.removeChild(jssStyles);
    }
  }, []);

  const theme: Theme = useMemo(
    () =>
      createTheme({
        palette: {
          mode: darkMode ? "dark" : "light",
          primary: {
            main: darkMode ? "#222432" : "#ffffff",
          },
          secondary: {
            main: darkMode ? "#0468d7" : "#0468d7",
          },
          background: {
            default: darkMode ? "#222432" : "#ffffff",
            paper: darkMode ? "#22293d" : "#f1f3f4",
          },
        },
      }),
    [darkMode]
  );

  return (
    <ThemeProvider theme={theme}>
      <CssBaseline enableColorScheme />

      <Header
        isDarkMode={darkMode}
        onThemeChange={() => {
          localStorage.setItem("darkMode", (!darkMode).toString());
          setDarkMode(!darkMode);
        }}
      />
      <div
        style={{
          minHeight: "80vh",
        }}
      >
        <Component {...pageProps} />
      </div>

      <SubmitProposalSection />

      <Footer />
    </ThemeProvider>
  );
}
Example #12
Source File: App.tsx    From react-flight-tracker with MIT License 4 votes vote down vote up
App: React.FC = () => {

  // States
  const [themeName, setThemeName] = useState(ThemeKeys.DarkTheme);

  const getTheme = () => {

    switch (themeName) {
      case ThemeKeys.DarkTheme: {
        return DarkTheme;
      };
      case ThemeKeys.LightTheme: {
        return LightTheme;
      };
      case ThemeKeys.PineappleTheme: {
        return PineappleTheme;
      };
      default:
        return DarkTheme;
    };
  };

  const handleThemeChange = (themeName: string) => {
    setThemeName(themeName);
  };

  const handleInjectCustomServices = () => {

    var services: Array<IService> = [];

    var openSkyAPIService = new OpenSkyAPIService(process.env.REACT_APP_OSKY_USERNAME, process.env.REACT_APP_OSKY_PASSWORD);
    services.push(openSkyAPIService);

    var geospatialService = new GeospatialService();
    services.push(geospatialService);

    return services;
  };

  const renderFallback = () => {

    const theme = getTheme();

    return (

      <Box
        sx={{
          height: '100vh',
          width: '100vw',
          overflow: 'hidden',
          userSelect: 'none',
          display: 'flex',
          flexDirection: 'column'
        }}>

        <ViewContainer
          isScrollLocked={true}>

          <Indicator1
            color={theme.palette.primary.main}
            scale={4.0} />
        </ViewContainer>
      </Box>
    );
  };

  return (

    <BrowserRouter>
      <StyledEngineProvider
        injectFirst={true}>
        <ThemeProvider
          theme={getTheme()}>

          <Suspense
            fallback={renderFallback()}>

            <SystemContextProvider
              onInjectCustomServices={handleInjectCustomServices}>

              <AppContextProvider
                onThemeChange={handleThemeChange}>
                <CssBaseline />
                <RouterPage />
              </AppContextProvider>
            </SystemContextProvider>
          </Suspense>
        </ThemeProvider>
      </StyledEngineProvider>
    </BrowserRouter>
  );
}
Example #13
Source File: CustomCMSApp.tsx    From firecms with MIT License 4 votes vote down vote up
/**
 * This is an example of how to use the components provided by FireCMS for
 * a better customisation.
 * @constructor
 */
export function CustomCMSApp() {

    const signInOptions = DEFAULT_SIGN_IN_OPTIONS;

    const navigation: NavigationBuilder = ({ user }: NavigationBuilderProps) => ({
        collections: [
            buildCollection({
                path: "products",
                schema: productSchema,
                name: "Products",
                permissions: ({ user }) => ({
                    edit: true,
                    create: true,
                    delete: true
                })
            })
        ]
    });

    const myAuthenticator: Authenticator = ({ user }) => {
        console.log("Allowing access to", user?.email);
        return true;
    };

    const {
        firebaseApp,
        firebaseConfigLoading,
        configError,
        firebaseConfigError
    } = useInitialiseFirebase({ firebaseConfig });

    const authDelegate: FirebaseAuthDelegate = useFirebaseAuthDelegate({
        firebaseApp,
        signInOptions
    });

    const dataSource = useFirestoreDataSource({
        firebaseApp: firebaseApp
        // You can add your `FirestoreTextSearchController` here
    });
    const storageSource = useFirebaseStorageSource({ firebaseApp: firebaseApp });

    if (configError) {
        return <div> {configError} </div>;
    }

    if (firebaseConfigError) {
        return <div>
            It seems like the provided Firebase config is not correct. If you
            are using the credentials provided automatically by Firebase
            Hosting, make sure you link your Firebase app to Firebase
            Hosting.
        </div>;
    }

    if (firebaseConfigLoading || !firebaseApp) {
        return <CircularProgressCenter/>;
    }

    return (
        <Router>
            <FireCMS navigation={navigation}
                     authDelegate={authDelegate}
                     authentication={myAuthenticator}
                     dataSource={dataSource}
                     storageSource={storageSource}
                     entityLinkBuilder={({ entity }) => `https://console.firebase.google.com/project/${firebaseApp.options.projectId}/firestore/data/${entity.path}/${entity.id}`}
            >
                {({ context, mode, loading }) => {

                    const theme = createCMSDefaultTheme({ mode });

                    let component;
                    if (loading) {
                        component = <CircularProgressCenter/>;
                    } else if (!context.authController.canAccessMainView) {
                        component = (
                            <FirebaseLoginView
                                allowSkipLogin={false}
                                signInOptions={signInOptions}
                                firebaseApp={firebaseApp}
                                authDelegate={authDelegate}/>
                        );
                    } else {
                        component = (
                            <Scaffold name={"My Online Shop"}>
                                <NavigationRoutes/>
                                <SideEntityDialogs/>
                            </Scaffold>
                        );
                    }

                    return (
                        <ThemeProvider theme={theme}>
                            <CssBaseline/>
                            {component}
                        </ThemeProvider>
                    );
                }}
            </FireCMS>
        </Router>
    );

}
Example #14
Source File: _app.tsx    From frontend with MIT License 4 votes vote down vote up
function CustomApp({
  Component,
  emotionCache = clientSideEmotionCache,
  pageProps: { session, dehydratedState, ...pageProps },
}: CustomAppProps) {
  const router = useRouter()
  const { i18n } = useTranslation()
  const { initialize, trackEvent } = useGTM()
  const onError = useCallback((error: unknown) => {
    if (error && isAxiosError(error)) {
      // Redirect to login
      if (error.response?.status === 401) {
        router.push({
          pathname: routes.login,
          query: { callbackUrl: router.asPath },
        })
      }
    }
  }, [])

  const [queryClient] = React.useState(
    () =>
      new QueryClient({
        defaultOptions: {
          queries: {
            queryFn,
            onError,
            staleTime: 25000,
          },
          mutations: { onError },
        },
      }),
  )

  useEffect(() => {
    // Init GTM
    initialize({
      events: { user_lang: i18n.language },
    })
  }, [])

  // Register route change complete event handlers
  useEffect(() => {
    const onRouteChange = (url: string) => {
      trackEvent({
        event: 'page_view',
        user_lang: i18n.language,
        page_title: document.title,
        page_pathname: url,
        page_location:
          document.location.protocol +
          '//' +
          document.location.hostname +
          document.location.pathname +
          document.location.search,
      })
    }

    router.events.on('routeChangeComplete', onRouteChange)
    return () => router.events.off('routeChangeComplete', onRouteChange)
  }, [i18n.language])

  return (
    <CacheProvider value={emotionCache}>
      <Head>
        <title>Podkrepi.bg</title>
        <meta name="viewport" content="minimum-scale=1, initial-scale=1, width=device-width" />
      </Head>
      <ThemeProvider theme={theme}>
        {/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}
        <CssBaseline />
        <SessionProvider session={session} refetchInterval={60}>
          <QueryClientProvider client={queryClient}>
            <Hydrate state={dehydratedState}>
              <Component {...pageProps} />
            </Hydrate>
          </QueryClientProvider>
        </SessionProvider>
      </ThemeProvider>
    </CacheProvider>
  )
}
Example #15
Source File: App.tsx    From NekoMaid with MIT License 4 votes vote down vote up
App: React.FC<{ darkMode: boolean, setDarkMode: (a: boolean) => void }> = React.memo(({ darkMode, setDarkMode }) => {
  const loc = useLocation()
  const his = useHistory()
  const pluginRef = useRef<Plugin | null>(null)
  const [mobileOpen, setMobileOpen] = useState(false)
  const [globalItemsOpen, setGlobalItemsOpen] = useState(false)
  const [globalData, setGlobalData] = useState<GlobalInfo>({ } as any)
  const [drawerWidth, setDrawerWidth] = useState(240)
  const updateF = useState(0)[1]
  const create = useMemo(() => {
    const io = socketIO(origin!, { path: pathname!, auth: { token } })
    const map: Record<string, Plugin> = { }
    const fn = (window as any).__NekoMaidAPICreate = (name: string) => map[name] || (map[name] = new Plugin(io, name))
    const nekoMaid = pluginRef.current = fn('NekoMaid')
    io.on('globalData', (data: GlobalInfo) => {
      const his: ServerRecord[] = JSON.parse(localStorage.getItem('NekoMaid:servers') || '[]')
      const curAddress = address!.replace('http://', '') + '?' + token
      let cur = his.find(it => it.address === curAddress)
      if (!cur) his.push((cur = { address: curAddress, time: 0 }))
      cur.time = Date.now()
      cur.icon = data.icon
      const arr = loc.pathname.split('/')
      if (!sent && arr.length > 2) io.emit('switchPage', arr[1], arr[2])
      sent = true
      localStorage.setItem('NekoMaid:servers', JSON.stringify(his))
      new Set(Object.values(data.plugins).flat()).forEach(loadPlugin)
      setGlobalData(data)
      pages = { }
      initPages(nekoMaid)
      onGlobalDataReceived(nekoMaid, data)
      update(Math.random())
      if (process.env.NODE_ENV !== 'development' && data.pluginVersion !== version) toast(lang.pluginUpdate, 'warning')
    }).on('!', () => {
      io.close()
      dialog({ content: lang.wrongToken, cancelButton: false })
        // eslint-disable-next-line no-return-assign
        .then(() => (location.search = location.pathname = location.hash = ''))
    }).on('reconnect', () => {
      toast(lang.reconnect)
      setTimeout(() => location.reload(), 5000)
    }).on('disconnect', () => failed(lang.disconnected)).on('connect_error', () => failed(lang.failedToConnect))
    return fn
  }, [])
  useEffect(() => { if (!loc.pathname || loc.pathname === '/') his.replace('/NekoMaid/dashboard') }, [loc.pathname])
  useEffect(() => {
    update = updateF
    return () => { update = undefined as any }
  }, [])

  const handleDrawerToggle = () => {
    setDrawerWidth(240)
    setMobileOpen(!mobileOpen)
  }

  const isExpand = drawerWidth === 240

  const routes: JSX.Element[] = []
  const mapToItem = (name: string, it: Page) => {
    const path = Array.isArray(it.path) ? it.path[0] : it.path
    const key = '/' + name + '/' + path
    routes.push(<pluginCtx.Provider key={key} value={create(name)}>
      <Route
        path={Array.isArray(it.path) ? it.path.map(it => '/' + name + '/' + it) : key}
        component={it.component}
        strict={it.strict}
        exact={it.exact}
        sensitive={it.sensitive}
      />
    </pluginCtx.Provider>)
    const icon = <ListItemIcon><pluginCtx.Provider value={create(name)}>
      {(typeof it.icon === 'function' ? <it.icon /> : it.icon) || <Build />}
    </pluginCtx.Provider></ListItemIcon>
    return it.title
      ? <NavLink key={key} to={'/' + name + '/' + (it.url || path)} activeClassName='actived'>
        <ListItem button>
          {isExpand ? icon : <Tooltip title={it.title} placement='right'>{icon}</Tooltip>}
          {isExpand && <ListItemText primary={it.title} />}
        </ListItem>
      </NavLink>
      : undefined
  }

  const singlePages: JSX.Element[] = []
  const multiPagesPages: Array<JSX.Element | JSX.Element[]> = []
  let index = 0
  for (const name in pages) {
    if (pages[name].length === 1) {
      const elm = mapToItem(name, pages[name][0])
      if (elm) singlePages.push(elm)
    } else {
      if (multiPagesPages.length) multiPagesPages.push(<Divider key={index++} />)
      multiPagesPages.push(pages[name].map(it => mapToItem(name, it)!).filter(Boolean))
    }
  }
  if (singlePages.length) multiPagesPages.push(<Divider key={index++} />, singlePages)

  const drawer = <Box sx={{ overflowX: 'hidden' }}>
    <Toolbar />
    <Divider sx={{ display: { sm: 'none', xs: 'block' } }} />
    <List sx={{
      '& a': {
        color: 'inherit',
        textDecoration: 'inherit'
      },
      '& .actived > div': {
        fontWeight: 'bold',
        color: theme => theme.palette.primary.main,
        backgroundColor: theme => alpha(theme.palette.primary.main, theme.palette.action.selectedOpacity) + '!important',
        '& svg': { color: theme => theme.palette.primary.main + '!important' }
      }
    }}>{multiPagesPages.flat()}</List>
  </Box>

  return <Box sx={{ display: 'flex' }}>
    <CssBaseline />
    <AppBar position='fixed' sx={{ zIndex: theme => theme.zIndex.drawer + 1 }}>
      <Toolbar>
        <IconButton
          color='inherit'
          edge='start'
          onClick={() => setDrawerWidth(isExpand ? 57 : 240)}
          sx={{ mr: 1, display: { sm: 'inline-flex', xs: 'none' } }}
        ><ChevronLeft sx={{ transition: '.3s', transform: isExpand ? undefined : 'rotate(-180deg)' }} /></IconButton>
        <IconButton color='inherit' edge='start' onClick={handleDrawerToggle} sx={{ mr: 2, display: { sm: 'none' } }}><Menu /></IconButton>
        <Typography variant='h3' noWrap component='div' sx={{ flexGrow: 1 }}>NekoMaid</Typography>
        {globalData.hasNBTAPI && <IconButton
          color='inherit'
          onClick={() => setGlobalItemsOpen(!globalItemsOpen)}
          onDragOver={() => setGlobalItemsOpen(true)}
        ><Backpack /></IconButton>}
        <LanguageSwitch />
        <IconButton color='inherit' edge='end' onClick={() => setDarkMode(!darkMode)}>
          {darkMode ? <Brightness7 /> : <Brightness4 />}
        </IconButton>
      </Toolbar>
    </AppBar>
    <globalCtx.Provider value={globalData}>
      <Box component='nav' sx={{ width: { sm: drawerWidth }, flexShrink: { sm: 0 } }}>
        <Drawer
          variant='temporary'
          open={mobileOpen}
          onClose={handleDrawerToggle}
          ModalProps={{ keepMounted: true }}
          sx={{
            display: { xs: 'block', sm: 'none' },
            '& .MuiDrawer-paper': {
              boxSizing: 'border-box',
              width: drawerWidth,
              backgroundImage: theme => theme.palette.mode === 'dark'
                ? 'linear-gradient(rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.05))'
                : undefined
            }
          }}
        >
          {drawer}
        </Drawer>
        <Drawer
          open
          variant='permanent'
          sx={{
            display: { xs: 'none', sm: 'block' },
            '& .MuiDrawer-paper': {
              boxSizing: 'border-box',
              width: drawerWidth,
              transition: 'width .3s',
              backgroundImage: theme => theme.palette.mode === 'dark' ? 'linear-gradient(rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.05))' : undefined
            }
          }}
        >
          {drawer}
        </Drawer>
      </Box>
      <Box component='main' sx={{ flexGrow: 1, width: '100vw' }}>
        <drawerWidthCtx.Provider value={drawerWidth}>{routes}</drawerWidthCtx.Provider>
        {globalData.hasNBTAPI && <pluginCtx.Provider value={pluginRef.current}>
          <GlobalItems open={globalItemsOpen} onClose={() => setGlobalItemsOpen(false)} />
        </pluginCtx.Provider>}
      </Box>
    </globalCtx.Provider>
  </Box>
})
Example #16
Source File: RequestPasswordRecovery.tsx    From abrechnung with GNU Affero General Public License v3.0 4 votes vote down vote up
export default function RequestPasswordRecovery() {
    const isLoggedIn = useRecoilValue(isAuthenticated);
    const [status, setStatus] = useState("initial");
    const [error, setError] = useState(null);
    const history = useHistory();

    useEffect(() => {
        if (isLoggedIn) {
            history.push("/");
        }
    }, [isLoggedIn, history]);

    const handleSubmit = (values, { setSubmitting }) => {
        requestPasswordRecovery(values)
            .then((res) => {
                setStatus("success");
                setError(null);
                setSubmitting(false);
            })
            .catch((err) => {
                setStatus("error");
                setError(err);
                setSubmitting(false);
            });
    };

    return (
        <Container component="main" maxWidth="xs">
            <CssBaseline />
            <Box sx={{ mt: 8, display: "flex", flexDirection: "column", alignItems: "center" }}>
                <Typography component="h1" variant="h5">
                    Recover Password
                </Typography>
                <Typography component="p" variant="body1">
                    Please enter your email. A recovery link will be sent shortly after.
                </Typography>
                {error && (
                    <Alert sx={{ mt: 4 }} severity="error">
                        {error}
                    </Alert>
                )}
                {status === "success" ? (
                    <Alert sx={{ mt: 4 }} severity="success">
                        A recovery link has been sent to you via email.
                    </Alert>
                ) : (
                    <Formik initialValues={{ email: "" }} onSubmit={handleSubmit}>
                        {({ values, handleChange, handleBlur, handleSubmit, isSubmitting }) => (
                            <Form onSubmit={handleSubmit}>
                                <TextField
                                    variant="outlined"
                                    margin="normal"
                                    required
                                    fullWidth
                                    autoFocus
                                    type="text"
                                    label="E-Mail"
                                    name="email"
                                    onBlur={handleBlur}
                                    onChange={handleChange}
                                    value={values.email}
                                />
                                {isSubmitting && <LinearProgress />}
                                <Button
                                    type="submit"
                                    fullWidth
                                    variant="contained"
                                    color="primary"
                                    disabled={isSubmitting}
                                    sx={{ margin: "3 0 2 0" }}
                                >
                                    Confirm
                                </Button>
                            </Form>
                        )}
                    </Formik>
                )}
            </Box>
        </Container>
    );
}
Example #17
Source File: Register.tsx    From abrechnung with GNU Affero General Public License v3.0 4 votes vote down vote up
export default function Register() {
    const loggedIn = useRecoilValue(isAuthenticated);
    const [loading, setLoading] = useState(true);
    const query = useQuery();
    const history = useHistory();

    const queryArgsForward = query.get("next") != null ? "?next=" + query.get("next") : "";

    useTitle("Abrechnung - Register");

    useEffect(() => {
        if (loggedIn) {
            setLoading(false);
            if (query.get("next") !== null && query.get("next") !== undefined) {
                history.push(query.get("next"));
            } else {
                history.push("/");
            }
        } else {
            setLoading(false);
        }
    }, [loggedIn, history, query]);

    const handleSubmit = (values, { setSubmitting }) => {
        // extract a potential invite token (which should be a uuid) from the query args
        let inviteToken = undefined;
        console.log(query.get("next"));
        if (query.get("next") !== null && query.get("next") !== undefined) {
            const re = /\/invite\/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/;
            const m = query.get("next").match(re);
            if (m != null) {
                inviteToken = m[1];
            }
        }
        const payload = {
            ...values,
            inviteToken: inviteToken,
        };

        register(payload)
            .then((res) => {
                toast.success(`Registered successfully, please confirm your email before logging in...`, {
                    autoClose: 20000,
                });
                setSubmitting(false);
                history.push(`/login${queryArgsForward}`);
            })
            .catch((err) => {
                toast.error(err);
                setSubmitting(false);
            });
    };

    const validate = (values) => {
        let errors = {};
        if (values.password !== values.password2) {
            errors["password2"] = "Passwords do not match";
        }
        return errors;
    };

    return (
        <>
            {loading ? (
                <Loading />
            ) : (
                <>
                    <Container maxWidth="xs">
                        <CssBaseline />
                        <Box sx={{ display: "flex", flexDirection: "column", alignItems: "center" }}>
                            <Avatar sx={{ margin: 1, backgroundColor: "primary.main" }}>
                                <LockOutlined />
                            </Avatar>
                            <Typography component="h1" variant="h5">
                                Register a new account
                            </Typography>
                            <Formik
                                validate={validate}
                                validationSchema={validationSchema}
                                initialValues={{
                                    username: "",
                                    email: "",
                                    password: "",
                                    password2: "",
                                }}
                                onSubmit={handleSubmit}
                            >
                                {({ values, handleBlur, handleChange, handleSubmit, isSubmitting }) => (
                                    <Form onSubmit={handleSubmit}>
                                        <TextField
                                            variant="outlined"
                                            margin="normal"
                                            required
                                            fullWidth
                                            autoFocus
                                            type="text"
                                            label="Username"
                                            name="username"
                                            onBlur={handleBlur}
                                            onChange={handleChange}
                                            value={values.username}
                                        />
                                        <TextField
                                            variant="outlined"
                                            margin="normal"
                                            required
                                            fullWidth
                                            type="email"
                                            name="email"
                                            label="E-Mail"
                                            onBlur={handleBlur}
                                            onChange={handleChange}
                                            value={values.email}
                                        />

                                        <TextField
                                            variant="outlined"
                                            margin="normal"
                                            required
                                            fullWidth
                                            type="password"
                                            name="password"
                                            label="Password"
                                            onBlur={handleBlur}
                                            onChange={handleChange}
                                            value={values.password}
                                        />

                                        <TextField
                                            variant="outlined"
                                            margin="normal"
                                            required
                                            fullWidth
                                            type="password"
                                            name="password2"
                                            label="Repeat Password"
                                            onBlur={handleBlur}
                                            onChange={handleChange}
                                            value={values.password2}
                                        />

                                        {isSubmitting && <LinearProgress />}
                                        <Button
                                            type="submit"
                                            fullWidth
                                            variant="contained"
                                            color="primary"
                                            disabled={isSubmitting}
                                            sx={{ mt: 1 }}
                                        >
                                            Register
                                        </Button>
                                        <Grid container={true} sx={{ justifyContent: "flex-end" }}>
                                            <Grid item>
                                                <Link
                                                    to={`/login${queryArgsForward}`}
                                                    component={RouterLink}
                                                    variant="body2"
                                                >
                                                    Already have an account? Sign in
                                                </Link>
                                            </Grid>
                                        </Grid>
                                    </Form>
                                )}
                            </Formik>
                        </Box>
                    </Container>
                </>
            )}
        </>
    );
}
Example #18
Source File: Login.tsx    From abrechnung with GNU Affero General Public License v3.0 4 votes vote down vote up
export default function Login() {
    const setUserData = useSetRecoilState(userData);
    const isLoggedIn = useRecoilValue(isAuthenticated);
    const query = useQuery();
    const history = useHistory();

    const queryArgsForward = query.get("next") != null ? "?next=" + query.get("next") : "";

    useTitle("Abrechnung - Login");

    useEffect(() => {
        if (isLoggedIn) {
            if (query.get("next") !== null && query.get("next") !== undefined) {
                history.push(query.get("next"));
            } else {
                history.push("/");
            }
        }
    }, [isLoggedIn, history, query]);

    const handleSubmit = (values, { setSubmitting }) => {
        login(values)
            .then((res) => {
                toast.success(`Logged in...`);
                setSubmitting(false);
                fetchProfile()
                    .then((result) => {
                        setUserData(result);
                    })
                    .catch((err) => {
                        toast.error(err);
                        removeToken();
                        setUserData(null);
                    });
            })
            .catch((err) => {
                toast.error(err);
                setSubmitting(false);
                removeToken();
                setUserData(null);
            });
    };

    return (
        <Container component="main" maxWidth="xs">
            <CssBaseline />
            <Box sx={{ display: "flex", flexDirection: "column", alignItems: "center" }}>
                <Avatar sx={{ margin: 1, backgroundColor: "primary.main" }}>
                    <LockOutlined />
                </Avatar>
                <Typography component="h1" variant="h5">
                    Sign in
                </Typography>
                <Formik
                    initialValues={{ password: "", username: "" }}
                    onSubmit={handleSubmit}
                    validationSchema={validationSchema}
                >
                    {({ values, handleBlur, handleChange, handleSubmit, isSubmitting }) => (
                        <Form onSubmit={handleSubmit}>
                            <input type="hidden" name="remember" value="true" />
                            <TextField
                                variant="outlined"
                                margin="normal"
                                required
                                fullWidth
                                autoFocus
                                type="text"
                                label="Username"
                                name="username"
                                onBlur={handleBlur}
                                onChange={handleChange}
                                value={values.username}
                            />

                            <TextField
                                variant="outlined"
                                margin="normal"
                                required
                                fullWidth
                                type="password"
                                name="password"
                                label="Password"
                                onBlur={handleBlur}
                                onChange={handleChange}
                                value={values.password}
                            />

                            {isSubmitting && <LinearProgress />}
                            <Button
                                type="submit"
                                fullWidth
                                variant="contained"
                                color="primary"
                                disabled={isSubmitting}
                                sx={{ mt: 1 }}
                            >
                                Login
                            </Button>
                            <Grid container={true} sx={{ justifyContent: "flex-end" }}>
                                <Grid item>
                                    <Link to={`/register${queryArgsForward}`} component={RouterLink} variant="body2">
                                        No account? register
                                    </Link>
                                </Grid>
                            </Grid>
                            <Grid container={true} sx={{ justifyContent: "flex-end" }}>
                                <Grid item>
                                    <Link to="/recover-password" component={RouterLink} variant="body2">
                                        Forgot your password?
                                    </Link>
                                </Grid>
                            </Grid>
                        </Form>
                    )}
                </Formik>
            </Box>
        </Container>
    );
}
Example #19
Source File: ConfirmPasswordRecovery.tsx    From abrechnung with GNU Affero General Public License v3.0 4 votes vote down vote up
export default function ConfirmPasswordRecovery() {
    const [status, setStatus] = useState("idle");
    const [error, setError] = useState(null);
    const { token } = useParams();

    const handleSubmit = (values, { setSubmitting }) => {
        confirmPasswordRecovery({ newPassword: values.password, token: token })
            .then((res) => {
                setStatus("success");
                setError(null);
                setSubmitting(false);
            })
            .catch((err) => {
                setStatus("error");
                setError(err);
                setSubmitting(false);
            });
    };

    const validate = (values) => {
        let errors = { password2: undefined };
        if (values.password !== values.password2) {
            errors.password2 = "Passwords do not match";
        }
        return errors;
    };

    return (
        <Container maxWidth="xs">
            <CssBaseline />
            <Box sx={{ mt: 8, display: "flex", flexDirection: "column", alignItems: "center" }}>
                <Typography component="h1" variant="h5">
                    Confirm Password Recovery
                </Typography>
                {error && (
                    <Alert sx={{ mt: 4 }} severity="error">
                        {error}
                    </Alert>
                )}
                {status === "success" ? (
                    <Alert sx={{ mt: 4 }} severity="success">
                        Password recovery successful, please{" "}
                        <Link to="/login" component={RouterLink}>
                            login
                        </Link>{" "}
                        using your new password.
                    </Alert>
                ) : (
                    <Formik
                        validate={validate}
                        initialValues={{
                            password: "",
                            password2: "",
                        }}
                        onSubmit={handleSubmit}
                    >
                        {({ values, handleChange, handleBlur, handleSubmit, isSubmitting }) => (
                            <Form>
                                <TextField
                                    variant="outlined"
                                    margin="normal"
                                    required
                                    fullWidth
                                    type="password"
                                    name="password"
                                    label="Password"
                                    onBlur={handleBlur}
                                    onChange={handleChange}
                                    value={values.password}
                                />

                                <TextField
                                    variant="outlined"
                                    margin="normal"
                                    required
                                    fullWidth
                                    type="password"
                                    name="password2"
                                    label="Repeat Password"
                                    onBlur={handleBlur}
                                    onChange={handleChange}
                                    value={values.password2}
                                />

                                {isSubmitting && <LinearProgress />}
                                <Button
                                    type="submit"
                                    fullWidth
                                    variant="contained"
                                    color="primary"
                                    disabled={isSubmitting}
                                    sx={{ margin: "3 0 2 0" }}
                                >
                                    Confirm
                                </Button>
                            </Form>
                        )}
                    </Formik>
                )}
            </Box>
        </Container>
    );
}
Example #20
Source File: Layout.tsx    From abrechnung with GNU Affero General Public License v3.0 4 votes vote down vote up
export default function Layout({ group = null, children, ...props }) {
    const authenticated = useRecoilValue(isAuthenticated);
    const [anchorEl, setAnchorEl] = useState(null);
    const theme: Theme = useTheme();
    const dotsMenuOpen = Boolean(anchorEl);
    const cfg = useRecoilValue(config);
    const location = useLocation();

    const [mobileOpen, setMobileOpen] = useState(true);

    const { window } = props;

    const handleProfileMenuOpen = (event) => {
        setAnchorEl(event.currentTarget);
    };

    const handleDotsMenuClose = (event) => {
        setAnchorEl(null);
    };

    const handleDrawerToggle = () => {
        setMobileOpen(!mobileOpen);
    };

    const drawer = (
        <div style={{ height: "100%" }}>
            <Toolbar />
            <Divider />
            {group != null && (
                <List sx={{ pb: 0 }}>
                    <ListItemLink
                        to={`/groups/${group.id}/`}
                        selected={
                            location.pathname === `/groups/${group.id}/` || location.pathname === `/groups/${group.id}`
                        }
                    >
                        <ListItemIcon>
                            <Paid />
                        </ListItemIcon>
                        <ListItemText primary="Transactions" />
                    </ListItemLink>
                    <ListItemLink
                        to={`/groups/${group.id}/balances`}
                        selected={location.pathname.startsWith(`/groups/${group.id}/balances`)}
                    >
                        <ListItemIcon>
                            <BarChart />
                        </ListItemIcon>
                        <ListItemText primary="Balances" />
                    </ListItemLink>
                    <ListItemLink
                        to={`/groups/${group.id}/accounts`}
                        selected={location.pathname.startsWith(`/groups/${group.id}/accounts`)}
                    >
                        <ListItemIcon>
                            <AccountBalance />
                        </ListItemIcon>
                        <ListItemText primary="Accounts" />
                    </ListItemLink>
                    <ListItemLink
                        to={`/groups/${group.id}/detail`}
                        selected={location.pathname.startsWith(`/groups/${group.id}/detail`)}
                    >
                        <ListItemIcon>
                            <AdminPanelSettings />
                        </ListItemIcon>
                        <ListItemText primary="Group Settings" />
                    </ListItemLink>
                    <ListItemLink
                        to={`/groups/${group.id}/members`}
                        selected={location.pathname.startsWith(`/groups/${group.id}/members`)}
                    >
                        <ListItemIcon>
                            <People />
                        </ListItemIcon>
                        <ListItemText primary="Group Members" />
                    </ListItemLink>
                    <ListItemLink
                        to={`/groups/${group.id}/invites`}
                        selected={location.pathname.startsWith(`/groups/${group.id}/invites`)}
                    >
                        <ListItemIcon>
                            <Mail />
                        </ListItemIcon>
                        <ListItemText primary="Group Invites" />
                    </ListItemLink>
                    <ListItemLink
                        to={`/groups/${group.id}/log`}
                        selected={location.pathname.startsWith(`/groups/${group.id}/log`)}
                    >
                        <ListItemIcon>
                            <Message />
                        </ListItemIcon>
                        <ListItemText primary="Group Log" />
                    </ListItemLink>
                    <Divider />
                </List>
            )}
            <SidebarGroupList group={group} />

            <Box
                sx={{
                    display: "flex",
                    position: "absolute",
                    width: "100%",
                    justifyContent: "center",
                    bottom: 0,
                    padding: 1,
                    borderTop: 1,
                    borderColor: theme.palette.divider,
                }}
            >
                {cfg.imprintURL && (
                    <Link href={cfg.imprintURL} target="_blank" sx={{ mr: 2 }}>
                        imprint
                    </Link>
                )}
                <Tooltip title="Source Code">
                    <Link sx={{ ml: 1 }} target="_blank" href={cfg.sourceCodeURL}>
                        <GitHub />
                    </Link>
                </Tooltip>
                {cfg.issueTrackerURL && (
                    <Tooltip title="Bug reports">
                        <Link sx={{ ml: 1 }} target="_blank" href={cfg.issueTrackerURL}>
                            <BugReport />
                        </Link>
                    </Tooltip>
                )}
            </Box>
        </div>
    );

    const container = window !== undefined ? () => window().document.body : undefined;

    return (
        <Box sx={{ display: "flex" }}>
            <CssBaseline />
            <AppBar
                position="fixed"
                sx={{
                    // width: {sm: `calc(100% - ${drawerWidth}px)`},
                    // ml: {sm: `${drawerWidth}px`},
                    zIndex: (theme) => theme.zIndex.drawer + 1,
                }}
            >
                <Toolbar>
                    <IconButton
                        color="inherit"
                        aria-label="open drawer"
                        onClick={handleDrawerToggle}
                        edge="start"
                        sx={{ mr: 2, display: { sm: "none" } }}
                    >
                        <MenuIcon />
                    </IconButton>
                    <Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
                        Abrechnung
                    </Typography>
                    {authenticated ? (
                        <div>
                            <IconButton
                                aria-label="account of current user"
                                aria-controls="menu-appbar"
                                aria-haspopup="true"
                                onClick={handleProfileMenuOpen}
                                color="inherit"
                            >
                                <AccountCircleIcon />
                            </IconButton>
                            <Menu
                                id="menu-appbar"
                                open={dotsMenuOpen}
                                anchorOrigin={{
                                    vertical: "top",
                                    horizontal: "right",
                                }}
                                keepMounted
                                anchorEl={anchorEl}
                                transformOrigin={{
                                    vertical: "top",
                                    horizontal: "right",
                                }}
                                onClose={handleDotsMenuClose}
                            >
                                <MenuItem component={RouterLink} to="/profile">
                                    Profile
                                </MenuItem>
                                <MenuItem component={RouterLink} to="/profile/settings">
                                    Settings
                                </MenuItem>
                                <MenuItem component={RouterLink} to="/profile/sessions">
                                    Sessions
                                </MenuItem>
                                <MenuItem component={RouterLink} to="/profile/change-email">
                                    Change E-Mail
                                </MenuItem>
                                <MenuItem component={RouterLink} to="/profile/change-password">
                                    Change Password
                                </MenuItem>
                                <Divider />
                                <MenuItem component={RouterLink} to="/logout">
                                    <ListItemIcon>
                                        <Logout fontSize="small" />
                                    </ListItemIcon>
                                    <ListItemText>Sign out</ListItemText>
                                </MenuItem>
                            </Menu>
                        </div>
                    ) : (
                        <Button component={RouterLink} color="inherit" to="/login">
                            Login
                        </Button>
                    )}
                </Toolbar>
            </AppBar>

            {authenticated ? (
                <Box component="nav" sx={{ width: { sm: drawerWidth }, flexShrink: { sm: 0 } }}>
                    <Drawer
                        container={container}
                        variant="temporary"
                        open={mobileOpen}
                        onClose={handleDrawerToggle}
                        ModalProps={{
                            keepMounted: true, // Better open performance on mobile.
                        }}
                        sx={{
                            display: { xs: "block", sm: "none" },
                            "& .MuiDrawer-paper": {
                                boxSizing: "border-box",
                                width: drawerWidth,
                            },
                        }}
                    >
                        {drawer}
                    </Drawer>
                    <Drawer
                        variant="permanent"
                        sx={{
                            flexShrink: 0,
                            display: { xs: "none", sm: "block" },
                            "& .MuiDrawer-paper": {
                                boxSizing: "border-box",
                                width: drawerWidth,
                            },
                        }}
                        open
                    >
                        {drawer}
                    </Drawer>
                </Box>
            ) : null}
            <Box
                component="main"
                sx={{
                    flexGrow: 1,
                    width: { sm: `calc(100% - ${drawerWidth}px)` },
                }}
            >
                <Toolbar />
                <Banner />
                <Container maxWidth="lg" sx={{ padding: { xs: 0, md: 1, lg: 3 } }}>
                    {children}
                </Container>
            </Box>
        </Box>
    );
}
Example #21
Source File: App.tsx    From mojito_pdm with Creative Commons Attribution Share Alike 4.0 International 4 votes vote down vote up
App: React.FC = () => {
    const mode = useRecoilValue(GlobalState.theme)
    const setBuyEnabled = useSetRecoilState(GlobalState.canBuy)
    const setColoursEnabled = useSetRecoilState(GlobalState.customColours)
    const setCars = useSetRecoilState(CarState.rawCars)

    useNuiEvent<Car[]>('setCars', setCars)

    useEffect(() => {
        fetchNui<{ buy: boolean, colours: boolean }>("fetchconfig").then((data) => {
            setBuyEnabled(data.buy)
            setColoursEnabled(data.colours)
        }).catch(() => {
            setBuyEnabled(true)
            setColoursEnabled(false)
        })
    })

    const theme = useMemo(
        () =>
            createTheme({
                palette: {
                    mode,
                    ...(mode === 'light'
                        ? {
                            // palette values for light mode
                            primary: blue,
                            text: {
                                primary: grey[900],
                                secondary: grey[800],
                            },
                            background: {
                                default: "transparent"
                            }
                        }
                        : {
                            // palette values for dark mode
                            primary: blue,
                            text: {
                                primary: '#fff',
                                secondary: grey[500],
                            },
                            background: {
                                default: "transparent"
                            }
                        }),
                },
                components: {
                    MuiCssBaseline: {
                        styleOverrides: {
                            body: {
                                scrollbarColor: "#6b6b6b #2b2b2b",
                                "&::-webkit-scrollbar, & *::-webkit-scrollbar": {
                                    backgroundColor: mode === "dark"? grey[800] : grey[200],
                                },
                                "&::-webkit-scrollbar-thumb, & *::-webkit-scrollbar-thumb": {
                                    borderRadius: 8,
                                    backgroundColor: grey[500],
                                    minHeight: 24,
                                },
                                "&::-webkit-scrollbar-thumb:hover, & *::-webkit-scrollbar-thumb:hover": {
                                    backgroundColor: grey[600],
                                },
                            },
                        },
                    },
                },
            }),
        [mode],
    );

    return (
        <ThemeProvider theme={theme}>
            <VisibilityProvider>
                <Box sx={{
                    width: 1100,
                    height: 600,
                    maxHeight: 600,
                }}>
                    <Paper elevation={2} sx={{minHeight: "100%", maxHeight: 600, overflowY: "scroll"}}>
                        <Catalogue/>
                    </Paper>
                </Box>
            </VisibilityProvider>
            <CssBaseline />
        </ThemeProvider>
    );
}
Example #22
Source File: FirebaseCMSApp.tsx    From firecms with MIT License 4 votes vote down vote up
/**
 * This is the default implementation of a FireCMS app using the Firebase services
 * as a backend.
 * You can use this component as a full app, by specifying collections and
 * entity schemas.
 *
 * This component is in charge of initialising Firebase, with the given
 * configuration object.
 *
 * If you are building a larger app and need finer control, you can use
 * {@link FireCMS}, {@link Scaffold}, {@link SideEntityDialogs}
 * and {@link NavigationRoutes} instead.
 *
 * @param props
 * @constructor
 * @category Firebase
 */
export function FirebaseCMSApp({
                                   name,
                                   logo,
                                   toolbarExtraWidget,
                                   authentication,
                                   schemaOverrideHandler,
                                   navigation,
                                   textSearchController,
                                   allowSkipLogin,
                                   signInOptions = DEFAULT_SIGN_IN_OPTIONS,
                                   firebaseConfig,
                                   onFirebaseInit,
                                   primaryColor,
                                   secondaryColor,
                                   fontFamily,
                                   dateTimeFormat,
                                   locale,
                                   HomePage,
                                   basePath,
                                   baseCollectionPath,
                                   LoginViewProps
                               }: FirebaseCMSAppProps) {

    const {
        firebaseApp,
        firebaseConfigLoading,
        configError,
        firebaseConfigError
    } = useInitialiseFirebase({ onFirebaseInit, firebaseConfig });

    const authDelegate: FirebaseAuthDelegate = useFirebaseAuthDelegate({
        firebaseApp,
        signInOptions
    });

    const dataSource = useFirestoreDataSource({
        firebaseApp: firebaseApp,
        textSearchController
    });
    const storageSource = useFirebaseStorageSource({ firebaseApp: firebaseApp });

    if (configError) {
        return <div> {configError} </div>;
    }

    if (firebaseConfigError) {
        return <div>
            It seems like the provided Firebase config is not correct. If you
            are using the credentials provided automatically by Firebase
            Hosting, make sure you link your Firebase app to Firebase
            Hosting.
        </div>;
    }

    if (firebaseConfigLoading || !firebaseApp) {
    return <>
        <CssBaseline/>
        <CircularProgressCenter/>
    </>;
    }

    return (
        <BrowserRouter basename={basePath}>
            <FireCMS navigation={navigation}
                     authDelegate={authDelegate}
                     authentication={authentication}
                     schemaOverrideHandler={schemaOverrideHandler}
                     dateTimeFormat={dateTimeFormat}
                     dataSource={dataSource}
                     storageSource={storageSource}
                     entityLinkBuilder={({ entity }) => `https://console.firebase.google.com/project/${firebaseApp.options.projectId}/firestore/data/${entity.path}/${entity.id}`}
                     locale={locale}
                     basePath={basePath}
                     baseCollectionPath={baseCollectionPath}>
                {({ context, mode, loading }) => {

                    const theme = createCMSDefaultTheme({
                        mode,
                        primaryColor,
                        secondaryColor,
                        fontFamily
                    });

                    let component;
                    if (loading) {
                        component = <CircularProgressCenter/>;
                    } else if (!context.authController.canAccessMainView) {
                        component = (
                            <FirebaseLoginView
                                logo={logo}
                                allowSkipLogin={allowSkipLogin}
                                signInOptions={signInOptions ?? DEFAULT_SIGN_IN_OPTIONS}
                                firebaseApp={firebaseApp}
                                authDelegate={authDelegate}
                                {...LoginViewProps}
                                />
                        );
                    } else {
                        component = (
                            <Scaffold name={name}
                                      logo={logo}
                                      toolbarExtraWidget={toolbarExtraWidget}>
                                <NavigationRoutes HomePage={HomePage}/>
                                <SideEntityDialogs/>
                            </Scaffold>
                        );
                    }

                    return (
                        <ThemeProvider theme={theme}>
                            <CssBaseline/>
                            {component}
                        </ThemeProvider>
                    );
                }}
            </FireCMS>
        </BrowserRouter>
    );
}