@mui/material#List TypeScript Examples

The following examples show how to use @mui/material#List. 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: GroupFilter.tsx    From Tachidesk-WebUI with Mozilla Public License 2.0 6 votes vote down vote up
export default function GroupFilter(props: Props) {
    const {
        state,
        name,
        position,
        updateFilterValue,
        update,
    } = props;

    const [open, setOpen] = React.useState(false);

    const handleClick = () => {
        setOpen(!open);
    };

    return (
        <>
            <ListItemButton onClick={handleClick}>
                <ListItemText primary={name} />
                {open ? <ExpandLess /> : <ExpandMore />}
            </ListItemButton>
            <Collapse in={open}>
                <List disablePadding>
                    <Options
                        sourceFilter={state}
                        group={position}
                        updateFilterValue={updateFilterValue}
                        update={update}
                    />
                </List>
            </Collapse>
        </>
    );
}
Example #2
Source File: AppNavbar.tsx    From sapio-studio with Mozilla Public License 2.0 6 votes vote down vote up
export function AppNavbar(props: {
    relayout: () => void;
    contract: ContractModel;
    bitcoin_node_manager: BitcoinNodeManager;
}): JSX.Element {
    const dispatch = useDispatch();

    return (
        <Paper className="AppNavBar" square={true}>
            <List sx={{ textAlign: 'center' }}>
                <MainScreens></MainScreens>
            </List>
            <Divider />
            <List>
                <ContractMenu relayout={props.relayout} />
                <NodeMenu bitcoin_node_manager={props.bitcoin_node_manager} />
                <Simulator />
            </List>
            <Divider />
            <List>
                <SettingsMenuItem />
            </List>
            <Divider />
        </Paper>
    );
}
Example #3
Source File: navigation.tsx    From sdk with MIT License 6 votes vote down vote up
export function Navigation() {
	const links = [{
		label: "About",
		path: "/about",
		default: true
	}, {
		label: "Connect",
		path: "/connect"
	}, {
		label: "Deploy Collection",
		path: "/deploy"
	}, {
		label: "Mint Token",
		path: "/mint"
	}, {
		label: "Sell",
		path: "/sell"
	}, {
		label: "Buy",
		path: "/buy"
	}, {
		label: "Bid",
		path: "/bid"
	}, {
		label: "Accept Bid",
		path: "/accept-bid"
	}, {
		label: "My Items",
		path: "/items"
	}]

	return (
		<List>
			{links.map((link) => (
				<ListItemLink key={link.path} to={link.path} primary={link.label} default={link.default}/>
			))}
		</List>
	)
}
Example #4
Source File: navigation.tsx    From example with MIT License 6 votes vote down vote up
export function Navigation() {
	const links = [{
		label: "About",
		path: "/about",
		default: true
	}, {
		label: "Connect",
		path: "/connect"
	}, {
		label: "Deploy Collection",
		path: "/deploy"
	}, {
		label: "Mint Token",
		path: "/mint"
	}, {
		label: "Sell",
		path: "/sell"
	}, {
		label: "Buy",
		path: "/buy"
	}, {
		label: "Bid",
		path: "/bid"
	}, {
		label: "Accept Bid",
		path: "/accept-bid"
	}]

	return (
		<List>
			{links.map((link) => (
				<ListItemLink key={link.path} to={link.path} primary={link.label} default={link.default}/>
			))}
		</List>
	)
}
Example #5
Source File: FileList.tsx    From frontend with MIT License 6 votes vote down vote up
function FileList({ files, onDelete }: Props) {
  return (
    <List dense>
      {files.map((file, key) => (
        <ListItem
          key={key}
          secondaryAction={
            <IconButton edge="end" aria-label="delete" onClick={() => onDelete && onDelete(file)}>
              <Delete />
            </IconButton>
          }>
          <ListItemAvatar>
            <Avatar>
              <UploadFile />
            </Avatar>
          </ListItemAvatar>
          <ListItemText primary={file.type} />
          <ListItemText primary={file.name} />
        </ListItem>
      ))}
    </List>
  )
}
Example #6
Source File: Profile.tsx    From abrechnung with GNU Affero General Public License v3.0 6 votes vote down vote up
export default function Profile() {
    const user = useRecoilValue(userData);
    const isGuest = useRecoilValue(isGuestUser);
    useTitle("Abrechnung - Profile");

    return (
        <MobilePaper>
            <Typography component="h3" variant="h5">
                Profile
            </Typography>
            {isGuest && (
                <Alert severity="info">
                    You are a guest user on this Abrechnung and therefore not permitted to create new groups or group
                    invites.
                </Alert>
            )}
            <List>
                <ListItem>
                    <ListItemText primary="Username" secondary={user.username} />
                </ListItem>
                <ListItem>
                    <ListItemText primary="E-Mail" secondary={user.email} />
                </ListItem>
                <ListItem>
                    <ListItemText
                        primary="Registered"
                        secondary={DateTime.fromISO(user.registered_at).toLocaleString(DateTime.DATETIME_FULL)}
                    />
                </ListItem>
            </List>
        </MobilePaper>
    );
}
Example #7
Source File: ExpandableListItem.tsx    From frontend with MIT License 6 votes vote down vote up
ExpandableListItem = ({ header, content }: Props) => {
  const [open, setOpen] = useState(false)

  return (
    <List
      sx={{
        my: 0,
        mx: { xs: 0, md: 3 },
        cursor: 'pointer',
      }}>
      <Paper elevation={1} sx={{ borderRadius: 2 }}>
        <Box
          sx={{ display: 'flex', alignItems: 'center', px: 3, py: 1 }}
          onClick={() => setOpen(!open)}>
          <ListItemText
            primary={header}
            primaryTypographyProps={{
              variant: 'subtitle1',
              color: `${withAccentColor(open)}`,
            }}
          />
          {open ? (
            <ExpandLess sx={{ color: `${withAccentColor(open)}` }} />
          ) : (
            <ExpandMore sx={{ color: `${withAccentColor(open)}` }} />
          )}
        </Box>
        <Collapse in={open}>
          <List>
            <Box sx={{ pl: { xs: 3, md: 6 }, pb: 2, pr: 2 }}>{content}</Box>
          </List>
        </Collapse>
      </Paper>
    </List>
  )
}
Example #8
Source File: AccountTransactionList.tsx    From abrechnung with GNU Affero General Public License v3.0 6 votes vote down vote up
export default function AccountTransactionList({ group, accountID }) {
    const transactions = useRecoilValue(accountTransactions({ groupID: group.id, accountID: accountID }));
    const clearingAccounts = useRecoilValue(clearingAccountsInvolvingUser({ groupID: group.id, accountID: accountID }));

    const combinedList: ArrayAccountsAndTransactions = (transactions as ArrayAccountsAndTransactions)
        .concat(clearingAccounts)
        .sort((f1, f2) => f2.last_changed.toSeconds() - f1.last_changed.toSeconds());

    return (
        <List>
            {combinedList.map((entry) => {
                if (entry.type === "clearing") {
                    return (
                        <AccountClearingListEntry key={entry.id} accountID={accountID} group={group} account={entry} />
                    );
                }

                return (
                    <AccountTransactionListEntry
                        key={entry.id}
                        accountID={accountID}
                        group={group}
                        transaction={entry}
                    />
                );
            })}
        </List>
    );
}
Example #9
Source File: Vault.tsx    From NekoMaid with MIT License 6 votes vote down vote up
Groups: React.FC<{ plugin: Plugin, id: string | undefined, onClose: () => void, groups: GroupInfo[] }> =
  ({ plugin, id, onClose, groups }) => {
    const [loading, setLoading] = useState(true)
    const [playerGroups, setPlayerGroups] = useState<Record<string, true>>({ })
    const refresh = () => {
      setLoading(true)
      plugin.emit('vault:playerGroup', (res: string[]) => {
        if (!res) return
        const obj: Record<string, true> = { }
        res.forEach(it => (obj[it] = true))
        setPlayerGroups(obj)
        setLoading(false)
      }, id, null, 0)
    }
    useEffect(() => {
      setPlayerGroups({})
      if (!id) return
      refresh()
    }, [id])
    return <Dialog onClose={onClose} open={!!id}>
      <DialogTitle>{lang.vault.whosPermissionGroup(id!)}</DialogTitle>
      <List sx={{ pt: 0 }}>
        {groups.map(it => <ListItem onClick={() => { }} key={it.id}>
          <ListItemIcon><Checkbox
            tabIndex={-1}
            disabled={loading}
            checked={!!playerGroups[it.id]}
            onChange={e => plugin.emit('vault:playerGroup', (res: boolean) => {
              action(res)
              refresh()
            }, id, it.id, e.target.checked ? 1 : 2)}
          /></ListItemIcon>
          <ListItemText primary={it.id} />
        </ListItem>)}
      </List>
      <DialogActions><Button onClick={onClose}>{minecraft['gui.back']}</Button></DialogActions>
    </Dialog>
  }
