@mui/material#Drawer TypeScript Examples
The following examples show how to use
@mui/material#Drawer.
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: Header.tsx From fluttertemplates.dev with MIT License | 6 votes |
displayMobile = (isOpen: boolean, onToggle: any) => {
return (
<div>
<IconButton onClick={onToggle}>
<MenuRounded />
</IconButton>
<Drawer open={isOpen} anchor="bottom" onClose={onToggle}>
{commonNav.map((item) => (
<ListItem
key={item.props.href}
style={{
padding: 16,
justifyContent: "center",
}}
>
{item}
</ListItem>
))}
</Drawer>
</div>
);
}
Example #2
Source File: Layout.tsx From your_spotify with GNU General Public License v3.0 | 6 votes |
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 #3
Source File: LibraryOptions.tsx From Tachidesk-WebUI with Mozilla Public License 2.0 | 6 votes |
export default function LibraryOptions() {
const [filtersOpen, setFiltersOpen] = React.useState(false);
const { active } = useLibraryOptionsContext();
return (
<>
<IconButton
onClick={() => setFiltersOpen(!filtersOpen)}
color={active ? 'warning' : 'default'}
>
<FilterListIcon />
</IconButton>
<Drawer
anchor="bottom"
open={filtersOpen}
onClose={() => setFiltersOpen(false)}
PaperProps={{
style: {
maxWidth: 600, padding: '1em', marginLeft: 'auto', marginRight: 'auto',
},
}}
>
<Options />
</Drawer>
</>
);
}
Example #4
Source File: ItemViewer.tsx From NekoMaid with MIT License | 5 votes |
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)
}}
/> {`< ${lang.itemEditor.clone} >`} <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 #5
Source File: Menu.tsx From console with GNU Affero General Public License v3.0 | 5 votes |
Menu = ({ classes }: IMenuProps) => {
const dispatch = useDispatch();
const features = useSelector(selFeatures);
const sidebarOpen = useSelector(
(state: AppState) => state.system.sidebarOpen
);
const operatorMode = useSelector(selOpMode);
const logout = () => {
const deleteSession = () => {
clearSession();
dispatch(userLogged(false));
localStorage.setItem("userLoggedIn", "");
localStorage.setItem("redirect-path", "");
dispatch(resetSession());
history.push(`${baseUrl}login`);
};
api
.invoke("POST", `/api/v1/logout`)
.then(() => {
deleteSession();
})
.catch((err: ErrorResponseHandler) => {
console.log(err);
deleteSession();
});
};
const allowedMenuItems = validRoutes(features, operatorMode);
return (
<Drawer
id="app-menu"
variant="permanent"
className={clsx(classes.drawer, {
[classes.drawerOpen]: sidebarOpen,
[classes.drawerClose]: !sidebarOpen,
})}
classes={{
paper: clsx({
[classes.drawerOpen]: sidebarOpen,
[classes.drawerClose]: !sidebarOpen,
}),
}}
>
<MenuToggle
onToggle={(nextState) => {
dispatch(menuOpen(nextState));
}}
isOpen={sidebarOpen}
/>
<ConsoleMenuList
menuItems={allowedMenuItems}
isOpen={sidebarOpen}
onLogoutClick={logout}
/>
</Drawer>
);
}
Example #6
Source File: Header.tsx From genshin-optimizer with MIT License | 5 votes |
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 #7
Source File: SourceOptions.tsx From Tachidesk-WebUI with Mozilla Public License 2.0 | 5 votes |
export default function SourceOptions({
sourceFilter,
updateFilterValue,
resetFilterValue,
setTriggerUpdate,
setSearch,
update,
}: IFilters1) {
const [FilterOptions, setFilterOptions] = React.useState(false);
function handleReset() {
resetFilterValue(0);
setFilterOptions(false);
}
function handleSubmit() {
setTriggerUpdate(0);
setSearch(true);
setFilterOptions(false);
}
return (
<>
<Fab
sx={{ position: 'fixed', bottom: '2em', right: '3em' }}
onClick={() => setFilterOptions(!FilterOptions)}
variant="extended"
color="primary"
>
<FilterListIcon />
Filter
</Fab>
<Drawer
anchor="bottom"
open={FilterOptions}
onClose={() => setFilterOptions(false)}
PaperProps={{
style: {
maxWidth: 600, padding: '1em', marginLeft: 'auto', marginRight: 'auto',
},
}}
>
<Box sx={{ display: 'flex' }}>
<Button
onClick={handleReset}
>
Reset
</Button>
<Button
sx={{ marginLeft: 'auto' }}
variant="contained"
onClick={handleSubmit}
>
Submit
</Button>
</Box>
<Options
sourceFilter={sourceFilter}
updateFilterValue={updateFilterValue}
group={undefined}
update={update}
/>
</Drawer>
</>
);
}
Example #8
Source File: PageBuilderSidebar.tsx From Cromwell with MIT License | 5 votes |
render() {
const props = this.props;
props.getInst(this);
const block = this.selectedBlock;
const data = block?.getData();
if (data?.isConstant) return <></>;
const bType = data?.type;
const blockProps = props.createBlockProps(block);
let content;
if (bType === 'text') {
content = <TextBlockSidebar
{...blockProps}
/>
}
if (bType === 'plugin') {
content = <PluginBlockSidebar
{...blockProps}
/>
}
if (bType === 'container') {
content = <ContainerBlockSidebar
{...blockProps}
/>
}
if (bType === 'HTML') {
content = <HTMLBlockSidebar
{...blockProps}
/>
}
if (bType === 'image') {
content = <ImageBlockSidebar
{...blockProps}
/>
}
if (bType === 'gallery') {
content = <GalleryBlockSidebar
{...blockProps}
/>
}
if (bType === 'editor') {
content = <EditorBlockSidebar
{...blockProps}
/>
}
return (
<Drawer
classes={{ root: styles.sidebar, paper: styles.sidebarPaper }}
variant="persistent"
anchor={'left'}
open={!!this.selectedBlock}
onClick={(e) => e.stopPropagation()}
>
<Tooltip title="Close settings">
<IconButton
className={styles.sidebarCloseBtn}
onClick={this.handleClose}
>
<CloseIcon />
</IconButton>
</Tooltip>
<div className={styles.settings}>
{!!this.selectedBlock && content}
</div>
</Drawer>
);
}
Example #9
Source File: ChapterOptions.tsx From Tachidesk-WebUI with Mozilla Public License 2.0 | 4 votes |
export default function ChapterOptions(props: IProps) {
const { options, optionsDispatch } = props;
const [filtersOpen, setFiltersOpen] = useState(false);
const [tabNum, setTabNum] = useState(0);
const filterOptions = useCallback(
(value: NullAndUndefined<boolean>, name: string) => {
optionsDispatch({ type: 'filter', filterType: name.toLowerCase(), filterValue: value });
}, [],
);
return (
<>
<IconButton
onClick={() => setFiltersOpen(!filtersOpen)}
color={options.active ? 'warning' : 'default'}
>
<FilterListIcon />
</IconButton>
<Drawer
anchor="bottom"
open={filtersOpen}
onClose={() => setFiltersOpen(false)}
PaperProps={{
style: {
maxWidth: 600,
padding: '1em',
marginLeft: 'auto',
marginRight: 'auto',
minHeight: '150px',
},
}}
>
<Box>
<Tabs
key={tabNum}
value={tabNum}
variant="fullWidth"
onChange={(e, newTab) => setTabNum(newTab)}
indicatorColor="primary"
textColor="primary"
>
<Tab value={0} label="Filter" />
<Tab value={1} label="Sort" />
<Tab value={2} label="Display" />
</Tabs>
<TabPanel index={0} currentIndex={tabNum}>
<Box sx={{ display: 'flex', flexDirection: 'column', minHeight: '150px' }}>
<FormControlLabel control={<ThreeStateCheckbox name="Unread" checked={options.unread} onChange={filterOptions} />} label="Unread" />
<FormControlLabel control={<ThreeStateCheckbox name="Downloaded" checked={options.downloaded} onChange={filterOptions} />} label="Downloaded" />
<FormControlLabel control={<ThreeStateCheckbox name="Bookmarked" checked={options.bookmarked} onChange={filterOptions} />} label="Bookmarked" />
</Box>
</TabPanel>
<TabPanel index={1} currentIndex={tabNum}>
<Box sx={{ display: 'flex', flexDirection: 'column', minHeight: '150px' }}>
{
SortTab.map((item) => (
<Stack
direction="row"
alignItems="center"
spacing="2"
sx={{ py: 1, height: 42 }}
onClick={() => (item[0] !== options.sortBy
? optionsDispatch({ type: 'sortBy', sortBy: item[0] })
: optionsDispatch({ type: 'sortReverse' }))}
>
<Box sx={{ height: 24, width: 24 }}>
{
options.sortBy === item[0]
&& (options.reverse
? (<ArrowUpward color="primary" />) : (<ArrowDownward color="primary" />))
}
</Box>
<Typography>{item[1]}</Typography>
</Stack>
))
}
</Box>
</TabPanel>
<TabPanel index={2} currentIndex={tabNum}>
<Stack flexDirection="column" sx={{ minHeight: '150px' }}>
<RadioGroup name="chapter-title-display" onChange={() => optionsDispatch({ type: 'showChapterNumber' })} value={options.showChapterNumber}>
<FormControlLabel label="By Source Title" value="title" control={<Radio checked={!options.showChapterNumber} />} />
<FormControlLabel label="By Chapter Number" value="chapterNumber" control={<Radio checked={options.showChapterNumber} />} />
</RadioGroup>
</Stack>
</TabPanel>
</Box>
</Drawer>
</>
);
}
Example #10
Source File: Layout.tsx From abrechnung with GNU Affero General Public License v3.0 | 4 votes |
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 #11
Source File: index.tsx From ExpressLRS-Configurator with GNU General Public License v3.0 | 4 votes |
Sidebar: FunctionComponent = () => {
const location = useLocation();
const configuratorActive =
matchPath(location.pathname, '/configurator') !== null;
const backpackActive = matchPath(location.pathname, '/backpack') !== null;
// const settingsActive = matchPath(location.pathname, '/settings') !== null;
const logsActive = matchPath(location.pathname, '/logs') !== null;
const serialMonitorActive =
matchPath(location.pathname, '/serial-monitor') !== null;
const supportActive = matchPath(location.pathname, '/support') !== null;
const { appStatus } = useAppState();
const navigationEnabled = appStatus !== AppStatus.Busy;
return (
<Drawer sx={styles.drawer} variant="permanent">
<Toolbar />
<Divider />
<Box sx={styles.drawerContainer}>
<List>
<ListItem
component={Link}
to="/configurator"
selected={configuratorActive}
sx={styles.menuItem}
button
disabled={!navigationEnabled}
>
<ListItemIcon>
<BuildIcon />
</ListItemIcon>
<ListItemText primary="Configurator" />
</ListItem>
<ListItem
component={Link}
to="/backpack"
selected={backpackActive}
sx={styles.menuItem}
button
disabled={!navigationEnabled}
>
<ListItemIcon>
<BackpackIcon />
</ListItemIcon>
<ListItemText primary="Backpack" />
</ListItem>
{/* <ListItem */}
{/* component={Link} */}
{/* to="/settings" */}
{/* selected={settingsActive} */}
{/* sx={styles.menuItem} */}
{/* button */}
{/* > */}
{/* <ListItemIcon> */}
{/* <SettingsIcon /> */}
{/* </ListItemIcon> */}
{/* <ListItemText primary="Settings" /> */}
{/* </ListItem> */}
<ListItem
component={Link}
to="/logs"
selected={logsActive}
sx={styles.menuItem}
button
disabled={!navigationEnabled}
>
<ListItemIcon>
<ListIcon />
</ListItemIcon>
<ListItemText primary="Logs" />
</ListItem>
<ListItem
component={Link}
to="/serial-monitor"
selected={serialMonitorActive}
sx={styles.menuItem}
button
disabled={!navigationEnabled}
>
<ListItemIcon>
<DvrIcon />
</ListItemIcon>
<ListItemText primary="Serial Monitor" />
</ListItem>
<ListItem
component={Link}
to="/support"
selected={supportActive}
sx={styles.menuItem}
button
disabled={!navigationEnabled}
>
<ListItemIcon>
<HelpIcon />
</ListItemIcon>
<ListItemText primary="Support" />
</ListItem>
</List>
</Box>
</Drawer>
);
}
Example #12
Source File: SettingsDrawer.tsx From GTAV-NativeDB with MIT License | 4 votes |
export default function SettingsDrawer({ open, onClose }: SettingsDrawerProps) {
const smallDisplay = useIsSmallDisplay()
const settings = useSettings()
const dispatch = useDispatch()
const handleThemeChanged = useCallback((e: ReactMouseEvent<HTMLElement, MouseEvent>, value: any) => {
if (value !== null) {
dispatch(setTheme(value))
}
}, [dispatch])
const handleSourcesChanged = useCallback((e: ReactMouseEvent<HTMLElement, MouseEvent>, value: any) => {
dispatch(setSources(value))
}, [dispatch])
return (
<Drawer
anchor={smallDisplay ? 'bottom' : 'right' }
open={open}
onClose={onClose}
>
<Box
sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
width: smallDisplay ? undefined : 400,
p: 2
}}
>
<Typography
variant="h5"
>
Settings
</Typography>
<IconButton aria-label="close settings" onClick={onClose}>
<CloseIcon fontSize="medium" />
</IconButton>
</Box>
<Divider variant="fullWidth" />
<Box sx={{ p: 2 }}>
<Stack spacing={2}>
<div>
<Typography variant="body1" gutterBottom>
Theme
</Typography>
<ToggleButtonGroup
color="primary"
value={settings.theme}
onChange={handleThemeChanged}
exclusive
fullWidth
>
<ToggleButton value="light">
<LightIcon sx={{ mr: 1 }} />
Light
</ToggleButton>
<ToggleButton value="system">
<SystemIcon sx={{ mr: 1 }} />
System
</ToggleButton>
<ToggleButton value="dark">
<DarkIcon sx={{ mr: 1 }} />
Dark
</ToggleButton>
</ToggleButtonGroup>
</div>
<div>
<Typography variant="body1" gutterBottom>
Sources
</Typography>
<ToggleButtonGroup
color="primary"
value={settings.sources}
onChange={handleSourcesChanged}
fullWidth
>
<ToggleButton value="alloc8or" disabled>
Alloc8or
</ToggleButton>
<ToggleButton value="dottiedot">
DottieDot
</ToggleButton>
<ToggleButton value="fivem">
FiveM
</ToggleButton>
</ToggleButtonGroup>
</div>
</Stack>
</Box>
</Drawer>
)
}
Example #13
Source File: CommentItemModule.tsx From bouncecode-cms with GNU General Public License v3.0 | 4 votes |
function CommentItemModule({post, comment}: ICommentItemModule) {
const [moreVert, setMoreVert] = React.useState(null);
const openMoreVert = Boolean(moreVert);
const toggleMoreVert = open => {
return event => {
if (open) {
setMoreVert(event.currentTarget);
} else {
setMoreVert(null);
}
};
};
const [commentDrawer, setCommentDrawer] = React.useState(null);
const toggleCommentDrawer = open => {
return event => {
if (
event.type === 'keydown' &&
(event.key === 'Tab' || event.key === 'Shift')
) {
return;
}
setCommentDrawer(open);
};
};
const [
emotionMutation,
{loading: emotionLoading},
] = useCommentEmotionMutation();
const [
undoEmotionMutation,
{loading: undoEmotionLoading},
] = useCommentEmotionUndoMutation();
const updateEmotion = emotion => {
return () => {
console.log(myEmotion);
console.log(emotion);
if (myEmotion === emotion.toLowerCase()) {
undoEmotionMutation({
variables: {
where: {
id: comment.id,
},
},
refetchQueries: [
{
query: CommentMyEmotionDocument,
variables: {where: {id: comment.id}},
},
],
});
} else {
emotionMutation({
variables: {
where: {
id: comment.id,
},
data: {emotion},
},
refetchQueries: [
{
query: CommentMyEmotionDocument,
variables: {where: {id: comment.id}},
},
],
});
}
};
};
const {
data: myEmotionData,
loading: myEmotionLoading,
} = useCommentMyEmotionQuery({
variables: {where: {id: comment.id}},
});
const myEmotion = myEmotionData?.commentMyEmotion?.emotion;
return (
<Grid container direction="column" spacing={1}>
<Grid item>
<Grid container spacing={2}>
<Grid item>
<Avatar></Avatar>
</Grid>
<Grid item xs>
<Grid container direction="column" spacing={1}>
<Grid item>
<Grid container spacing={2} alignItems="center">
<Grid item>
<Typography variant="body2">
{comment.user.email}
</Typography>
</Grid>
<Grid item>
<Typography variant="caption">
{formatDistance(
new Date(comment.createdDate),
new Date(),
{addSuffix: true},
)}
</Typography>
</Grid>
</Grid>
</Grid>
<Grid item>
<Typography variant="body1">{comment.text}</Typography>
</Grid>
<Grid
container
justifyContent="space-between"
alignItems="center">
<Grid item>
<Grid container alignItems="center">
<Grid item>
<Button
variant="text"
size="small"
startIcon={<ThumbUpOutlined />}
onClick={updateEmotion('LIKE')}
disabled={
myEmotionLoading ||
emotionLoading ||
undoEmotionLoading
}>
{comment.like || ''}
</Button>
</Grid>
<Grid item>
<Button
variant="text"
size="small"
startIcon={<ThumbDownOutlined />}
onClick={updateEmotion('UNLIKE')}
disabled={
myEmotionLoading ||
emotionLoading ||
undoEmotionLoading
}>
{comment.unlike || ''}
</Button>
</Grid>
{post ? (
<Grid item>
<Button
variant="text"
size="small"
onClick={toggleCommentDrawer(true)}
disabled>
답글
</Button>
<Drawer
anchor="bottom"
open={commentDrawer}
onClose={toggleCommentDrawer(false)}>
<Container maxWidth="md">
<Box pt={2} pb={2}>
<CommentCreateFormModule />
</Box>
</Container>
</Drawer>
</Grid>
) : (
undefined
)}
</Grid>
</Grid>
<Grid item>
<IconButton onClick={toggleMoreVert(true)} disabled>
<MoreVert fontSize="small" />
</IconButton>
<Menu
anchorEl={moreVert}
open={openMoreVert}
onClose={toggleMoreVert(false)}>
<MenuItem
// selected={option === 'Pyxis'}
onClick={toggleMoreVert(false)}>
<ListItemIcon>
<AssistantPhotoOutlined />
</ListItemIcon>
<Typography variant="inherit">ì‹ ê³ </Typography>
</MenuItem>
</Menu>
</Grid>
</Grid>
{/* {post ? (
<Grid item>
<Grid container direction="column" spacing={2}>
<Grid item>
<Button
variant="text"
size="small"
startIcon={<KeyboardArrowDown />}>
답글 1개 보기
</Button>
</Grid>
<Grid item>
<CommentItemModule comment />
</Grid>
</Grid>
</Grid>
) : (
undefined
)} */}
</Grid>
</Grid>
</Grid>
</Grid>
</Grid>
);
}
Example #14
Source File: Navbar.tsx From website with Apache License 2.0 | 4 votes |
Navbar = ({
rootPageHasAnimation,
}: {
rootPageHasAnimation?: boolean;
}) => {
const [drawerState, setDrawerState] = useState(false);
const [toggleMoreIcon, setToggleMoreIcon] = useState(false);
const [initialPageWidth, setInitialPageWidth] = useState(0);
const theme = useTheme();
const ref = useRef<HTMLButtonElement | null>(null);
/* In the future we should come up with a different solution that doesn't
rerender this component, its not much of a problem right now but later it
*may* become a problem
- Cody
*/
const scrollPos = useScrollPosition(15);
const toggleDrawer = useCallback(
(open: boolean = false) => setDrawerState(open ?? !drawerState),
[drawerState],
);
useEffect(() => {
// This is used for checking if its mobile or not
setInitialPageWidth(window.innerWidth);
}, []);
return (
<Wrapper>
<SkipNavLink
contentId="skipNav"
style={{
background: theme.background.backgroundColor,
color:
theme.type === "dark"
? theme.text.textColorExtremelyLight
: theme.text.textColorDark,
zIndex: 9999999,
}}
/>
<Drawer
anchor="left"
open={drawerState}
onClose={() => toggleDrawer(false)}
>
<DrawerLogoContainer>
<DrawerLogo
alt="dahliaOS logo"
src={
theme.type === "dark"
? "/images/logos/logo-white.png"
: "/images/logos/logo-color.png"
}
/>
</DrawerLogoContainer>
<Container>
<Link href="/#features">Features</Link>
<Link href="/#download">Download</Link>
<Link href="mailto:[email protected]">Contact</Link>
<Link href="https://github.com/orgs/dahliaos/people" target="_blank">
Developers
</Link>
<Link href="https://docs.dahliaOS.io">Documentation</Link>
<Divider />
<Category>Find us on</Category>
<Link href="/discord" target="_blank">
Discord
</Link>
<Link href="/github" target="_blank">
GitHub
</Link>
<Link href="/reddit" target="_blank">
Reddit
</Link>
<Link href="/telegram" target="_blank">
Telegram
</Link>
<Link href="/facebook" target="_blank">
Facebook
</Link>
<Link href="/instagram" target="_blank">
Instagram
</Link>
<Link href="/twitter" target="_blank">
Twitter
</Link>
<Divider />
<Category>For developers</Category>
<Link href="/github">Source Code</Link>
<Link href="/discord">Join Our Team</Link>
</Container>
</Drawer>
<StyledAppBar
rootPageHasAnimation={
initialPageWidth < 1075 ? false : rootPageHasAnimation
}
position="fixed"
scrollPos={scrollPos}
>
<StyledToolbar scrollPos={scrollPos}>
<IconButton
edge="start"
color="inherit"
aria-label="menu"
onClick={() => toggleDrawer(true)}
>
<MenuIcon
style={
theme.type === "dark"
? undefined
: { color: theme.text.textColorDark }
}
/>
</IconButton>
<AppBarLogoLinkContainer href="/">
<AppBarLogo
alt="dahliaOS logo"
src={
theme.type === "dark"
? "/images/logos/logo-white.png"
: "/images/logos/logo-color.png"
}
draggable={false}
/>
</AppBarLogoLinkContainer>
<DesktopNav>
<AppBarLink href="/#features">Features</AppBarLink>
<AppBarLink href="/#download">Download</AppBarLink>
<AppBarLink href="https://web.dahliaOS.io" target="_blank">
Demo
</AppBarLink>
<AppBarLink
href="https://github.com/orgs/dahliaos/people"
target="_blank"
>
Developers
</AppBarLink>
<AppBarLink href="https://docs.dahliaOS.io">
Documentation
</AppBarLink>
<IconButton
ref={ref}
aria-label="nav-more"
aria-haspopup="true"
onClick={() => setToggleMoreIcon(true)}
>
<MoreVert style={{ color: theme.text.textColorLight }} />
</IconButton>
<Menu
open={toggleMoreIcon}
onClose={() => setToggleMoreIcon(false)}
anchorOrigin={{ vertical: "bottom", horizontal: "left" }}
anchorEl={ref.current}
keepMounted
>
<MenuItem>
<MenuLink href="/github" target="_blank">
Source Code
</MenuLink>
</MenuItem>
<MenuItem disabled>Screenshots</MenuItem>
</Menu>
</DesktopNav>
</StyledToolbar>
</StyledAppBar>
<SkipNavContent id="skipNav" />
</Wrapper>
);
}
Example #15
Source File: ThemeEditActions.tsx From Cromwell with MIT License | 4 votes |
render() {
const { isSidebarOpen, themeConfig } = this.state;
const editingPageConfig = this.getThemeEditor().getEditingPageConfig();
const pageInfos = this.state.pageInfos?.map(p => {
if (p.id === editingPageConfig?.id) {
return Object.assign({}, p, editingPageConfig);
}
return p;
});
const defaultPages = pageInfos?.filter(p => !p.isVirtual);
const customPages = pageInfos?.filter(p => p.isVirtual);
if (!themeConfig) return null;
return (<>
<div className={styles.ThemeEditActions} ref={this.wrapperRef}>
<div>
<Tooltip title="Pages">
<IconButton
onClick={this.handlePagesToggle}
>
<PagesIcon />
</IconButton>
</Tooltip>
<Tooltip title="Page meta info">
<IconButton
onClick={this.handleMetaToggle}
>
<InfoOutlinedIcon />
</IconButton>
</Tooltip>
<Popover open={this.state.pageMetaOpen}
anchorEl={this.wrapperRef.current}
style={{ zIndex: 9999 }}
onClose={this.handleMetaToggle}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'left',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'left',
}}
>
<PageSettings
themeConfig={themeConfig}
pageConfig={editingPageConfig}
handlePageInfoChange={this.handlePageInfoChange}
/>
</Popover>
<Tooltip title="Undo">
<IconButton
ref={this.undoBtnRef}
onClick={this.undoModification}
>
<UndoIcon />
</IconButton>
</Tooltip>
<Tooltip title="Redo">
<IconButton
ref={this.redoBtnRef}
onClick={this.redoModification}
>
<RedoIcon />
</IconButton>
</Tooltip>
</div>
<div className={styles.bottomBlock} >
<Tooltip title="Options">
<IconButton
onClick={this.handleOptionsToggle}
className={styles.actionBtn}
aria-label="Options"
ref={this.optionsAnchorEl}
>
<MoreVertOutlinedIcon />
</IconButton>
</Tooltip>
<Popover open={this.state.pageOptionsOpen}
anchorEl={this.optionsAnchorEl.current}
style={{ zIndex: 9999 }}
onClose={this.handleOptionsToggle}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'left',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'left',
}}
>
<div>
<MenuItem
onClick={this.handleResetCurrentPage} className={styles.optionsItem}>
<SettingsBackupRestoreIcon />
<p>Reset to default</p>
</MenuItem>
<MenuItem
disabled={!editingPageConfig?.isVirtual}
onClick={this.handleDeleteCurrentPage} className={styles.optionsItem}>
<DeleteForeverIcon />
<p>Delete page</p>
</MenuItem>
</div>
</Popover>
<Button variant="contained" color="primary"
className={styles.saveBtn}
size="small"
onClick={this.handleSaveEditingPage}
>Save</Button>
</div>
</div>
<LoadingStatus isActive={this.state.loadingStatus} />
<Drawer
classes={{ paper: styles.sidebarPaper }}
variant="persistent"
anchor={'left'}
open={isSidebarOpen}
onClick={(e) => e.stopPropagation()}
>
<div className={styles.sidebar}>
<div className={styles.pageList} key="_2_">
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<p className={styles.pageListHeader}>Theme pages</p>
<div style={{ display: 'flex', alignItems: 'center' }}>
<Tooltip title="Theme settings">
<IconButton
className={styles.sidebarCloseBtn}
onClick={this.handleThemeSettingsToggle}>
<SettingsIcon />
</IconButton>
</Tooltip>
<Tooltip title="Close">
<IconButton
className={styles.sidebarCloseBtn}
onClick={this.handlePagesToggle}>
<CloseIcon />
</IconButton>
</Tooltip>
</div>
</div>
{defaultPages?.map(p => (
<PageListItem
activePage={editingPageConfig}
key={p.id + p.route}
page={p}
handleOpenPage={this.handleOpenPage}
handleDeletePage={this.handleDeletePage}
onPreviewChange={this.handlePreviewChange(p)}
/>
))}
</div>
{customPages && (
<div className={styles.pageList} key="_3_">
<p className={styles.pageListHeader}>Custom pages</p>
{customPages.map(p => (
<PageListItem
activePage={editingPageConfig}
key={p.id + p.route}
page={p}
handleOpenPage={this.handleOpenPage}
handleDeletePage={this.handleDeletePage}
onPreviewChange={this.handlePreviewChange(p)}
/>
))}
<Tooltip title="Add a new page">
<MenuItem
className={clsx(styles.addPageItem, styles.navBarItem)}
>
<IconButton
aria-label="add page"
onClick={this.handleAddCustomPage}
>
<AddCircleIcon />
</IconButton>
</MenuItem>
</Tooltip>
</div>
)}
</div>
<Modal
open={this.state?.themeSettingsOpen}
blurSelector="#root"
className={commonStyles.center}
onClose={this.handleThemeSettingsToggle}
>
<div className={styles.themeSettings}>
<div className={styles.themeSettingsItem}
style={{ justifyContent: 'space-between' }}
>
<h3 className={styles.themeSettingsTitle}>Theme settings</h3>
<IconButton
onClick={this.handleThemeSettingsToggle}>
<CloseIcon />
</IconButton>
</div>
<div className={styles.themeSettingsItem}>
<ModeSwitch
value={this.state?.themePalette?.mode ?? 'light'}
onToggle={() => {
this.changedPalette = true;
this.setState(prev => {
const isLight = prev.themePalette?.mode !== 'dark';
return {
themePalette: Object.assign({}, prev.themePalette, {
mode: isLight ? 'dark' : 'light'
})
}
});
}}
/>
</div>
<div className={styles.themeSettingsItem}>
<ColorPicker
label="Primary color"
value={this.state.themePalette?.primaryColor}
onChange={(color) => {
this.changedPalette = true;
this.setState(prev => {
return {
themePalette: Object.assign({}, prev.themePalette, {
primaryColor: color,
})
}
})
}}
/>
</div>
<div className={styles.themeSettingsItem}>
<ColorPicker
label="Secondary color"
value={this.state.themePalette?.secondaryColor}
onChange={(color) => {
this.changedPalette = true;
this.setState(prev => {
return {
themePalette: Object.assign({}, prev.themePalette, {
secondaryColor: color,
})
}
})
}}
/>
</div>
</div>
</Modal>
</Drawer>
</>)
}
Example #16
Source File: Header.tsx From metaplex with Apache License 2.0 | 4 votes |
Header = ({ narrow }: { narrow: boolean }) => {
const navs = [
{
href: `/entanglement/`,
innerNarrow: 'About',
inner: <HomeIcon />,
},
{
href: `/entanglement/create`,
inner: 'Create',
},
{
href: `/entanglement/show`,
inner: 'Show',
},
{
href: `/entanglement/swap`,
inner: 'Swap',
},
{
href: `/entanglement/search`,
inner: 'Search',
},
{
href: `/entanglement/wizard`,
inner: 'Wizard',
},
];
const [drawerOpen, setDrawerOpen] = React.useState(false);
const toggleDrawer = open => event => {
if (
event.type === 'keydown' &&
(event.key === 'Tab' || event.key === 'Shift')
) {
return;
}
setDrawerOpen(open);
};
return (
<Box
sx={{
height: '52px',
display: 'flex',
bgcolor: 'action.disabledBackground',
overflow: 'auto',
}}
>
{narrow ? (
<React.Fragment>
<Button onClick={toggleDrawer(true)}>
<MenuIcon />
</Button>
<Drawer open={drawerOpen} onClose={toggleDrawer(false)}>
<Box
sx={{ width: 250 }}
role="presentation"
onClick={toggleDrawer(false)}
onKeyDown={toggleDrawer(false)}
>
<List>
<ListItem>
<ListItemText
primary="Token Entangler"
primaryTypographyProps={{
fontSize: '1.2rem',
fontWeight: 'medium',
letterSpacing: 0,
}}
/>
</ListItem>
<Divider />
{navs.map((nav, idx) => {
return (
<Link to={nav.href} key={idx} style={{ color: 'inherit' }}>
<ListItemButton>
{nav.innerNarrow || nav.inner}
</ListItemButton>
</Link>
);
})}
</List>
</Box>
</Drawer>
</React.Fragment>
) : (
<Stack
direction="row"
spacing={2}
sx={{
display: 'flex',
justifyContent: 'flex-start',
alignItems: 'center',
marginLeft: '36px',
}}
>
{navs.map((nav, idx) => {
return (
<Link to={nav.href} key={idx}>
<Button variant="outlined" style={{ minWidth: 0 }}>
{nav.inner}
</Button>
</Link>
);
})}
</Stack>
)}
<Box sx={{ flexGrow: 1, minWidth: '36px' }}></Box>
<Settings narrow={narrow} />
</Box>
);
}
Example #17
Source File: index.tsx From metaplex with Apache License 2.0 | 4 votes |
Settings = ({ narrow }: { narrow: boolean }) => {
const { disconnect, publicKey } = useWallet();
const { setEndpoint, env, endpoint } = useConnectionConfig();
const { setVisible } = useWalletModal();
const open = React.useCallback(() => setVisible(true), [setVisible]);
const { setModal } = useModal();
const theme = useTheme();
const colorModeCtx = useColorMode();
const handleConnect = React.useCallback(() => {
setModal(ModalEnum.WALLET);
setVisible(true);
}, [setModal, setVisible]);
const connectedActions = [
{
click: async () => {
if (publicKey) {
await navigator.clipboard.writeText(publicKey.toBase58());
notify({
message: 'Wallet update',
description: 'Address copied to clipboard',
});
}
},
innerNarrow: () =>
`Copy Address (${publicKey && shortenAddress(publicKey.toBase58())})`,
inner: function ConnectedWalletCopyC() {
return (
<React.Fragment>
<CopyOutlined />
{publicKey && shortenAddress(publicKey.toBase58())}
</React.Fragment>
);
},
},
{
click: open,
inner: () => 'Change\u00A0Wallet',
},
{
click: () => disconnect().catch(),
inner: () => `Disconnect\u00A0(${env})`,
expandedExtra: {
// these are interepreted as props. TODO: specific types
color: 'error' as any,
variant: 'contained' as any,
},
},
];
const [drawerOpen, setDrawerOpen] = React.useState(false);
const [envCollapseOpen, setEnvCollapseOpen] = React.useState(false);
const hackySkipSet = 'hackySkipSet';
const toggleDrawer = open => event => {
if (
event.type === 'keydown' &&
(event.key === 'Tab' || event.key === 'Shift')
) {
return;
}
if (event.target.classList.contains(hackySkipSet)) {
return;
}
setDrawerOpen(open);
};
const drawerC = inner => {
return (
<React.Fragment>
<Button onClick={toggleDrawer(true)}>
<AccountBalanceWalletIcon />
</Button>
<Drawer anchor="right" open={drawerOpen} onClose={toggleDrawer(false)}>
<Box
sx={{ width: 250 }}
role="presentation"
onClick={toggleDrawer(false)}
onKeyDown={toggleDrawer(false)}
>
{inner}
</Box>
</Drawer>
</React.Fragment>
);
};
const themeSwitch = (
<Button
sx={{ ml: 1 }}
onClick={colorModeCtx.toggleColorMode}
color="inherit"
>
{theme.palette.mode === 'dark' ? (
<Brightness7Icon />
) : (
<Brightness4Icon />
)}
</Button>
);
if (narrow) {
const listHead = (
<ListItem>
<ListItemText
primary="Wallet"
primaryTypographyProps={{
fontSize: '1.2rem',
fontWeight: 'medium',
letterSpacing: 0,
}}
/>
</ListItem>
);
return (
<React.Fragment>
{!publicKey &&
drawerC(
<List>
{listHead}
<Divider />
<ListItemButton
onClick={() => setEnvCollapseOpen(!envCollapseOpen)}
className={hackySkipSet}
>
Change Network
{envCollapseOpen ? <ExpandLess /> : <ExpandMore />}
</ListItemButton>
<Collapse in={envCollapseOpen} timeout="auto" unmountOnExit>
<List component="div" disablePadding>
{ENDPOINTS.map(p => (
<ListItemButton
selected={endpoint === p.endpoint}
onClick={() => setEndpoint(p.endpoint)}
key={p.name}
sx={{ pl: 4 }}
className={hackySkipSet}
>
{p.name}
</ListItemButton>
))}
</List>
</Collapse>
<ListItemButton onClick={handleConnect}>Connect</ListItemButton>
</List>,
)}
{publicKey &&
drawerC(
<List>
{listHead}
<Divider />
{connectedActions.map((a, idx) => {
return (
<ListItemButton onClick={a.click} key={idx}>
{(a.innerNarrow && a.innerNarrow()) || a.inner()}
</ListItemButton>
);
})}
</List>,
)}
{themeSwitch}
</React.Fragment>
);
} else {
return (
<Stack
direction="row"
spacing={2}
sx={{
display: 'flex',
justifyContent: 'flex-end',
alignItems: 'center',
marginRight: '36px',
}}
>
{!publicKey && (
<React.Fragment>
<FormControl variant="standard" style={{ minWidth: '10ch' }}>
<Select
id="connected-env-select"
onChange={e => {
setEndpoint(e.target.value);
}}
value={endpoint}
>
{ENDPOINTS.map(({ name, endpoint }) => (
<MenuItem key={name} value={endpoint}>
{name}
</MenuItem>
))}
</Select>
</FormControl>
<Link underline="none">
<Button variant="contained" onClick={handleConnect}>
Connect
</Button>
</Link>
</React.Fragment>
)}
{publicKey &&
connectedActions.map((a, idx) => {
return (
<Button
key={idx}
variant="outlined"
onClick={a.click}
{...a.expandedExtra}
>
{a.inner()}
</Button>
);
})}
{themeSwitch}
</Stack>
);
}
}
Example #18
Source File: App.tsx From NekoMaid with MIT License | 4 votes |
App: React.FC<{ darkMode: boolean, setDarkMode: (a: boolean) => void }> = React.memo(({ darkMode, setDarkMode }) => {
const loc = useLocation()
const his = useHistory()
const pluginRef = useRef<Plugin | null>(null)
const [mobileOpen, setMobileOpen] = useState(false)
const [globalItemsOpen, setGlobalItemsOpen] = useState(false)
const [globalData, setGlobalData] = useState<GlobalInfo>({ } as any)
const [drawerWidth, setDrawerWidth] = useState(240)
const updateF = useState(0)[1]
const create = useMemo(() => {
const io = socketIO(origin!, { path: pathname!, auth: { token } })
const map: Record<string, Plugin> = { }
const fn = (window as any).__NekoMaidAPICreate = (name: string) => map[name] || (map[name] = new Plugin(io, name))
const nekoMaid = pluginRef.current = fn('NekoMaid')
io.on('globalData', (data: GlobalInfo) => {
const his: ServerRecord[] = JSON.parse(localStorage.getItem('NekoMaid:servers') || '[]')
const curAddress = address!.replace('http://', '') + '?' + token
let cur = his.find(it => it.address === curAddress)
if (!cur) his.push((cur = { address: curAddress, time: 0 }))
cur.time = Date.now()
cur.icon = data.icon
const arr = loc.pathname.split('/')
if (!sent && arr.length > 2) io.emit('switchPage', arr[1], arr[2])
sent = true
localStorage.setItem('NekoMaid:servers', JSON.stringify(his))
new Set(Object.values(data.plugins).flat()).forEach(loadPlugin)
setGlobalData(data)
pages = { }
initPages(nekoMaid)
onGlobalDataReceived(nekoMaid, data)
update(Math.random())
if (process.env.NODE_ENV !== 'development' && data.pluginVersion !== version) toast(lang.pluginUpdate, 'warning')
}).on('!', () => {
io.close()
dialog({ content: lang.wrongToken, cancelButton: false })
// eslint-disable-next-line no-return-assign
.then(() => (location.search = location.pathname = location.hash = ''))
}).on('reconnect', () => {
toast(lang.reconnect)
setTimeout(() => location.reload(), 5000)
}).on('disconnect', () => failed(lang.disconnected)).on('connect_error', () => failed(lang.failedToConnect))
return fn
}, [])
useEffect(() => { if (!loc.pathname || loc.pathname === '/') his.replace('/NekoMaid/dashboard') }, [loc.pathname])
useEffect(() => {
update = updateF
return () => { update = undefined as any }
}, [])
const handleDrawerToggle = () => {
setDrawerWidth(240)
setMobileOpen(!mobileOpen)
}
const isExpand = drawerWidth === 240
const routes: JSX.Element[] = []
const mapToItem = (name: string, it: Page) => {
const path = Array.isArray(it.path) ? it.path[0] : it.path
const key = '/' + name + '/' + path
routes.push(<pluginCtx.Provider key={key} value={create(name)}>
<Route
path={Array.isArray(it.path) ? it.path.map(it => '/' + name + '/' + it) : key}
component={it.component}
strict={it.strict}
exact={it.exact}
sensitive={it.sensitive}
/>
</pluginCtx.Provider>)
const icon = <ListItemIcon><pluginCtx.Provider value={create(name)}>
{(typeof it.icon === 'function' ? <it.icon /> : it.icon) || <Build />}
</pluginCtx.Provider></ListItemIcon>
return it.title
? <NavLink key={key} to={'/' + name + '/' + (it.url || path)} activeClassName='actived'>
<ListItem button>
{isExpand ? icon : <Tooltip title={it.title} placement='right'>{icon}</Tooltip>}
{isExpand && <ListItemText primary={it.title} />}
</ListItem>
</NavLink>
: undefined
}
const singlePages: JSX.Element[] = []
const multiPagesPages: Array<JSX.Element | JSX.Element[]> = []
let index = 0
for (const name in pages) {
if (pages[name].length === 1) {
const elm = mapToItem(name, pages[name][0])
if (elm) singlePages.push(elm)
} else {
if (multiPagesPages.length) multiPagesPages.push(<Divider key={index++} />)
multiPagesPages.push(pages[name].map(it => mapToItem(name, it)!).filter(Boolean))
}
}
if (singlePages.length) multiPagesPages.push(<Divider key={index++} />, singlePages)
const drawer = <Box sx={{ overflowX: 'hidden' }}>
<Toolbar />
<Divider sx={{ display: { sm: 'none', xs: 'block' } }} />
<List sx={{
'& a': {
color: 'inherit',
textDecoration: 'inherit'
},
'& .actived > div': {
fontWeight: 'bold',
color: theme => theme.palette.primary.main,
backgroundColor: theme => alpha(theme.palette.primary.main, theme.palette.action.selectedOpacity) + '!important',
'& svg': { color: theme => theme.palette.primary.main + '!important' }
}
}}>{multiPagesPages.flat()}</List>
</Box>
return <Box sx={{ display: 'flex' }}>
<CssBaseline />
<AppBar position='fixed' sx={{ zIndex: theme => theme.zIndex.drawer + 1 }}>
<Toolbar>
<IconButton
color='inherit'
edge='start'
onClick={() => setDrawerWidth(isExpand ? 57 : 240)}
sx={{ mr: 1, display: { sm: 'inline-flex', xs: 'none' } }}
><ChevronLeft sx={{ transition: '.3s', transform: isExpand ? undefined : 'rotate(-180deg)' }} /></IconButton>
<IconButton color='inherit' edge='start' onClick={handleDrawerToggle} sx={{ mr: 2, display: { sm: 'none' } }}><Menu /></IconButton>
<Typography variant='h3' noWrap component='div' sx={{ flexGrow: 1 }}>NekoMaid</Typography>
{globalData.hasNBTAPI && <IconButton
color='inherit'
onClick={() => setGlobalItemsOpen(!globalItemsOpen)}
onDragOver={() => setGlobalItemsOpen(true)}
><Backpack /></IconButton>}
<LanguageSwitch />
<IconButton color='inherit' edge='end' onClick={() => setDarkMode(!darkMode)}>
{darkMode ? <Brightness7 /> : <Brightness4 />}
</IconButton>
</Toolbar>
</AppBar>
<globalCtx.Provider value={globalData}>
<Box component='nav' sx={{ width: { sm: drawerWidth }, flexShrink: { sm: 0 } }}>
<Drawer
variant='temporary'
open={mobileOpen}
onClose={handleDrawerToggle}
ModalProps={{ keepMounted: true }}
sx={{
display: { xs: 'block', sm: 'none' },
'& .MuiDrawer-paper': {
boxSizing: 'border-box',
width: drawerWidth,
backgroundImage: theme => theme.palette.mode === 'dark'
? 'linear-gradient(rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.05))'
: undefined
}
}}
>
{drawer}
</Drawer>
<Drawer
open
variant='permanent'
sx={{
display: { xs: 'none', sm: 'block' },
'& .MuiDrawer-paper': {
boxSizing: 'border-box',
width: drawerWidth,
transition: 'width .3s',
backgroundImage: theme => theme.palette.mode === 'dark' ? 'linear-gradient(rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.05))' : undefined
}
}}
>
{drawer}
</Drawer>
</Box>
<Box component='main' sx={{ flexGrow: 1, width: '100vw' }}>
<drawerWidthCtx.Provider value={drawerWidth}>{routes}</drawerWidthCtx.Provider>
{globalData.hasNBTAPI && <pluginCtx.Provider value={pluginRef.current}>
<GlobalItems open={globalItemsOpen} onClose={() => setGlobalItemsOpen(false)} />
</pluginCtx.Provider>}
</Box>
</globalCtx.Provider>
</Box>
})
Example #19
Source File: ProductList.tsx From Cromwell with MIT License | 4 votes |
export default function ProductTable() {
const client = getGraphQLClient();
const [showFilter, setShowFilter] = useState(false);
const filterInstRef = useRef<IFrontendFilter | null>(null);
const [attributes, setAttributes] = useState<TAttribute[] | null>(null);
const productsRef = useRef<TFilteredProductList | null>(null);
const attributesFilterInput = useRef<TProductFilter>({});
const initialFilterRef = useRef<TProductFilter>({});
const entityListPageRef = useRef<IEntityListPage<TProductFilter> | null>(null);
useEffect(() => {
init();
if (filterInstRef.current && initialFilterRef.current) {
const filter = initialFilterRef.current;
if (filter.attributes || filter.minPrice || filter.maxPrice || filter.nameSearch) {
filterInstRef.current.setFilter(filter);
attributesFilterInput.current = filter;
entityListPageRef.current?.resetList?.();
}
}
}, []);
const init = async () => {
const attributes = await client.getAttributes();
setAttributes(attributes);
}
const handleToggleFilter = () => {
setShowFilter(prev => !prev);
}
const onFilterMount = () => {
filterInstRef.current?.updateFilterMeta(productsRef.current);
}
const onFilterChange = (params: TProductFilter) => {
Object.keys(params).forEach(key => {
attributesFilterInput.current[key] = params[key];
});
entityListPageRef.current?.resetList?.();
}
return (
<>
<EntityTableComp
entityCategory={EDBEntity.Product}
entityListRoute={productListInfo.route}
entityBaseRoute={productPageInfo.baseRoute}
listLabel="Products"
entityLabel="Product"
nameProperty="name"
getManyFiltered={async (options) => {
if (!options.filterParams) options.filterParams = {};
options.filterParams.minPrice = attributesFilterInput.current?.minPrice;
options.filterParams.maxPrice = attributesFilterInput.current?.maxPrice;
options.filterParams.attributes = attributesFilterInput.current?.attributes;
options.filterParams.nameSearch = attributesFilterInput.current?.nameSearch;
const data = await client.getFilteredProducts(options);
filterInstRef.current?.updateFilterMeta(data);
productsRef.current = data;
return data;
}}
deleteOne={client.deleteProduct}
deleteMany={client.deleteManyProducts}
deleteManyFiltered={client.deleteManyFilteredProducts}
getPageListInstance={inst => {
entityListPageRef.current = inst;
initialFilterRef.current = Object.assign({}, inst.getFilterInput());
}}
onClearAllFilters={() => {
filterInstRef.current?.setFilter({});
attributesFilterInput.current = {};
}}
isFilterActive={() => {
const filter = attributesFilterInput.current;
return !!(filter.nameSearch || filter.attributes || filter.maxPrice || filter.minPrice);
}}
columns={[
{
name: 'mainImage',
label: 'Image',
type: 'Image',
visible: true,
},
{
name: 'name',
label: 'Name',
type: 'Simple text',
visible: true,
minWidth: '25%',
},
{
name: 'sku',
label: 'SKU',
type: 'Simple text',
visible: true,
},
{
name: 'price',
label: 'Price',
type: 'Currency',
visible: true,
},
{
name: 'oldPrice',
label: 'Old Price',
type: 'Currency',
visible: false,
},
{
name: 'stockStatus',
label: 'Stock status',
type: 'Simple text',
visible: true,
exactSearch: true,
searchOptions: [
{
value: 'In stock',
label: 'In stock',
},
{
value: 'Out of stock',
label: 'Out of stock',
},
{
value: 'On backorder',
label: 'On backorder',
},
]
},
...baseEntityColumns.map(col => {
if (col.name === 'createDate') return { ...col, visible: true }
return { ...col, visible: false }
}),
]}
customElements={{
listLeftActions: (
<div>
<Tooltip title="Attribute filter">
<IconButton
className={styles.attributeFilterButton}
onClick={handleToggleFilter}
aria-label="show filter"
>
<FilterListIcon />
</IconButton>
</Tooltip>
</div>
)
}}
/>
<Drawer
classes={{ paper: styles.filterDrawer }}
variant="persistent"
anchor={'left'}
open={showFilter}
onClose={() => setShowFilter(false)}>
<div className={styles.filterHeader}>
<h3>Filter</h3>
<Tooltip title="Close">
<IconButton
onClick={handleToggleFilter}
aria-label="close filter"
>
<CloseIcon />
</IconButton>
</Tooltip>
</div>
<ProductFilter
instanceSettings={{
disableMobile: true,
onChange: onFilterChange,
getInstance: (inst) => { filterInstRef.current = inst },
onMount: onFilterMount,
}}
data={{
attributes
}}
/>
</Drawer>
</>
)
}