@mui/material#useMediaQuery TypeScript Examples

The following examples show how to use @mui/material#useMediaQuery. 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: useMobile.tsx    From frontend with MIT License 6 votes vote down vote up
export default function useMobile() {
  const mobile = useMediaQuery('(max-width:900px)')
  const small = useMediaQuery('(max-width:600px)')

  return {
    mobile,
    small,
  }
}
Example #2
Source File: useSidebar.ts    From usehooks-ts with MIT License 6 votes vote down vote up
function useSidebar(): ReturnType {
  const { breakpoints } = useTheme()
  const isMobile = useMediaQuery(breakpoints.down('lg'))
  const [isOpen, setOpen] = useState(false)

  const closeSidebar = () => {
    if (isMobile) {
      setOpen(false)
    }
  }

  const openSidebar = () => setOpen(true)

  useEffect(() => {
    // Hide sidebar by default on small screen
    if (isMobile && isOpen) {
      closeSidebar()
    }

    // Show sidebar by default on large screen
    if (!isMobile && !isOpen) {
      openSidebar()
    }

    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isMobile])

  return [
    isOpen,
    {
      openSidebar,
      closeSidebar,
    },
  ]
}
Example #3
Source File: ModeState.tsx    From firecms with MIT License 6 votes vote down vote up
ModeProvider: React.FC<ModeProviderProps> = ({ children }) => {

    const prefersDarkModeQuery = useMediaQuery("(prefers-color-scheme: dark)");
    const prefersDarkModeStorage: boolean | null = localStorage.getItem("prefers-dark-mode") != null ? localStorage.getItem("prefers-dark-mode") === "true" : null;
    const prefersDarkMode = prefersDarkModeStorage ?? prefersDarkModeQuery;
    const [mode, setMode] = useState<"light" | "dark">(prefersDarkMode ? "dark" : "light");

    useEffect(() => {
        setMode(prefersDarkMode ? "dark" : "light");
    }, [prefersDarkMode]);

    const toggleMode = () => {
        if (mode === "light") {
            if (!prefersDarkModeQuery)
                localStorage.setItem("prefers-dark-mode", "true");
            else
                localStorage.removeItem("prefers-dark-mode");
            setMode("dark");
        } else {
            if (prefersDarkModeQuery)
                localStorage.setItem("prefers-dark-mode", "false");
            else
                localStorage.removeItem("prefers-dark-mode");
            setMode("light");
        }
    };

    return (
        <ModeStateContext.Provider
            value={{
                mode,
                setMode,
                toggleMode
            }}
        >
            {children}
        </ModeStateContext.Provider>
    );
}
Example #4
Source File: Header.tsx    From your_spotify with GNU General Public License v3.0 6 votes vote down vote up
export default function Header({ left, title, subtitle, hideInterval }: HeaderProps) {
  const dispatch = useAppDispatch();
  const intervalDetail = useSelector(selectIntervalDetail);
  const showSider = !useMediaQuery('(max-width: 900px)');

  const changeInterval = useCallback(
    (newInterval: IntervalDetail) => {
      dispatch(setDataInterval(intervalDetailToRedux(newInterval)));
    },
    [dispatch],
  );

  return (
    <div className={s.root}>
      <div className={s.left}>
        {left}
        <div className={s.texts}>
          <Text element="h1">{title}</Text>
          {showSider && <Text>{subtitle}</Text>}
        </div>
      </div>
      {!hideInterval && (
        <div>
          <IntervalSelector value={intervalDetail} onChange={changeInterval} />
        </div>
      )}
    </div>
  );
}
Example #5
Source File: App.tsx    From NekoMaid with MIT License 6 votes vote down vote up
AppWrap: React.FC = () => {
  const isDark = useMediaQuery('(prefers-color-scheme: dark)')
  const mode = localStorage.getItem('NekoMaid:colorMode')
  const [darkMode, setDarkMode] = useState(mode ? mode === 'dark' : isDark)
  const primary = (colors as any)[localStorage.getItem('NekoMaid:color') || 'blue']
  ;(document.getElementById('theme-color-meta') as HTMLMetaElement)?.setAttribute('content', primary[500])
  const theme = React.useMemo(() => createTheme({
    typography,
    components: {
      MuiCssBaseline: {
        styleOverrides: {
          body: darkMode ? darkScrollbar() : null
        }
      }
    },
    palette: {
      primary,
      mode: darkMode ? 'dark' : 'light',
      background: darkMode ? { default: '#212121', paper: '#212121' } : { default: '#f4f6f8', paper: '#ffffff' }
    }
  }, (muiLanguages as any)[lang.muiName]), [darkMode])
  return <ThemeProvider theme={theme}>
    <DialogWrapper />
    <Snackbars />
    <App darkMode={darkMode} setDarkMode={setDarkMode} />
  </ThemeProvider>
}
Example #6
Source File: useMediaQueryUp.tsx    From genshin-optimizer with MIT License 6 votes vote down vote up
export default function useMediaQueryUp() {
  const theme = useTheme();
  const sm = useMediaQuery(theme.breakpoints.up('sm'));
  const md = useMediaQuery(theme.breakpoints.up('md'));
  const lg = useMediaQuery(theme.breakpoints.up('lg'));
  const xl = useMediaQuery(theme.breakpoints.up('xl'));
  if (xl) return "xl"
  if (lg) return "lg"
  if (md) return "md"
  if (sm) return "sm"
  return "xs"
}
Example #7
Source File: Theme.tsx    From GTAV-NativeDB with MIT License 6 votes vote down vote up
function Theme({ children }: { children: ReactNode }) {
  const settings = useSettings()
  const systemIsDark = useMediaQuery('(prefers-color-scheme: dark)')
  const dark = settings.theme === 'dark' || (settings.theme === 'system' && systemIsDark)
  const theme = useMemo(
    () => createTheme(dark ? darkTheme : lightTheme),
    [dark]
  )

  useEffect(() => {
    document.querySelector('meta[name="theme-color"]')
      ?.setAttribute('content', dark ? '#272727' :'#0e752e')
  }, [dark])

  return (
    <ThemeProvider theme={theme}>
      {children}
    </ThemeProvider>
  )
}
Example #8
Source File: layout.tsx    From usehooks-ts with MIT License 6 votes vote down vote up
Layout: FC = ({ children }) => {
  const { title } = useSiteMetadata()
  const [isSidebarOpen, { openSidebar, closeSidebar }] = useSidebar()
  const [isModalOpen, { openModal, closeModal }] = useSearchModal()
  const theme = useTheme()
  const isLarge = useMediaQuery(theme.breakpoints.up('md'))

  return (
    <Root>
      <CustomScrollbar theme={theme} />
      <Header
        siteTitle={title}
        openSidebar={openSidebar}
        openSearch={openModal}
      />

      <Sidebar open={isSidebarOpen} onClose={closeSidebar} />

      <Main
        sx={{ paddingLeft: isLarge && isSidebarOpen ? `${drawerWidth}px` : 0 }}
      >
        {children}
        <Footer />
      </Main>

      <SearchModal open={isModalOpen} onClose={closeModal} />

      <BackToTop />
    </Root>
  )
}
Example #9
Source File: EmptyView.tsx    From Tachidesk-WebUI with Mozilla Public License 2.0 6 votes vote down vote up
export default function EmptyView({ message, messageExtra }: IProps) {
    const theme = useTheme();
    const isMobileWidth = useMediaQuery(theme.breakpoints.down('sm'));

    return (
        <Box sx={{
            position: 'absolute',
            left: `calc(50% + ${isMobileWidth ? '0px' : theme.spacing(8 / 2)})`,
            top: '50%',
            transform: 'translate(-50%, -50%)',
            textAlign: 'center',
        }}
        >
            <Typography variant="h3" gutterBottom>
                {getRandomErrorFace()}
            </Typography>
            <Typography variant="h5">
                {message}
            </Typography>
            {messageExtra}
        </Box>
    );
}
Example #10
Source File: Layout.tsx    From your_spotify with GNU General Public License v3.0 6 votes vote down vote up
export default function Layout({ children }: LayoutProps) {
  const [open, setOpen] = useState(false);
  const showSider = !useMediaQuery('(max-width: 900px)');
  const publicToken = useSelector(selectPublicToken);

  const drawer = useCallback(() => {
    setOpen((old) => !old);
  }, []);

  return (
    <div className={s.root}>
      {!showSider && (
        <Drawer open={open} anchor="left" onClose={() => setOpen(false)}>
          <Sider />
        </Drawer>
      )}
      <section className={s.sider}>{showSider && <Sider />}</section>
      <section
        className={clsx({
          [s.content]: true,
          [s.contentdrawer]: showSider,
        })}>
        {publicToken && (
          <div className={s.publictoken}>
            <Text>You are viewing as guest</Text>
          </div>
        )}
        {!showSider && (
          <IconButton onClick={drawer} className={s.drawerbutton}>
            <Menu />
          </IconButton>
        )}
        {children}
      </section>
    </div>
  );
}
Example #11
Source File: Footer.tsx    From frontend with MIT License 6 votes vote down vote up
SocialIcons = () => {
  const theme = useTheme()
  const sm = useMediaQuery(theme.breakpoints.up('sm'))
  return (
    <Grid direction="row" container spacing={2} justifyContent={sm ? 'flex-start' : 'center'}>
      <Grid item>
        <ExternalLink href={socialUrls.facebook}>
          <Facebook />
        </ExternalLink>
      </Grid>
      <Grid item>
        <ExternalLink href={socialUrls.linkedin}>
          <LinkedIn />
        </ExternalLink>
      </Grid>
      <Grid item>
        <ExternalLink href={socialUrls.youtube}>
          <YouTube />
        </ExternalLink>
      </Grid>
      <Grid item>
        <ExternalLink href={socialUrls.instagram}>
          <Instagram />
        </ExternalLink>
      </Grid>
    </Grid>
  )
}
Example #12
Source File: Artist.tsx    From your_spotify with GNU General Public License v3.0 6 votes vote down vote up
export default function Artist(props: ArtistProps | HeaderArtistProps) {
  const upmd = useMediaQuery('(min-width: 1150px)');
  const upmobile = useMediaQuery('(min-width: 600px)');

  if (props.line) {
    return (
      <div className={s.root}>
        <Text className={s.artistname}>Artist name</Text>
        {upmobile && <Text className={clsx(s.genres, s.header)}>Genres</Text>}
        <Text className={clsx(s.sumcount, s.header)}>Count</Text>
        <Text className={clsx(s.sumduration, s.header)}>Total duration</Text>
      </div>
    );
  }

  const { artist, duration, totalDuration, count, totalCount } = props;
  return (
    <div className={s.root}>
      <img className={s.artistcover} src={getImage(artist)} alt="Artist cover" />
      <Text className={s.artistname}>
        <InlineArtist artist={artist} />
      </Text>
      {upmobile && <Text className={s.genres}>{artist.genres.join(', ')}</Text>}
      <Text className={s.sumcount}>
        {count} {upmd && <Text>({Math.floor((count / totalCount) * 10000) / 100})</Text>}
      </Text>
      <Text className={s.sumduration}>
        {msToMinutesAndSeconds(duration)}{' '}
        {upmd && <Text>({Math.floor((duration / totalDuration) * 10000) / 100})</Text>}
      </Text>
    </div>
  );
}
Example #13
Source File: layout.tsx    From usehooks-ts with MIT License 6 votes vote down vote up
TopLayout: FC = ({ children }) => {
  const matches = useMediaQuery('(prefers-color-scheme: dark)')
  const theme = themes[matches ? 'dark' : 'light']

  return (
    <ThemeProvider theme={theme}>
      <CssBaseline />
      <Layout>{children}</Layout>
    </ThemeProvider>
  )
}
Example #14
Source File: Track.tsx    From your_spotify with GNU General Public License v3.0 5 votes vote down vote up
export default function Track(props: TrackProps | HeaderTrackProps) {
  const trackId = props.line ? null : props.track.id;
  const play = useCallback(async () => {
    if (!trackId) return;
    try {
      await api.play(trackId);
    } catch (e) {
      console.error(e);
    }
  }, [trackId]);

  const upmd = useMediaQuery('(min-width: 1150px)');

  if (props.line) {
    return (
      <div className={s.root}>
        <div className={clsx(s.name, s.header)}>
          <Text className={s.trackname}>Track name / Artist</Text>
        </div>
        {upmd && <Text className={clsx(s.albumname, s.header)}>Album name</Text>}
        {upmd && <Text className={clsx(s.duration, s.header)}>Duration</Text>}
        <Text className={clsx(s.sumcount, s.header)}>Count</Text>
        <Text className={clsx(s.sumduration, s.header)}>Total duration</Text>
      </div>
    );
  }

  const { track, album, artists, playable, duration, totalDuration, count, totalCount } = props;
  return (
    <div className={s.root}>
      {playable && (
        <IconButton className={s.play} size="small" onClick={play}>
          <PlayArrow />
        </IconButton>
      )}
      <img className={s.albumcover} src={getImage(album)} alt="Album cover" />
      <div className={s.name}>
        <Text className={s.trackname}>{track.name}</Text>
        <Text className={s.artistname}>
          {artists.map((art) => (
            <React.Fragment key={art.id}>
              <InlineArtist key={art.id} artist={art} />{' '}
            </React.Fragment>
          ))}
        </Text>
      </div>
      {upmd && <Text className={s.albumname}>{album.name}</Text>}
      {upmd && <Text className={s.duration}>{msToMinutesAndSeconds(track.duration_ms)}</Text>}
      <Text className={s.sumcount}>
        {count} {upmd && <Text>({Math.floor((count / totalCount) * 10000) / 100})</Text>}
      </Text>
      <Text className={s.sumduration}>
        {msToMinutesAndSeconds(duration)}{' '}
        {upmd && <Text>({Math.floor((duration / totalDuration) * 10000) / 100})</Text>}
      </Text>
    </div>
  );
}
Example #15
Source File: DefaultNavBar.tsx    From Tachidesk-WebUI with Mozilla Public License 2.0 5 votes vote down vote up
export default function DefaultNavBar() {
    const { title, action, override } = useContext(NavBarContext);
    const { darkTheme } = useContext(DarkTheme);

    const theme = useTheme();
    const history = useHistory();

    const isMobileWidth = useMediaQuery(theme.breakpoints.down('sm'));
    const isMainRoute = navbarItems.some(({ path }) => path === history.location.pathname);

    // Allow default navbar to be overrided
    if (override.status) return override.value;

    let navbar = <></>;
    if (isMobileWidth) {
        if (isMainRoute) {
            navbar = <MobileBottomBar navBarItems={navbarItems.filter((it) => it.show !== 'desktop')} />;
        }
    } else {
        navbar = <DesktopSideBar navBarItems={navbarItems.filter((it) => it.show !== 'mobile')} />;
    }

    return (
        <Box sx={{ flexGrow: 1 }}>
            <AppBar position="fixed" color={darkTheme ? 'default' : 'primary'}>
                <Toolbar>
                    {
                        !navbarItems.some(({ path }) => path === history.location.pathname)
                            && (
                                <IconButton
                                    edge="start"
                                    sx={{ marginRight: theme.spacing(2) }}
                                    color="inherit"
                                    aria-label="menu"
                                    disableRipple
                                    // when page is opened in new tab backbutton will
                                    // take you to the library
                                    onClick={() => (history.length === 1 ? history.push('/library') : history.goBack())}
                                    size="large"
                                >
                                    <ArrowBack />
                                </IconButton>
                            )
                    }
                    <Typography variant={isMobileWidth ? 'h6' : 'h5'} sx={{ flexGrow: 1 }}>
                        {title}
                    </Typography>
                    {action}
                </Toolbar>
            </AppBar>
            {navbar}
        </Box>
    );
}
Example #16
Source File: theme.ts    From your_spotify with GNU General Public License v3.0 5 votes vote down vote up
useTheme = () => {
  const dark = useSelector(selectDarkMode);
  const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)');

  const isDark = dark === 'dark' || (dark === 'follow' && prefersDarkMode);

  const theme = useMemo(
    () =>
      createTheme({
        palette: {
          mode: isDark ? 'dark' : 'light',
          primary: {
            main: isDark ? '#ffffff' : '#000000',
          },
        },
        components: {
          MuiPaper: {
            styleOverrides: {
              root: {
                backgroundImage: 'unset',
              },
            },
          },
          MuiCheckbox: {
            styleOverrides: {
              root: {
                color: 'var(--primary) !important',
              },
            },
          },
          MuiSkeleton: {
            styleOverrides: {
              rectangular: {
                borderRadius: '6px',
              },
            },
          },
        },
        shape: {
          borderRadius: 6,
        },
      }),
    [isDark],
  );
  return theme;
}
Example #17
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 #18
Source File: ItemViewer.tsx    From NekoMaid with MIT License 5 votes vote down vote up
GlobalItems: React.FC<{ open: boolean, onClose: () => void }> = ({ open, onClose }) => {
  const matches = useMediaQuery((theme: any) => theme.breakpoints.down('md'))
  const [flag, update] = useState(0)
  const [copyItemLeft, setCopyItemLeft] = useState<Item | undefined>()
  const [copyItemRight, setCopyItemRight] = useState<Item | undefined>()
  const items: Array<Item | undefined> = JSON.parse(localStorage.getItem('NekoMaid:items') || '[]')
  const save = () => {
    localStorage.setItem('NekoMaid:items', JSON.stringify(items))
    process.nextTick(update, flag + 1)
  }
  return <Drawer anchor='bottom' variant='persistent' elevation={16} open={open} PaperProps={{ elevation: 16 }}>
    <Box sx={{ padding: 2, display: 'flex', justifyContent: 'center', paddingBottom: 0, alignItems: 'center' }}>
      <ItemViewer
        item={copyItemLeft}
        data={{ type: InvType.GLOBAL_ITEMS }}
        onDrag={() => process.nextTick(setCopyItemLeft)}
        onDrop={it => {
          setCopyItemLeft(it)
          setCopyItemRight(it)
        }}
      />&nbsp;{`< ${lang.itemEditor.clone} >`}&nbsp;<ItemViewer
        item={copyItemRight}
        data={{ type: InvType.GLOBAL_ITEMS }}
        onDrag={() => process.nextTick(setCopyItemRight)}
        onDrop={it => {
          setCopyItemLeft(it)
          setCopyItemRight(it)
        }}
      />
    </Box>
    <Box sx={{ padding: 2, display: 'flex', justifyContent: 'center', flexWrap: 'wrap' }}>
      {Array.from({ length: 14 }, (_, i) => <ItemViewer
        key={i}
        item={items[i]}
        data={{ type: InvType.GLOBAL_ITEMS }}
        onDrag={() => {
          items[i] = undefined
          save()
          if (matches) process.nextTick(onClose)
        }}
        onDrop={it => {
          items[i] = it
          save()
        }}
        onEdit={item => {
          if (item === false) return
          items[i] = item || undefined
          save()
        }}
      />)}
    </Box>
    <ItemEditor />
  </Drawer>
}
Example #19
Source File: Header.tsx    From genshin-optimizer with MIT License 5 votes vote down vote up
function HeaderContent({ anchor }) {
  const theme = useTheme();
  const isLarge = useMediaQuery(theme.breakpoints.up('lg'));
  const isMobile = useMediaQuery(theme.breakpoints.down('md'));

  const { t } = useTranslation("ui")

  const { params: { currentTab } } = useMatch({ path: "/:currentTab", end: false }) ?? { params: { currentTab: "" } };
  if (isMobile) return <MobileHeader anchor={anchor} currentTab={currentTab} />
  return <AppBar position="static" sx={{ bgcolor: "#343a40", display: "flex", flexWrap: "nowrap" }} elevation={0} id={anchor} >
    <Tabs
      value={currentTab}
      variant="scrollable"
      scrollButtons="auto"

      sx={{
        "& .MuiTab-root": {
          px: 1,
          flexDirection: "row",
          minWidth: 40,
          minHeight: "auto",
        },
        "& .MuiTab-root:hover": {
          transition: "background-color 0.5s ease",
          backgroundColor: "rgba(255,255,255,0.1)"
        },
        "& .MuiTab-root > .MuiTab-iconWrapper": {
          mb: 0,
          mr: 0.5
        },
      }}
    >
      <Tab value="" component={RouterLink} to="/" label={<Typography variant="h6" sx={{ px: 1 }}>
        <Trans t={t} i18nKey="pageTitle">Genshin Optimizer</Trans>
      </Typography>} />
      {content.map(({ i18Key, value, to, svg }) => <Tab key={value} value={value} component={RouterLink} to={to} icon={<FontAwesomeIcon icon={svg} />} label={t(i18Key)} />)}
      <Box flexGrow={1} />
      {links.map(({ i18Key, href, label, svg }) => <Tab key={label} component="a" href={href} target="_blank" icon={<FontAwesomeIcon icon={svg} />} onClick={e => ReactGA.outboundLink({ label }, () => { })} label={isLarge && t(i18Key)} />)}
    </Tabs>
  </AppBar>
}
Example #20
Source File: OneTimeDonationPage.tsx    From frontend with MIT License 5 votes vote down vote up
export default function OneTimeDonation({ slug }: { slug: string }) {
  const { data } = useViewCampaign(slug)
  if (!data || !data.campaign) return <NotFoundPage />
  const { campaign } = data
  const matches = useMediaQuery('sm')

  const bannerSource = backgroundCampaignPictureUrl(campaign)
  const beneficiaryAvatarSource = beneficiaryCampaignPictureUrl(campaign)
  return (
    <StyledLayout maxWidth={false}>
      <Grid
        container
        component="section"
        maxWidth="lg"
        justifyContent="center"
        m="0 auto"
        marginTop={theme.spacing(matches ? 20 : 25)}>
        <Box className={classes.bannerWrapper}>
          <Image
            src={bannerSource}
            alt="Campaign banner image"
            layout="fill"
            objectFit="cover"
            className={classes.banner}
          />
        </Box>

        <Grid
          item
          xs={12}
          justifyContent="center"
          p={4}
          className={classes.beneficiaryAvatarWrapper}>
          <Image
            src={beneficiaryAvatarSource}
            alt={campaign.title}
            width={250}
            height={250}
            className={classes.beneficiaryAvatar}
          />
        </Grid>
        <Grid className={classes.stepperWrapper}>
          <Typography variant="h4" sx={{ textAlign: 'center', marginBottom: theme.spacing(4) }}>
            {campaign.title}
          </Typography>
          <DonationStepper />
        </Grid>
      </Grid>
    </StyledLayout>
  )
}
Example #21
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 #22
Source File: add-button.tsx    From tams-club-cal with MIT License 5 votes vote down vote up
AddButton = (props: AddButtonProps) => {
    const router = useRouter();
    const theme = useTheme();
    const matches = useMediaQuery(theme.breakpoints.down('md'));

    const redirectTo = () => {
        router.push(props.path || '#');
    };

    // Change position of button to the left side if it's the edit history button
    const leftOrRight = props.editHistory ? { left: { lg: 32, xs: 12 } } : { right: { lg: 32, xs: 12 } };

    return (
        <Tooltip
            title={
                props.editHistory ? 'Show Edit History' : `${props.edit ? 'Edit' : 'Add'} ${props.label || 'resource'}`
            }
        >
            <Fab
                variant={props.editHistory ? 'extended' : 'circular'}
                size={matches ? 'small' : 'large'}
                color={props.editHistory ? 'primary' : props.color || 'default'}
                aria-label={props.editHistory ? 'edit history' : props.edit ? 'edit' : 'add'}
                onClick={redirectTo}
                sx={{
                    display: 'flex',
                    margin: props.editHistory ? '12px auto' : 'auto',
                    position: 'fixed',
                    bottom: { lg: 32, xs: 12 },
                    zIndex: (theme) => theme.zIndex.appBar + 1,
                    color: (theme) => theme.palette.common.white,
                    ...leftOrRight,
                }}
            >
                {props.editHistory ? (
                    <AccessTimeRoundedIcon sx={{ marginRight: 1 }} width="16" />
                ) : props.edit ? (
                    <EditIcon width="16" />
                ) : (
                    <AddIcon htmlColor="white" width="16" />
                )}
                {props.editHistory ? 'Show Edit History' : null}
            </Fab>
        </Tooltip>
    );
}
Example #23
Source File: useIsSmallDisplay.ts    From GTAV-NativeDB with MIT License 5 votes vote down vote up
export default function useIsSmallDisplay() {
  const theme = useTheme()
  return useMediaQuery(theme.breakpoints.down('md'))
}
Example #24
Source File: ProductCard.tsx    From Cromwell with MIT License 5 votes vote down vote up
ProductCard = (props?: ProductCardProps & {
  className?: string;
}) => {
  const { product } = props ?? {};
  const router = useRouter();
  const isMobile = useMediaQuery<Theme>((theme) => theme.breakpoints.down('sm'));
  const variant = (props?.variant === 'horizontal' && !isMobile) ? 'horizontal' : 'vertical';

  const handleOpenQuickView = () => {
    if (!product?.id) return;
    appState.isQuickViewOpen = true;
    appState.quickViewProductId = product?.id;
  }

  if (!product) return null;

  return (
    <MuiProductCard
      product={product}
      attributes={props?.attributes}
      classes={{
        root: clsx(props?.className, commonStyles.onHoverLinkContainer, styles.Product),
        title: commonStyles.onHoverLink,
      }}
      onOpenCart={() => appState.isCartOpen = true}
      onOpenWishlist={() => appState.isWishlistOpen = true}
      noImagePlaceholderUrl={'/themes/@cromwell/theme-store/no-photos.png'}
      variant={variant}
      onFailedAddToCart={(item, result) => {
        if (result.code === 4) {
          handleOpenQuickView();
        }
      }}
      elements={{
        OtherActions: () => {
          return (
            <Tooltip title="Quick view">
              <IconButton
                aria-label="Open product in quick view"
                className={styles.actionBtn}
                onClick={handleOpenQuickView}>
                <SearchIcon />
              </IconButton>
            </Tooltip>
          )
        },
      }}
      onProductLinkClick={(event, link) => router?.push(link)}
      imageProps={{ unoptimized: true }}
    />
  );
}
Example #25
Source File: SearchResultModule.tsx    From ui-schema with MIT License 5 votes vote down vote up
SearchResultModule: React.FC<{
    match: any
    term: string | undefined
}> = (
    {
        match, term,
    },
) => {
    const {setOpen} = useSearch()
    const {setOpen: setDrawerOpen} = useDrawer()
    const {breakpoints} = useTheme()
    const isMd = useMediaQuery(breakpoints.up('md'))
    return <Box mb={1}>
        <SearchLink
            to={match.pagePath + '#doc-module--' + match.module}
            onClick={() => {
                setOpen(false)
                if (!isMd) {
                    setDrawerOpen(false)
                }
            }}
            // style={{textDecoration: 'none'}}
        >
            <Paper variant={'outlined'} style={{borderRadius: 5}}>
                <Box p={1}>
                    <Typography>
                        <Highlighter
                            searchWords={term?.split(' ') || []}
                            textToHighlight={match.module}
                            autoEscape
                            highlightTag={SearchHighlight}
                        />
                    </Typography>
                    <Box style={{display: 'flex'}}>
                        <Typography variant={'body2'}>{match.package}</Typography>
                        <Typography variant={'caption'} style={{marginLeft: 'auto', opacity: 0.6}}>Score: {match.score.toFixed(2)}</Typography>
                    </Box>
                </Box>
            </Paper>
        </SearchLink>
    </Box>
}
Example #26
Source File: DonationTab.tsx    From frontend with MIT License 4 votes vote down vote up
export default function DonationTab() {
  const router = useRouter()
  const { t } = useTranslation()
  const matches = useMediaQuery(theme.breakpoints.down('md'))

  const { data: user } = getCurrentPerson(!!router.query?.register)
  if (router.query?.register) {
    delete router.query.register
    router.replace({ pathname: router.pathname, query: router.query }, undefined, { shallow: true })
  }
  const { data: userDonations, isLoading: isUserDonationLoading } = useUserDonations()
  const { data: campaigns, isLoading: isCampaignLoading } = useCampaignList()
  return (
    <StyledProfileTab name={ProfileTabs.donations}>
      <Typography className={classes.h1}>{user?.user ? user.user.firstName + ',' : ''}</Typography>
      <Typography variant="h5" fontWeight={'medium'}>
        {t('profile:donations.helpThanks')} ❤️
      </Typography>
      <Grid
        container
        spacing={theme.spacing(2)}
        marginTop={theme.spacing(1)}
        alignItems={'flex-end'}>
        <Grid order={matches ? 3 : 1} item xs={12} md={4}>
          <Card>
            {!isCampaignLoading && campaigns ? (
              <CardActionArea>
                <CardMedia
                  component="img"
                  height="193"
                  image={campaignListPictureUrl(campaigns[0])}
                  alt={campaigns[0].title}
                />
                <CardContent>
                  <Typography gutterBottom variant="h5" component="div">
                    {campaigns[0].title}
                  </Typography>
                  <Typography variant="body2" color="text.secondary">
                    {truncate(campaigns[0].description, { length: 120 })}
                  </Typography>
                </CardContent>
              </CardActionArea>
            ) : (
              <CircularProgress />
            )}
            <CardActions>
              <Button variant="contained" size="medium" color="secondary">
                {t('profile:donations.donateNow')} ❤️
              </Button>
            </CardActions>
          </Card>
        </Grid>
        <Grid order={matches ? 1 : 2} item xs={12} md={8}>
          {!isUserDonationLoading && userDonations ? (
            <Card className={classes.donationsBox}>
              <Box className={classes.donationsBoxRow}>
                <Typography fontWeight="medium" variant="h5">
                  {t('profile:donations.totalDonations')}
                </Typography>
                <Typography fontWeight="medium" variant="h5">
                  {money(userDonations.total)}
                </Typography>
              </Box>
              <Box className={classes.donationsBoxRow}>
                <Box>
                  <Typography variant="h5">{t('profile:donations.recurringDonations')}</Typography>
                  {/* TODO: Use date-fns to format and localize the months,
                   that the user has recurring donations when that is possible */}
                  {/* <Typography>Я, Ф, М, А 2022</Typography> */}
                </Box>
                <Typography fontWeight="medium" variant="h5">
                  {money(sumBy(userDonations.donations, 'amount'))}
                </Typography>
              </Box>
              <Box className={classes.donationsBoxRow}>
                <Typography variant="h5">{t('profile:donations.cardDonations')}</Typography>
                <Typography fontWeight="medium" variant="h5">
                  {money(userDonations.total)}
                </Typography>
              </Box>
              <Box className={classes.donationsBoxRow}>
                <Typography variant="h5">{t('profile:donations.bankDonations')}</Typography>
                <Typography fontWeight="medium" variant="h5">
                  {money(userDonations.total)}
                </Typography>
              </Box>
            </Card>
          ) : (
            <CircularProgress />
          )}
        </Grid>
        <Grid order={matches ? 2 : 3} item xs={12}>
          <DonationTable donations={userDonations?.donations} />
        </Grid>
      </Grid>
    </StyledProfileTab>
  )
}
Example #27
Source File: LinearGraphWidget.tsx    From console with GNU Affero General Public License v3.0 4 votes vote down vote up
LinearGraphWidget = ({
  classes,
  title,

  timeStart,
  timeEnd,
  propLoading,
  panelItem,
  apiPrefix,
  hideYAxis = false,
  areaWidget = false,
  yAxisFormatter = (item: string) => item,
  xAxisFormatter = (item: string) => item,
  zoomActivated = false,
}: ILinearGraphWidget) => {
  const dispatch = useDispatch();
  const [loading, setLoading] = useState<boolean>(true);
  const [data, setData] = useState<object[]>([]);
  const [dataMax, setDataMax] = useState<number>(0);
  const [result, setResult] = useState<IDashboardPanel | null>(null);

  useEffect(() => {
    if (propLoading) {
      setLoading(true);
    }
  }, [propLoading]);

  useEffect(() => {
    if (loading) {
      let stepCalc = 0;
      if (timeStart !== null && timeEnd !== null) {
        const secondsInPeriod = timeEnd.unix() - timeStart.unix();
        const periods = Math.floor(secondsInPeriod / 60);

        stepCalc = periods < 1 ? 15 : periods;
      }

      api
        .invoke(
          "GET",
          `/api/v1/${apiPrefix}/info/widgets/${
            panelItem.id
          }/?step=${stepCalc}&${
            timeStart !== null ? `&start=${timeStart.unix()}` : ""
          }${timeStart !== null && timeEnd !== null ? "&" : ""}${
            timeEnd !== null ? `end=${timeEnd.unix()}` : ""
          }`
        )
        .then((res: any) => {
          const widgetsWithValue = widgetDetailsToPanel(res, panelItem);
          setData(widgetsWithValue.data);
          setResult(widgetsWithValue);
          setLoading(false);
          let maxVal = 0;
          for (const dp of widgetsWithValue.data) {
            for (const key in dp) {
              if (key === "name") {
                continue;
              }
              let val = parseInt(dp[key]);

              if (isNaN(val)) {
                val = 0;
              }

              if (maxVal < val) {
                maxVal = val;
              }
            }
          }
          setDataMax(maxVal);
        })
        .catch((err: ErrorResponseHandler) => {
          dispatch(setErrorSnackMessage(err));
          setLoading(false);
        });
    }
  }, [loading, panelItem, timeEnd, timeStart, dispatch, apiPrefix]);

  let intervalCount = Math.floor(data.length / 5);

  const linearConfiguration = result
    ? (result?.widgetConfiguration as ILinearGraphConfiguration[])
    : [];

  const CustomizedDot = (prop: any) => {
    const { cx, cy, index } = prop;

    if (index % 3 !== 0) {
      return null;
    }
    return <circle cx={cx} cy={cy} r={3} strokeWidth={0} fill="#07264A" />;
  };

  const theme = useTheme();
  const biggerThanMd = useMediaQuery(theme.breakpoints.up("md"));

  return (
    <Box className={zoomActivated ? "" : classes.singleValueContainer}>
      {!zoomActivated && (
        <div className={classes.titleContainer}>
          {title} <ExpandGraphLink panelItem={panelItem} />
        </div>
      )}
      <Box
        sx={
          zoomActivated
            ? { flexDirection: "column" }
            : {
                height: "100%",
                display: "grid",
                gridTemplateColumns: {
                  md: "1fr 1fr",
                  sm: "1fr",
                },
              }
        }
        style={areaWidget ? { gridTemplateColumns: "1fr" } : {}}
      >
        {loading && <Loader className={classes.loadingAlign} />}
        {!loading && (
          <React.Fragment>
            <div
              className={
                zoomActivated ? classes.zoomChartCont : classes.chartCont
              }
            >
              <ResponsiveContainer width="99%">
                <AreaChart
                  data={data}
                  margin={{
                    top: 5,
                    right: 20,
                    left: hideYAxis ? 20 : 5,
                    bottom: 0,
                  }}
                >
                  {areaWidget && (
                    <defs>
                      <linearGradient id="colorUv" x1="0" y1="0" x2="0" y2="1">
                        <stop offset="0%" stopColor="#2781B0" stopOpacity={1} />
                        <stop
                          offset="100%"
                          stopColor="#ffffff"
                          stopOpacity={0}
                        />

                        <stop
                          offset="95%"
                          stopColor="#ffffff"
                          stopOpacity={0.8}
                        />
                      </linearGradient>
                    </defs>
                  )}
                  <CartesianGrid
                    strokeDasharray={areaWidget ? "2 2" : "5 5"}
                    strokeWidth={1}
                    strokeOpacity={1}
                    stroke={"#eee0e0"}
                    vertical={!areaWidget}
                  />
                  <XAxis
                    dataKey="name"
                    tickFormatter={(value: any) => xAxisFormatter(value)}
                    interval={intervalCount}
                    tick={{
                      fontSize: "68%",
                      fontWeight: "normal",
                      color: "#404143",
                    }}
                    tickCount={10}
                    stroke={"#082045"}
                  />
                  <YAxis
                    type={"number"}
                    domain={[0, dataMax * 1.1]}
                    hide={hideYAxis}
                    tickFormatter={(value: any) => yAxisFormatter(value)}
                    tick={{
                      fontSize: "68%",
                      fontWeight: "normal",
                      color: "#404143",
                    }}
                    stroke={"#082045"}
                  />
                  {linearConfiguration.map((section, index) => {
                    return (
                      <Area
                        key={`area-${section.dataKey}-${index.toString()}`}
                        type="monotone"
                        dataKey={section.dataKey}
                        isAnimationActive={false}
                        stroke={!areaWidget ? section.lineColor : "#D7E5F8"}
                        fill={areaWidget ? "url(#colorUv)" : section.fillColor}
                        fillOpacity={areaWidget ? 0.65 : 0}
                        strokeWidth={!areaWidget ? 3 : 0}
                        strokeLinecap={"round"}
                        dot={areaWidget ? <CustomizedDot /> : false}
                      />
                    );
                  })}
                  <Tooltip
                    content={
                      <LineChartTooltip
                        linearConfiguration={linearConfiguration}
                        yAxisFormatter={yAxisFormatter}
                      />
                    }
                    wrapperStyle={{
                      zIndex: 5000,
                    }}
                  />
                </AreaChart>
              </ResponsiveContainer>
            </div>
            {!areaWidget && (
              <Fragment>
                {zoomActivated && (
                  <Fragment>
                    <strong>Series</strong>
                    <br />
                    <br />
                  </Fragment>
                )}
                {biggerThanMd && (
                  <div className={classes.legendChart}>
                    {linearConfiguration.map((section, index) => {
                      return (
                        <div
                          className={classes.singleLegendContainer}
                          key={`legend-${section.keyLabel}-${index.toString()}`}
                        >
                          <div
                            className={classes.colorContainer}
                            style={{ backgroundColor: section.lineColor }}
                          />
                          <div className={classes.legendLabel}>
                            {section.keyLabel}
                          </div>
                        </div>
                      );
                    })}
                  </div>
                )}
              </Fragment>
            )}
          </React.Fragment>
        )}
      </Box>
    </Box>
  );
}
Example #28
Source File: DocsDetails.tsx    From ui-schema with MIT License 4 votes vote down vote up
DocContent: React.FC<{
    content: string | undefined
    id: string
    progress: string
    doc?: DocRouteModule
}> = ({content, id, progress, doc}) => {
    const {palette} = useTheme()
    const [loadingModuleDocs, setLoadingModuleDocs] = React.useState<boolean>(false)
    const [fullWidth, setFullWidth] = React.useState(window.localStorage.getItem('docs-details--fullWidth') === 'yes')
    const [modules, setModules] = React.useState<any>(undefined)
    const {breakpoints} = useTheme()
    const isLg = useMediaQuery(breakpoints.up('lg'))
    const module = doc?.docModule
    React.useEffect(() => {
        if (!module || (module && moduleDocsCache.current[module.modulePath])) {
            setModules(module ? moduleDocsCache.current[module.modulePath] : undefined)
            setLoadingModuleDocs(false)
            return
        }
        setLoadingModuleDocs(true)
        fetch('/docs/' + module.package + '/' + module.fromPath + '.json')
            .then((res) => res.status !== 200 ? Promise.reject(res) : res.json())
            .then((data) => {
                moduleDocsCache.current[module.modulePath] = data
                setModules(data)
                setLoadingModuleDocs(false)
            })
            .catch(e => {
                console.error('error loading module-api docs', module, e)
                setLoadingModuleDocs(false)
            })
        return () => setModules(undefined)
    }, [module])

    const mdData = React.useMemo(() => {
        if (!content) return undefined
        const lines: string[] = content.split('\n')
        // todo: add correct front-matter extraction, but e.g. `front-matter` is no longer maintained/browser-optimized
        if (lines[0] === '---') {
            const i = lines.slice(1).findIndex((l: string) => l === '---')
            if (i !== -1) {
                lines.splice(0, i + 2)
            }
        }
        return lines.join('\n')
    }, [content])

    return <>
        <PageContent maxWidth={isLg && fullWidth ? 'xl' : 'md'} style={{flexGrow: 1}}>
            <div style={{display: 'flex', alignItems: 'center', margin: '4px 12px'}}>
                {isLg ?
                    <Button
                        onClick={() => {
                            setFullWidth(f => {
                                const n = !f
                                window.localStorage.setItem('docs-details--fullWidth', n ? 'yes' : 'no')
                                return n
                            })
                        }}
                        color={'secondary'} size={'small'}
                    >
                        {fullWidth ? <IcShowCompact style={{transform: 'rotate(90deg)'}}/> : <IcShowFull style={{transform: 'rotate(90deg)'}}/>}
                    </Button> : null}
                <Typography variant={'body2'} style={{marginLeft: 'auto'}}>
                    <Link
                        target={'_blank'} rel="noreferrer noopener nofollow"
                        href={'https://github.com/ui-schema/ui-schema/tree/develop/packages/docs/src/content/' + id + '.md'}
                    >Edit Page</Link>
                </Typography>
            </div>

            <Paper style={{margin: '0 0 12px 0', padding: 24, display: 'flex', flexDirection: 'column', borderRadius: 5}} variant={'outlined'}>
                {progress === 'start' || progress === 'progress' || loadingModuleDocs ?
                    <LoadingCircular title={'Loading Docs'}/> :
                    progress === 'error' ?
                        'error' :
                        progress === 'not-found' ?
                            <PageNotFound
                                title={'Not Available'}
                                error={'This document seems to be vanished - or not yet created.'}
                            /> :
                            <Markdown source={mdData}/>}
            </Paper>

            {progress === 'success' && !loadingModuleDocs ?
                <>
                    {doc?.demos?.schema ?
                        <div style={{display: 'block', textAlign: 'right', margin: '0 12px 4px 12px'}}>
                            <Typography variant={'body2'} style={{marginLeft: 'auto'}}>
                                <Link
                                    target={'_blank'} rel="noreferrer noopener nofollow"
                                    href={'https://github.com/ui-schema/ui-schema/tree/develop/packages/docs/src/content/' + id + 'Demo.js'}
                                >Edit Demos</Link>
                            </Typography>
                        </div> : null}

                    {doc?.demos?.schema ?
                        <Paper style={{marginBottom: 12, padding: 24, display: 'flex', flexDirection: 'column', borderRadius: 5}} variant={'outlined'}>
                            <Markdown
                                source={`
## Demo UI Generator

Examples of this widget, using \`ds-material\`. Type in/change the input and check the data or change the schema (e.g. add specific keywords from above), the demo generators are showing invalid directly.
`}/>
                            {doc?.demos?.schema.map(([demoText, demoSchema], i) =>
                                <React.Fragment key={i}>
                                    <Markdown source={demoText}/>
                                    <DemoUIGenerator activeSchema={demoSchema} id={'i-' + i}/>
                                </React.Fragment>)}
                        </Paper>
                        : null}

                    {doc?.docModule ?
                        <Paper style={{margin: '12px 0', padding: 24, display: 'flex', flexDirection: 'column', borderRadius: 5}} variant={'outlined'}>
                            <DocsDetailsModules modules={modules}/>
                        </Paper> : null}
                </> : null}
        </PageContent>

        <Paper
            style={{
                margin: '0 12px',
                // padding: '0 12px',
                display: 'flex',
                flexDirection: 'column',
                overflowX: 'auto',
                opacity: progress === 'success' ? 1 : 0,
                transition: '0.32s opacity ease-out',
                flexShrink: 0,
                position: 'sticky',
                bottom: 12,
                left: 0,
                right: 0,
                zIndex: 10,
                maxHeight: '85vh',
                maxWidth: 375,
                borderRadius: 5,
                //borderTop: '1px solid ' + palette.primary.main,
                //background: palette.primary.main,
                boxShadow: '0px 2px 4px -1px rgba(0,0,0,0.2),0px 4px 5px 0px rgba(0,0,0,0.14),0px 1px 10px 0px rgba(0,0,0,0.12)',
            }}
            // elevation={4}
            variant={'outlined'}
        >
            <LinkableHeadlineMenu
                disableNavLink
                //style={{margin: 0, padding: 0}}
                startIcon={<IcToc/>}
                titleStyle={{color: palette.background.paper, fontWeight: 'bold', background: palette.primary.main}}
                btnVariant={'contained'}
                disablePadding
                bindKey={'m'}
                linkListStyle={{display: 'flex', flexDirection: 'column', overflow: 'auto'}}
                // collapseStyle={{overflow: 'auto'}}
                //linkItemStyle={{color: palette.background.paper}}
            />
        </Paper>
    </>
}
Example #29
Source File: ProfilePage.tsx    From frontend with MIT License 4 votes vote down vote up
export default function ProfilePage() {
  const { t } = useTranslation()
  const { status } = useSession()

  const router = useRouter()
  const matches = useMediaQuery(theme.breakpoints.down('sm'))
  const currentTab = router.query.slug ?? ProfileTabs.donations
  const tab = useMemo<ProfileTab>(() => {
    return tabs.find((tab) => tab.slug === currentTab) ?? tabs[0]
  }, [currentTab])

  if (status === 'loading') {
    return <LinearProgress />
  }

  if (status !== 'authenticated') {
    return (
      <StyledLayout
        title={t('nav.profile')}
        githubUrl="https://github.com/podkrepi-bg/frontend/tree/master/src/components/auth/profile/ProfilePage.tsx"
        figmaUrl="https://www.figma.com/file/MmvFKzUv6yE5U2wrOpWtwS/Podkrepi.bg?node-id=5987%3A21094">
        Not authenticated
      </StyledLayout>
    )
  }

  const { Component: SelectedTab } = tab

  return (
    <Layout profilePage={true}>
      <Box sx={{ width: '100%' }}>
        <Box
          sx={{
            backgroundColor: 'white',
            borderRadius: '25px 25px 0px 0px',
            padding: '10px 30px',
            boxShadow: 3,
          }}>
          <h1 className={classes.h1}>Дарителски профил</h1>
          <Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
            <Tabs value={tab.slug}>
              <Tab
                className={matches ? classes.tabMobile : ''}
                value={ProfileTabs.donations}
                label={matches ? undefined : t('profile:donations.index')}
                aria-label={matches ? t('profile:donations.index') : undefined}
                onClick={() => router.push(routes.profile.donations)}
                icon={matches ? <DonationIcon /> : undefined}
              />
              <Tab
                className={matches ? classes.tabMobile : ''}
                value={ProfileTabs.personalInformation}
                label={matches ? undefined : t('profile:personalInformation')}
                aria-label={matches ? t('profile:personalInformation') : undefined}
                onClick={() => router.push(routes.profile.personalInformation)}
                icon={matches ? <AccountBoxIcon /> : undefined}
              />
              <Tab
                className={matches ? classes.tabMobile : ''}
                value={ProfileTabs.certificates}
                label={matches ? undefined : t('profile:certificates')}
                aria-label={matches ? t('profile:certificates') : undefined}
                onClick={() => router.push(routes.profile.certificates)}
                icon={matches ? <CertificateIcon /> : undefined}
              />
              <Tab
                className={matches ? classes.tabMobile : ''}
                value={ProfileTabs.contractDonation}
                label={matches ? undefined : t('profile:donationsContract')}
                aria-label={matches ? t('profile:donationsContract') : undefined}
                onClick={() => router.push(routes.profile.contractDonation)}
                icon={matches ? <ContractIcon /> : undefined}
              />
            </Tabs>
          </Box>
        </Box>
        {SelectedTab && <SelectedTab />}
      </Box>
    </Layout>
  )
}