Example #10
Source File: WidgetsList.tsx    From fluttertemplates.dev with MIT License 6 votes vote down vote up
function WidgetsList(props: WidgetsListProps) {
  return (
    <div
      style={{
        width: `100%`,
        marginTop: "1rem",
        marginLeft: "1rem",
      }}
    >
      <Typography
        variant="h4"
        style={{
          fontWeight: "bold",
        }}
      >
        {props.componentSubgroup.title}
      </Typography>
      <List>
        {props.componentSubgroup.widgets.map((item, index) => (
          <WidgetDemoBlock
            key={`widget_${index}_${item.title}`}
            title={item.title}
            codeUrl={item.codeUrl}
            demoUrl={item.demoUrl}
            rawCodeUrl={item.rawCodeUrl}
            description={item.description}
            id={item.id.split("/").slice(-1)[0]}
          />
        ))}
      </List>
    </div>
  );
}
Example #11
Source File: FieldDisplay.tsx    From genshin-optimizer with MIT License 6 votes vote down vote up
FieldDisplayList = styled(List)(({ theme }) => ({
  borderRadius: theme.shape.borderRadius,
  overflow: "hidden",
  margin: 0,
  '> .MuiListItem-root:nth-of-type(even)': {
    backgroundColor: theme.palette.contentDark.main
  },
  '> .MuiListItem-root:nth-of-type(odd)': {
    backgroundColor: theme.palette.contentDarker.main
  },
}))
Example #12
Source File: Dashboard.tsx    From NekoMaid with MIT License 5 votes vote down vote up
Players: React.FC<{ players?: CurrentStatus['players'] }> = React.memo(({ players }) => {
  const his = useHistory()
  const plugin = usePlugin()
  const globalData = useGlobalData()
  const [page, setPage] = useState(1)
  const [id, update] = useState(0)
  return <Card>
    <CardHeader title={lang.dashboard.onlinePlayers} />
    <Divider />
    <CardContent>
      {players?.length === 0
        ? <Empty />
        : <>
        <List sx={{ paddingTop: 0 }}>
          {players
            ? players.slice((page - 1) * 8, page * 8).map(p => {
              const name = typeof p === 'string' ? p : p.name
              return <Tooltip key={name} title={'IP: ' + ((p as any).ip || lang.unknown)}>
                <ListItem
                  secondaryAction={<>
                    <IconButton
                      edge='end'
                      size='small'
                      onClick={() => dialog(lang.dashboard.confirmKick(<span className='bold'>{name}</span>), lang.reason)
                        .then(it => it != null && plugin.emit('dashboard:kick', (res: boolean) => {
                          action(res)
                          if (!players) return
                          players.splice(players.indexOf(it!), 1)
                          update(id + 1)
                        }, name, it || null))
                      }
                    ><ExitToApp /></IconButton>
                    <IconButton edge='end' onClick={() => his.push('/NekoMaid/playerList/' + name)} size='small'><MoreHoriz /></IconButton>
                  </>
                  }
                >
                  <ListItemAvatar>
                    <Avatar
                      src={getSkin(globalData, name, true)}
                      imgProps={{ crossOrigin: 'anonymous', onClick () { his.push('/NekoMaid/playerList/' + name) }, style: { width: 40, height: 40 } }}
                      sx={{ cursor: 'pointer' }}
                      variant='rounded'
                    />
                  </ListItemAvatar>
                  <ListItemText primary={name} />
                </ListItem>
              </Tooltip>
            })
            : <LoadingList />
          }
        </List>
        {players && <Pagination
          page={page}
          onChange={(_, it) => setPage(it)}
          count={Math.max(Math.ceil(players.length / 8), 1)}
          sx={{ display: 'flex', justifyContent: 'flex-end' }}
        />}
      </>}
    </CardContent>
  </Card>
})
Example #13
Source File: SortFilter.tsx    From Tachidesk-WebUI with Mozilla Public License 2.0 5 votes vote down vote up
export default function SortFilter(props: Props) {
    const {
        values,
        name,
        state,
        position,
        group,
        updateFilterValue,
        update,
    } = props;
    const [val, setval] = React.useState(state);

    const [open, setOpen] = React.useState(false);

    const handleClick = () => {
        setOpen(!open);
    };

    if (values) {
        const handleChange = (event:
        React.MouseEvent<HTMLDivElement, MouseEvent>, index: number) => {
            const tmp = val;
            if (tmp.index === index) {
                tmp.ascending = !tmp.ascending;
            } else {
                tmp.ascending = true;
            }
            tmp.index = index;
            setval(tmp);
            const upd = update.filter((e: {
                position: number; group: number | undefined;
            }) => !(position === e.position && group === e.group));
            updateFilterValue([...upd, { position, state: JSON.stringify(tmp), group }]);
        };

        const ret = (
            <FormControl fullWidth>
                <ListItemButton onClick={handleClick}>
                    <ListItemText primary={name} />
                    {open ? <ExpandLess /> : <ExpandMore />}
                </ListItemButton>
                <Collapse in={open}>
                    <List>
                        {values.map((value: string, index: number) => {
                            let icon;
                            if (val.index === index) {
                                icon = val.ascending ? (<ArrowUpwardIcon color="primary" />)
                                    : (<ArrowDownwardIcon color="primary" />);
                            }
                            return (
                                <ListItem disablePadding key={`${name} ${value}`}>
                                    <ListItemButton
                                        onClick={(event) => handleChange(event, index)}
                                    >
                                        <ListItemIcon>
                                            {icon}
                                        </ListItemIcon>
                                        <ListItemText primary={value} />
                                    </ListItemButton>
                                </ListItem>
                            );
                        })}
                    </List>
                </Collapse>
            </FormControl>
        );
        return (
            <Box key={name} sx={{ display: 'flex', flexDirection: 'column', minWidth: 120 }}>
                {ret}
            </Box>
        );
    }
    return (<></>);
}
Example #14
Source File: ContextMenu.tsx    From multi-downloader-nx with MIT License 5 votes vote down vote up
function ContextMenu<T extends HTMLElement, >(props: ContextMenuProps<T>) {
  const [anchor, setAnchor] = React.useState( { x: 0, y: 0 } );
  
  const [show, setShow] = React.useState(false);

  React.useEffect(() => {
    const { popupItem: ref } = props;
    if (ref.current === null)
      return;
    const listener = (ev: MouseEvent) => {
      ev.preventDefault();
      setAnchor({ x: ev.x + 10, y: ev.y + 10 });
      setShow(true);
    }
    ref.current.addEventListener('contextmenu', listener);

    return () => { 
      if (ref.current)
        ref.current.removeEventListener('contextmenu', listener)
    };
  }, [ props.popupItem ])

  return show ? <Box sx={{ zIndex: 9999, p: 1, background: 'rgba(0, 0, 0, 0.75)', backdropFilter: 'blur(5px)', position: 'fixed', left: anchor.x, top: anchor.y }}>
    <List sx={{ p: 0, m: 0 }}>
      {props.options.map((item, i) => {
        return item === 'divider' ? <Divider key={`ContextMenu_Divider_${i}_${item}`}/> : 
        <Button color='inherit' key={`ContextMenu_Value_${i}_${item}`} onClick={() => {
          item.onClick();
          setShow(false);
        }} sx={buttonSx}>
          {item.text}
        </Button>
      })}
      <Divider />
      <Button fullWidth color='inherit' onClick={() => setShow(false)} sx={buttonSx} >
        Close
      </Button>
    </List>
  </Box> : <></>
}
Example #15
Source File: Header.tsx    From genshin-optimizer with MIT License 5 votes vote down vote up
function MobileHeader({ anchor, currentTab }) {
  const [mobileOpen, setMobileOpen] = useState(false);

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


  const { t } = useTranslation("ui")
  return <>
    <AppBar position="fixed" sx={{ bgcolor: "#343a40" }} elevation={0}  >
      <Drawer
        anchor="right"
        variant="temporary"
        open={mobileOpen}
        onClose={handleDrawerToggle}
        ModalProps={{
          keepMounted: true, // Better open performance on mobile.
        }}
      >
        <List>
          <ListItemButton key="home" component={RouterLink} to={'/'} selected={currentTab === ""} disabled={currentTab === ""} onClick={handleDrawerToggle} >
            <ListItemText>{t("pageTitle")}</ListItemText>
          </ListItemButton >
          {content.map(({ i18Key, value, to, svg }) =>
            <ListItemButton key={value} component={RouterLink} to={to} selected={currentTab === value} disabled={currentTab === value} onClick={handleDrawerToggle} >
              <ListItemIcon><FontAwesomeIcon icon={svg} /></ListItemIcon>
              <ListItemText>{t(i18Key)}</ListItemText>
            </ListItemButton >)}
        </List>
        <Divider />
        <List>
          {links.map(({ i18Key, href, svg, label }) =>
            <ListItemButton key={label} component="a" href={href} target="_blank" onClick={e => ReactGA.outboundLink({ label }, () => { })} >
              <ListItemIcon><FontAwesomeIcon icon={svg} /></ListItemIcon>
              <ListItemText>{t(i18Key)}</ListItemText>
            </ListItemButton >)}
        </List>
      </Drawer>
      <Toolbar>
        <Button variant="text" sx={{ color: "white" }} component={RouterLink} to="/">
          <Typography variant="h6" noWrap component="div">
            <Trans t={t} i18nKey="pageTitle">Genshin Optimizer</Trans>
          </Typography>
        </Button>
        <Box flexGrow={1} />
        <IconButton
          color="inherit"
          aria-label="open drawer"
          edge="end"
          onClick={handleDrawerToggle}
        >
          <MenuIcon />
        </IconButton>
      </Toolbar>
    </AppBar>
    {/* add a blank toolbar to keep space and provide a scroll anchor */}
    <Toolbar id={anchor} />
  </>
}
Example #16
Source File: TLSCertificate.tsx    From console with GNU Affero General Public License v3.0 5 votes vote down vote up
TLSCertificate = ({
  classes,
  certificateInfo,
  onDelete = () => {},
}: ITLSCertificate) => {
  const certificates = certificateInfo.domains || [];
  return (
    <Chip
      key={certificateInfo.name}
      variant="outlined"
      color="primary"
      className={classes.certificateWrapper}
      label={
        <Container>
          <Grid item xs={1} className={classes.certificateIcon}>
            <CertificateIcon />
          </Grid>
          <Grid item xs={11} className={classes.certificateInfo}>
            <Typography variant="subtitle1" display="block" gutterBottom>
              {certificateInfo.name}
            </Typography>
            <Box className={classes.certificateExpiry}>
              <EventBusyIcon color="inherit" fontSize="small" />
              &nbsp;
              <span className={"label"}>Expiry:&nbsp;</span>
              <span>
                <Moment format="YYYY/MM/DD">{certificateInfo.expiry}</Moment>
              </span>
            </Box>
            <Divider />
            <br />
            <Box className={classes.certificateDomains}>
              <span className="label">{`${certificates.length} Domain (s):`}</span>
            </Box>
            <List className={classes.certificatesList}>
              {certificates.map((dom) => (
                <ListItem className={classes.certificatesListItem}>
                  <ListItemAvatar>
                    <LanguageIcon />
                  </ListItemAvatar>
                  <ListItemText primary={dom} />
                </ListItem>
              ))}
            </List>
          </Grid>
        </Container>
      }
      onDelete={onDelete}
    />
  );
}
Example #17
Source File: QueryStateEditor.tsx    From mui-toolpad with MIT License 5 votes vote down vote up
export default function QueryStateEditor() {
  const dom = useDom();
  const state = usePageEditorState();
  const domApi = useDomApi();

  const [editedState, setEditedState] = React.useState<NodeId | null>(null);
  const editedStateNode = editedState ? appDom.getNode(dom, editedState, 'queryState') : null;
  const handleEditStateDialogClose = React.useCallback(() => setEditedState(null), []);

  const page = appDom.getNode(dom, state.nodeId, 'page');
  const { queryStates = [] } = appDom.getChildNodes(dom, page) ?? [];

  // To keep dialog content around during closing animation
  const lastEditedStateNode = useLatest(editedStateNode);

  const handleRemove = React.useCallback(() => {
    if (editedStateNode) {
      domApi.removeNode(editedStateNode.id);
    }
    handleEditStateDialogClose();
  }, [editedStateNode, handleEditStateDialogClose, domApi]);

  return queryStates.length > 0 ? (
    <Stack spacing={1} alignItems="start">
      <List>
        {queryStates.map((stateNode) => {
          return (
            <ListItem key={stateNode.id} button onClick={() => setEditedState(stateNode.id)}>
              {stateNode.name}
            </ListItem>
          );
        })}
      </List>
      {lastEditedStateNode ? (
        <Dialog
          fullWidth
          maxWidth="lg"
          open={!!editedStateNode}
          onClose={handleEditStateDialogClose}
          scroll="body"
        >
          <DialogTitle>Edit Query State ({lastEditedStateNode.id})</DialogTitle>
          <DialogContent>
            <QueryStateNodeEditor node={lastEditedStateNode} />
          </DialogContent>
          <DialogActions>
            <Button color="inherit" variant="text" onClick={handleEditStateDialogClose}>
              Close
            </Button>
            <Button onClick={handleRemove}>Remove</Button>
          </DialogActions>
        </Dialog>
      ) : null}
    </Stack>
  ) : null;
}
Example #18
Source File: index.tsx    From Search-Next with GNU General Public License v3.0 5 votes vote down vote up
NavigationPage: React.FC<PageProps> = (props) => {
  const menu: Classify[] = navigations;
  const history = useNavigate();
  const location = useLocation();
  const params = useParams();
  const [selected, setSelected] = React.useState<Classify>({} as Classify);

  const changeSelect = (path: string, type: 'push' | 'replace' = 'replace') => {
    const find = menu.find((i) => i.path === path);
    if (find) {
      const path = `${basePath}/${find.path}`;
      if (type === 'push') history(path);
      if (type === 'replace') history(path, { replace: true });
      setSelected(find);
    }
  };

  const menuChange = (id: string, item: Classify) => {
    changeSelect(item.path, 'push');
  };

  React.useEffect(() => {
    const path = location.pathname;
    if (path === basePath + '/*') {
      history(`${basePath}/${menu[0].path}`, { replace: true });
      setSelected(menu[0]);
    } else {
      const { classify } = params;
      changeSelect(classify || '');
    }
  }, []);

  return (
    <MenuLayoutNew
      {...props}
      mode="page"
      menu={menu as MenuLayoutMenu[]}
      pathname={basePath}
      onChange={menuChange}
      menuFooter={
        <List dense>
          <MenuListItem
            icon={<InsertComment />}
            primary="提交网站"
            onClick={() => history('/help/commit_website')}
          />
        </List>
      }
    >
      {Recursion(selected)}
    </MenuLayoutNew>
  );
}
Example #19
Source File: AdminLayout.tsx    From frontend with MIT License 5 votes vote down vote up
export default function AdminLayout({ children }: Props) {
  const theme = useTheme()

  const initialOpen = useMemo<boolean>(() => {
    const item = typeof window !== 'undefined' ? window.localStorage.getItem('menu-open') : false
    if (item) {
      return Boolean(JSON.parse(item))
    }
    return false
  }, [])

  const [open, setOpen] = useState<boolean>(initialOpen)

  useEffect(() => {
    if (typeof window !== 'undefined') {
      window.localStorage.setItem('menu-open', JSON.stringify(open))
    }
  }, [open])

  const toggleMenu = useCallback(() => setOpen((open) => !open), [])
  return (
    <StyledBox className={classes.wrapper}>
      <AdminAppBar isOpen={open}>
        <Box className={classes.appbarHeader}>
          <Box sx={{ display: 'flex', alignItems: 'center' }}>
            <IconButton>
              <Notifications color="info" />
            </IconButton>
            <PrivateMenu />
          </Box>
        </Box>
      </AdminAppBar>
      <Drawer variant="permanent" open={open} theme={theme}>
        <DrawerHeader />
        <List sx={{ p: '2rem .5rem', height: '100%', position: 'relative' }}>
          {items.map(({ items, menu, icon }, index) => (
            <HoverMenu isOpen={open} key={index} menu={menu} icon={icon} items={items} />
          ))}
          <CustomListItem icon={open ? <MenuOpen /> : <ChevronRight />} onClick={toggleMenu} />
          <CustomListItem
            icon={<Settings />}
            label={'Настройки'}
            sx={{ position: 'absolute', bottom: '1rem' }}
          />
        </List>
      </Drawer>

      <Box component="main" sx={{ flexGrow: 1 }}>
        <DrawerHeader />
        {children}
      </Box>
      <PanelFooter>
        <Button sx={{ color: 'white' }}>
          <GppGood />
        </Button>
        <Typography color="white">{'Вие сте логнат като администратор'}</Typography>
      </PanelFooter>
      <Snackbar />
    </StyledBox>
  )
}
Example #20
Source File: WalletDialog.tsx    From wallet-adapter with Apache License 2.0 5 votes vote down vote up
WalletDialog: FC<WalletDialogProps> = ({
    title = 'Select your wallet',
    featuredWallets = 3,
    onClose,
    ...props
}) => {
    const { wallets, select } = useWallet();
    const { open, setOpen } = useWalletDialog();
    const [expanded, setExpanded] = useState(false);

    const [featured, more] = useMemo(
        () => [wallets.slice(0, featuredWallets), wallets.slice(featuredWallets)],
        [wallets, featuredWallets]
    );

    const handleClose = useCallback(
        (event: SyntheticEvent, reason?: 'backdropClick' | 'escapeKeyDown') => {
            if (onClose) onClose(event, reason!);
            if (!event.defaultPrevented) setOpen(false);
        },
        [setOpen, onClose]
    );

    const handleWalletClick = useCallback(
        (event: SyntheticEvent, walletName: WalletName) => {
            select(walletName);
            handleClose(event);
        },
        [select, handleClose]
    );

    const handleExpandClick = useCallback(() => setExpanded(!expanded), [setExpanded, expanded]);

    return (
        <RootDialog open={open} onClose={handleClose} {...props}>
            <DialogTitle>
                {title}
                <IconButton onClick={handleClose} size="large">
                    <CloseIcon />
                </IconButton>
            </DialogTitle>
            <DialogContent>
                <List>
                    {featured.map((wallet) => (
                        <WalletListItem
                            key={wallet.adapter.name}
                            onClick={(event) => handleWalletClick(event, wallet.adapter.name)}
                            wallet={wallet}
                        />
                    ))}
                    {more.length ? (
                        <>
                            <Collapse in={expanded} timeout="auto" unmountOnExit>
                                <List>
                                    {more.map((wallet) => (
                                        <WalletListItem
                                            key={wallet.adapter.name}
                                            onClick={(event) => handleWalletClick(event, wallet.adapter.name)}
                                            wallet={wallet}
                                        />
                                    ))}
                                </List>
                            </Collapse>
                            <ListItem>
                                <Button onClick={handleExpandClick}>
                                    {expanded ? 'Less' : 'More'} options
                                    {expanded ? <CollapseIcon /> : <ExpandIcon />}
                                </Button>
                            </ListItem>
                        </>
                    ) : null}
                </List>
            </DialogContent>
        </RootDialog>
    );
}
Example #21
Source File: index.tsx    From Search-Next with GNU General Public License v3.0 5 votes vote down vote up
MenuLayout: React.FC<MenuLayoutProps> = ({
  menu,
  menuFooter,
  basePath = '',
  showCopyright = true,
  children,
  title,
  onChange,
  ...props
}) => {
  const location = useLocation();
  const history = useNavigate();
  const [selected, setSelected] = React.useState<MenuLayoutMenu>(
    [] as unknown as MenuLayoutMenu,
  );

  React.useEffect(() => {
    const state = location?.state as RouteState;
    if (state && state?.search) {
      const sel = menu.find((i) => i.id === state?.search);
      const selected = sel ? sel : menu[0];
      setSelected(selected);
      if (onChange) onChange(selected.id, selected);
    } else {
      setSelected(menu[0]);
      if (onChange) onChange(menu[0].id, menu[0]);
    }
  }, []);

  return (
    <div className="flex h-screen bg-gray-50">
      <div
        className={classNames(
          'max-w-xs flex-grow py-7 px-7 pl-12 border-gray-200 border-r flex flex-col',
          !!menuFooter && 'pb-2',
        )}
      >
        <div className="flex items-center">
          <IconButton size="small" onClick={() => history(-1)}>
            <ArrowBack />
          </IconButton>
          <span className="text-xl font-semibold">{title}</span>
        </div>
        <List dense className="flex-grow">
          {menu.map((i, j) => (
            <MenuListItem
              key={j}
              selected={i.id === selected.id}
              onClick={() => {
                setSelected(i);
                if (onChange) onChange(i.id, i);
              }}
              icon={i.icon}
              primary={i.name}
            />
          ))}
        </List>
        <div>{menuFooter}</div>
      </div>
      <div className="flex-grow h-full flex flex-col">
        <div
          className="flex-grow overflow-y-auto pl-12 pb-8"
          style={{ scrollSnapType: 'proximity' }}
        >
          {children}
        </div>
        {showCopyright && (
          <div className="text-center h-8 max-w-4xl">
            <Copyright />
          </div>
        )}
      </div>
    </div>
  );
}
Example #22
Source File: SidebarGroupList.tsx    From abrechnung with GNU Affero General Public License v3.0 5 votes vote down vote up
export default function SidebarGroupList({ group = null }) {
    const groups = useRecoilValue(groupList);
    const isGuest = useRecoilValue(isGuestUser);
    const [showGroupCreationModal, setShowGroupCreationModal] = useState(false);

    const openGroupCreateModal = () => {
        setShowGroupCreationModal(true);
    };

    const closeGroupCreateModal = (evt, reason) => {
        if (reason !== "backdropClick") {
            setShowGroupCreationModal(false);
        }
    };

    return (
        <>
            <List sx={{ pt: 0 }}>
                <ListItem sx={{ pt: 0, pb: 0 }}>
                    <ListItemText secondary="Groups" />
                </ListItem>
                {groups.map((it) => (
                    <ListItemLink key={it.id} to={`/groups/${it.id}`} selected={group && group.id === it.id}>
                        <ListItemText primary={it.name} />
                    </ListItemLink>
                ))}
                {!isGuest && (
                    <ListItem sx={{ padding: 0 }}>
                        <Grid container justifyContent="center">
                            <IconButton size="small" onClick={openGroupCreateModal}>
                                <Add />
                            </IconButton>
                        </Grid>
                    </ListItem>
                )}
            </List>
            {!isGuest && <GroupCreateModal show={showGroupCreationModal} onClose={closeGroupCreateModal} />}
        </>
    );
}
Example #23
Source File: SkeletonComponent.tsx    From firecms with MIT License 5 votes vote down vote up
function renderMap<T extends object>(property: MapProperty<T>, size: PreviewSize) {

    if (!property.properties)
        return <></>;

    let mapProperties: string[];
    if (!size) {
        mapProperties = Object.keys(property.properties);
    } else {
        if (property.previewProperties)
            mapProperties = property.previewProperties as string[];
        else
            mapProperties = Object.keys(property.properties).slice(0, 3);
    }

    if (size)
        return (
            <List>
                {mapProperties && mapProperties.map((key: string) => (
                    <ListItem key={property.title + key}>
                        <SkeletonComponent
                            property={(property.properties as any)[key]}
                            size={"small"}/>
                    </ListItem>
                ))}
            </List>
        );

    return (
        <Table size={"small"}>
            <TableBody>
                {mapProperties &&
                mapProperties.map((key, index) => {
                    return (
                        <TableRow key={`table_${property.title}_${index}`}
                                  sx={{
                                      "&:last-child th, &:last-child td": {
                                          borderBottom: 0
                                      }
                                  }}>
                            <TableCell key={`table-cell-title-${key}`}
                                       component="th">
                                <Skeleton variant="text"/>
                            </TableCell>
                            <TableCell key={`table-cell-${key}`} component="th">
                                <SkeletonComponent
                                    property={(property.properties as any)[key]}
                                    size={"small"}/>
                            </TableCell>
                        </TableRow>
                    );
                })}
            </TableBody>
        </Table>
    );

}
Example #24
Source File: StatsDialog.tsx    From GTAV-NativeDB with MIT License 5 votes vote down vote up
export default function StatsDialog({ open, onClose }: Props) {
  const stats = useStats()

  return (
    <Dialog open={open} onClose={onClose} fullWidth maxWidth="xs">
      <DialogTitle>
        Stats
      </DialogTitle>
      <List dense>
        <ListItem sx={{ px: 3 }} >
          <ListItemText 
            primary="Namespaces"
            secondary={stats.namespaces}
          />
        </ListItem>
        <ListItem sx={{ px: 3 }} >
          <ListItemText 
            primary="Natives"
            secondary={stats.natives}
          />
        </ListItem>
        <ListItem sx={{ px: 3 }} >
          <ListItemText 
            primary="Comments"
            secondary={stats.comments}
          />
        </ListItem>
        <ListItem sx={{ px: 3 }} >
          <ListItemText 
            primary="Known names"
            secondary={`${stats.knownNames.confirmed} (${stats.knownNames.total})`}
          />
        </ListItem>
      </List>
      <DialogActions>
        <Button onClick={onClose}>Close</Button>
      </DialogActions>
    </Dialog>
  )
}
Example #25
Source File: GroupInvite.tsx    From abrechnung with GNU Affero General Public License v3.0 5 votes vote down vote up
export default function GroupInvite() {
    const [group, setGroup] = useState(null);
    const [error, setError] = useState(null);
    const history = useHistory();
    const params = useParams();
    const inviteToken = params["inviteToken"];

    useTitle("Abrechnung - Join Group");

    useEffect(() => {
        fetchGroupPreview({ token: inviteToken })
            .then((res) => {
                setGroup(res);
                setError(null);
            })
            .catch((err) => {
                setError(err);
                setGroup(null);
            });
    }, [setGroup, setError, history, inviteToken]);

    const join = () => {
        joinGroup({ token: inviteToken })
            .then((value) => {
                setError(null);
                history.push("/");
            })
            .catch((err) => {
                setError(err);
            });
    };

    return (
        <MobilePaper>
            {error !== null ? (
                <Alert severity="error">{error}</Alert>
            ) : group === null ? (
                <Loading />
            ) : (
                <>
                    <Typography variant="h5">
                        <h4>You have been invited to group {group.name}</h4>
                    </Typography>
                    <List>
                        <ListItem>
                            <ListItemText primary="Name" secondary={group.name} />
                        </ListItem>
                        <ListItem>
                            <ListItemText primary="Description" secondary={group.description} />
                        </ListItem>
                        <ListItem>
                            <ListItemText primary="Created At" secondary={group.created_at} />
                        </ListItem>
                        <ListItem>
                            <ListItemText primary="Invitation Description" secondary={group.invite_description} />
                        </ListItem>
                        <ListItem>
                            <ListItemText primary="Invitation Valid Until" secondary={group.invite_valid_until} />
                        </ListItem>
                        <ListItem>
                            <ListItemText
                                primary="Invitation Single Use"
                                secondary={group.invite_single_use ? "yes" : "no"}
                            />
                        </ListItem>
                    </List>
                    <Grid container={true} sx={{ justifyContent: "center" }}>
                        <Button color="primary" onClick={join}>
                            Join
                        </Button>
                    </Grid>
                </>
            )}
        </MobilePaper>
    );
}
Example #26
Source File: NativeInfo.tsx    From GTAV-NativeDB with MIT License 4 votes vote down vote up
export default function NativeInfo() {
  const { native: nativeHash } = useParams<{ native?: string }>()
  const [usageNotFound, setUsageNotFound] = useState(false)
  const settings = useSettings()
  const native = useNative(nativeHash ?? '')
  const copyToClipboard = useCopyToClipboard()

  const onShare = useCallback(() => {
    copyToClipboard(createShareUrl(`/natives/${nativeHash}`))
  }, [copyToClipboard, nativeHash])

  const onUsageNotFound = useCallback(() => {
    setUsageNotFound(true)
  }, [setUsageNotFound])

  useEffect(() => {
    setUsageNotFound(false)
  }, [nativeHash])

  if (!nativeHash) {
    return (
      <Box sx={{ p: 2 }}>
        <NoNativeSelected />
      </Box>
    )
  }

  if  (!native) {
    return (
      <Box sx={{ p: 2 }}>
        <NativeNotFound nativeHash={nativeHash} />
      </Box>
    )
  }

  return (
    <Box sx={{ p: 2 }}>
      <Box sx={{ display: 'flex', alignItems: 'center', gap: 1, pb: 1 }}>
        <Tooltip title="Copy Link">
          <IconButton onClick={onShare} size="small" aria-label="copy link">
            <ShareIcon />
          </IconButton>
        </Tooltip>
        <Typography 
          sx={{ 
            textOverflow: 'ellipsis', 
            overflow: 'hidden' 
          }}
          variant="h5" 
          component="h1" 
        >
          {native.name}
        </Typography>
      </Box>
      <Stack spacing={2}>
        <Paper sx={{ p: 2 }}>
          <NativeDetails
            hash={native.hash}
            jhash={native.jhash}
            build={native.build}
            variant="body2"
          />
          <NativeDefinition
            name={native.name}
            params={native.params}
            returnType={native.returnType}
            variant="body2"
          />
        </Paper>
        {native.comment && (
          <div>
          <Typography variant="subtitle1" gutterBottom>
            Comment
          </Typography>
          <Paper sx={{ p: 2 }}>
            <NativeComment variant="body2">
              {native.comment}
            </NativeComment>
          </Paper>
        </div>
        )}
        {native.examples && !_.isEmpty(native.examples) && (
          <div>
            <Typography variant="subtitle1" gutterBottom>
              Examples
            </Typography>
            <Paper>
              <CodeExamples
                examples={native.examples}
              />
            </Paper>
          </div>
        )}
        {native.oldNames && (
          <div>
            <Typography variant="subtitle1" gutterBottom>
              Old name{native.oldNames?.length !== 1 ? 's' : ''}
            </Typography>
            <Paper>
              <List>
                {native.oldNames.map(oldName => (
                  <ListItem key={oldName} dense>
                    <ListItemText primary={oldName} />
                  </ListItem>
                ))}
              </List>
            </Paper>
          </div>
        )}
        {(!usageNotFound && _.includes(settings.sources, NativeSources.DottieDot)) && (
          <div>
            <Typography variant="subtitle1" gutterBottom>
              Script usage
            </Typography>
            <Paper>
              <NativeUsage 
                onNotFound={onUsageNotFound}
                nativeHash={nativeHash} 
              />
            </Paper>
          </div>
        )}
      </Stack>
    </Box>
  )
}
Example #27
Source File: PlayerList.tsx    From NekoMaid with MIT License 4 votes vote down vote up
PlayerInfo: React.FC<{ name?: string }> = React.memo(({ name }) => {
  const plugin = usePlugin()
  const globalData = useGlobalData()
  const [open, setOpen] = useState(false)
  const [info, setInfo] = useState<IPlayerInfo | undefined>()
  const refresh = () => plugin.emit('playerList:query', setInfo, name)
  useEffect(() => {
    setInfo(undefined)
    if (name) refresh()
  }, [name])

  return name && info
    ? <>
      <Divider />
      <List
        sx={{ width: '100%' }}
        component='nav'
        subheader={<ListSubheader component='div' sx={{ backgroundColor: 'inherit' }}>{lang.playerList.details}</ListSubheader>}
      >
        <ListItem>
          <ListItemIcon><AssignmentInd /></ListItemIcon>
          <ListItemText primary={globalData.onlineMode
            ? <Link underline='hover' rel='noopener' target='_blank' href={'https://namemc.com/profile/' + info.id}>{info.id}</Link>
            : info.id
          } />
        </ListItem>
        {!info.hasPlayedBefore && <ListItem>
          <ListItemIcon><ErrorOutline color='error' /></ListItemIcon>
          <ListItemText primary={lang.playerList.hasNotPlayed} />
        </ListItem>}
        {info.ban != null && <ListItem>
          <ListItemIcon><Block color='error' /></ListItemIcon>
          <ListItemText primary={lang.playerList.banned + (info.ban ? ': ' + info.ban : '')} />
        </ListItem>}
        {info.whitelisted && <ListItem>
          <ListItemIcon><Star color='warning' /></ListItemIcon>
          <ListItemText primary={lang.playerList.whitelisted} />
        </ListItem>}
        {info.isOP && <ListItem>
          <ListItemIcon><Security color='primary' /></ListItemIcon>
          <ListItemText primary={lang.playerList.op} />
          </ListItem>}
        {info.hasPlayedBefore && <>
            <ListItemButton onClick={() => setOpen(!open)}>
            <ListItemIcon><Equalizer /></ListItemIcon>
            <ListItemText primary={minecraft['gui.stats']} />
            {open ? <ExpandLess /> : <ExpandMore />}
          </ListItemButton>
          <Collapse in={open} timeout="auto" unmountOnExit>
            <List component='div' dense disablePadding>
              {[
                minecraft['stat.minecraft.play_time'] + ': ' + dayjs.duration(info.playTime / 20, 'seconds').humanize(),
                lang.playerList.firstPlay + ': ' + dayjs(info.firstPlay).fromNow(),
                lang.playerList.lastPlay + ': ' + dayjs(info.lastOnline).fromNow(),
                minecraft['stat.minecraft.leave_game'] + ': ' + info.quit,
                minecraft['stat.minecraft.deaths'] + ': ' + info.death,
                minecraft['stat.minecraft.player_kills'] + ': ' + info.playerKill,
                minecraft['stat.minecraft.mob_kills'] + ': ' + info.entityKill,
                lang.playerList.tnt + ': ' + info.tnt
              ].map((it, i) => <ListItem key={i} sx={{ pl: 4 }}>
                <ListItemIcon>{icons[i]}</ListItemIcon>
                <ListItemText primary={it} />
              </ListItem>)}
            </List>
          </Collapse>
        </>}
      </List>
      <CardActions disableSpacing sx={{ justifyContent: 'flex-end' }}>
        <Tooltip title={lang.playerList[info.whitelisted ? 'clickToRemoveWhitelist' : 'clickToAddWhitelist']}>
          <IconButton onClick={() => whitelist(name, plugin, refresh, !info.whitelisted)}>
            {info.whitelisted ? <Star color='warning' /> : <StarBorder />}
          </IconButton>
        </Tooltip>
        <Tooltip title={lang.playerList[info.ban == null ? 'clickToBan' : 'clickToPardon']}>
          <IconButton onClick={() => banPlayer(name, plugin, refresh, info.ban == null)}>
            <Block color={info.ban == null ? undefined : 'error'} />
          </IconButton>
        </Tooltip>
      </CardActions>
    </>
    : <></>
})
Example #28
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 #29
Source File: Worlds.tsx    From NekoMaid with MIT License 4 votes vote down vote up
Worlds: React.FC = () => {
  const plugin = usePlugin()
  const globalData = useGlobalData()
  const [worlds, setWorlds] = useState<World[]>([])
  const [selected, setSelected] = useState('')
  const [open, setOpen] = useState(false)
  const update = () => plugin.emit('worlds:fetch', (data: World[]) => {
    setWorlds(data)
    if (data.length) setSelected(old => data.some(it => it.id === old) ? old : '')
  })
  useEffect(() => {
    const offUpdate = plugin.on('worlds:update', update)
    update()
    return () => { offUpdate() }
  }, [])
  const sw = worlds.find(it => it.id === selected)
  const getSwitch = (name: string, configId = name) => sw
    ? <ListItem
      secondaryAction={<Switch disabled={!globalData.hasMultiverse} checked={(sw as any)[name]}
      onChange={e => {
        plugin.emit('worlds:set', sw.id, configId, e.target.checked.toString())
        success()
      }}
    />}><ListItemText primary={(lang.worlds as any)[name]} /></ListItem>
    : null

  return <Box sx={{ minHeight: '100%', py: 3 }}>
    <Toolbar />
    <Container maxWidth={false}>
      <Grid container spacing={3}>
        <Grid item lg={8} md={12} xl={9} xs={12}>
        <Card>
          <CardHeader title={lang.worlds.title} />
          <Divider />
          <Box sx={{ position: 'relative' }}>
            <TableContainer>
              <Table>
                <TableHead>
                  <TableRow>
                    <TableCell padding='checkbox' />
                    <TableCell>{lang.worlds.name}</TableCell>
                    {globalData.hasMultiverse && <TableCell>{lang.worlds.alias}</TableCell>}
                    <TableCell>{lang.worlds.players}</TableCell>
                    <TableCell>{lang.worlds.chunks}</TableCell>
                    <TableCell>{lang.worlds.entities}</TableCell>
                    <TableCell>{lang.worlds.tiles}</TableCell>
                    <TableCell>{lang.worlds.time}</TableCell>
                    <TableCell>{lang.worlds.weather}</TableCell>
                  </TableRow>
                </TableHead>
                <TableBody>
                  {worlds.map(it => <TableRow key={it.id}>
                    <TableCell padding='checkbox'><Checkbox checked={selected === it.id} onClick={() => setSelected(it.id)} /></TableCell>
                    <TableCell><Tooltip title={it.id}><span>{it.name}</span></Tooltip></TableCell>
                    {globalData.hasMultiverse && <TableCell>{it.alias}
                      <IconButton size='small' onClick={() => dialog(lang.inputValue, lang.worlds.alias).then(res => {
                        if (res == null) return
                        plugin.emit('worlds:set', it.id, 'alias', res)
                        success()
                      })}><Edit fontSize='small' /></IconButton>
                      </TableCell>}
                    <TableCell>{it.players}</TableCell>
                    <TableCell>{it.chunks}</TableCell>
                    <TableCell>{it.entities}</TableCell>
                    <TableCell>{it.tiles}</TableCell>
                    <TableCell><Countdown time={it.time} max={24000} interval={50} /></TableCell>
                    <TableCell><IconButton size='small' onClick={() => {
                      plugin.emit('worlds:weather', it.id)
                      success()
                    }}>
                      {React.createElement((it.weather === 1 ? WeatherRainy : it.weather === 2 ? WeatherLightningRainy : WbSunny) as any)}
                    </IconButton></TableCell>
                  </TableRow>)}
                </TableBody>
              </Table>
            </TableContainer>
          </Box>
        </Card>
        </Grid>
        <Grid item lg={4} md={6} xl={3} xs={12}>
          <Card>
            <CardHeader
              title={lang.operations}
              sx={{ position: 'relative' }}
              action={<Tooltip title={lang.worlds.save} placement='left'>
                <IconButton
                  size='small'
                  onClick={() => {
                    if (!sw) return
                    plugin.emit('worlds:save', sw.id)
                    success()
                  }}
                  sx={cardActionStyles}
                ><Save /></IconButton>
              </Tooltip>}
            />
            <Divider />
            <Box sx={{ position: 'relative' }}>
              {sw
                ? <List sx={{ width: '100%' }} component='nav'>
                  <ListItem secondaryAction={<ToggleButtonGroup
                    exclusive
                    color='primary'
                    size='small'
                    value={sw.difficulty}
                    onChange={(_, value) => {
                      plugin.emit('worlds:difficulty', sw.id, value)
                      success()
                    }}
                  >
                    {difficulties.map(it => <ToggleButton value={it.toUpperCase()} key={it}>{minecraft['options.difficulty.' + it]}</ToggleButton>)}
                  </ToggleButtonGroup>}><ListItemText primary={minecraft['options.difficulty']} /></ListItem>
                  <ListItem secondaryAction={<Switch checked={sw.pvp} onChange={e => {
                    plugin.emit('worlds:pvp', sw.id, e.target.checked)
                    success()
                  }} />}><ListItemText primary='PVP' /></ListItem>
                  {getSwitch('allowAnimals', 'spawning.animals.spawn')}
                  {getSwitch('allowMonsters', 'spawning.monsters.spawn')}
                  {globalData.hasMultiverse && <>
                    {getSwitch('allowFlight')}
                    {getSwitch('autoHeal')}
                    {getSwitch('hunger')}
                  </>}
                  <ListItem secondaryAction={globalData.canSetViewDistance
                    ? <IconButton
                      onClick={() => dialog({
                        content: lang.inputValue,
                        input: {
                          error: true,
                          type: 'number',
                          helperText: lang.invalidValue,
                          validator: (it: string) => /^\d+$/.test(it) && +it > 1 && +it < 33
                        }
                      }).then(res => {
                        if (!res) return
                        plugin.emit('worlds:viewDistance', sw.id, parseInt(res as any))
                        success()
                      })}
                    ><Edit /></IconButton>
                    : undefined}>
                    <ListItemText primary={lang.worlds.viewDistance + ': ' + sw.viewDistance} />
                  </ListItem>
                  <ListItem><ListItemText primary={minecraft['selectWorld.enterSeed']} secondary={sw.seed} /></ListItem>
                  <ListItemButton onClick={() => setOpen(!open)}>
                    <ListItemText primary={minecraft['selectWorld.gameRules']} />
                    {open ? <ExpandLess /> : <ExpandMore />}
                  </ListItemButton>
                  <Collapse in={open} timeout="auto" unmountOnExit>
                    <List component='div' dense disablePadding>
                      {sw.rules.map(([key, value]) => {
                        const isTrue = value === 'true'
                        const isBoolean = isTrue || value === 'false'
                        const isNumber = /^\d+$/.test(value)
                        return <ListItem
                          key={key}
                          sx={{ pl: 4 }}
                          secondaryAction={isBoolean
                            ? <Switch
                              checked={isTrue}
                              onChange={e => {
                                plugin.emit('worlds:rule', sw.id, key, e.target.checked.toString())
                                success()
                              }}
                            />
                            : <IconButton
                              onClick={() => dialog({
                                content: lang.inputValue,
                                input: isNumber
                                  ? {
                                      error: true,
                                      type: 'number',
                                      helperText: lang.invalidValue,
                                      validator: (it: string) => /^\d+$/.test(it)
                                    }
                                  : { }
                              }).then(res => {
                                if (res == null) return
                                plugin.emit('worlds:rule', sw.id, key, res)
                                success()
                              })}
                            ><Edit /></IconButton>}
                        >
                          <ListItemText primary={(minecraft['gamerule.' + key] || key) + (isBoolean ? '' : ': ' + value)} />
                        </ListItem>
                      })}
                    </List>
                  </Collapse>
                </List>
                : <CardContent><Empty /></CardContent>
              }
            </Box>
          </Card>
        </Grid>
      </Grid>
    </Container>
  </Box>
}