@material-ui/core#Hidden TypeScript Examples
The following examples show how to use
@material-ui/core#Hidden.
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: Grid.tsx From firetable with Apache License 2.0 | 6 votes |
export default function GridPage() {
const router = useRouter();
const tableCollection = decodeURIComponent(router.match.params.id);
let filters: FireTableFilter[] = [];
const parsed = queryString.parse(router.location.search);
if (typeof parsed.filters === "string") {
// decoded
//[{"key":"cohort","operator":"==","value":"AMS1"}]
filters = JSON.parse(parsed.filters);
//TODO: json schema validator
}
return (
<Navigation tableCollection={tableCollection}>
<Grid
key={tableCollection}
collection={tableCollection}
filters={filters}
/>
<Hidden smDown>
<SideDrawer />
</Hidden>
</Navigation>
);
}
Example #2
Source File: index.tsx From lobis-frontend with MIT License | 6 votes |
function ViewBase({ children }: IViewBaseProps) {
const classes = useStyles();
const [mobileOpen, setMobileOpen] = useState(false);
const isSmallerScreen = useMediaQuery("(max-width: 960px)");
const isSmallScreen = useMediaQuery("(max-width: 600px)");
const handleDrawerToggle = () => {
setMobileOpen(!mobileOpen);
};
return (
<div className="view-base-root">
<Messages />
<Header drawe={!isSmallerScreen} handleDrawerToggle={handleDrawerToggle} />
<div className={classes.drawer}>
<Hidden mdUp>
<MobileDrawer mobileOpen={mobileOpen} handleDrawerToggle={handleDrawerToggle} />
</Hidden>
<Hidden smDown>
<Drawer />
</Hidden>
</div>
<div className={`${classes.content} ${isSmallerScreen && classes.contentShift}`}>{children}</div>
</div>
);
}
Example #3
Source File: Sidebar.tsx From knboard with MIT License | 6 votes |
Sidebar = () => {
const dispatch = useDispatch();
const mobileOpen = useSelector(mobileDrawerOpen);
const handleCloseMobileDrawer = () => {
dispatch(setMobileDrawerOpen(false));
};
return (
<>
<Hidden smUp implementation="css">
<Drawer
variant="temporary"
anchor="left"
open={mobileOpen}
onClose={handleCloseMobileDrawer}
ModalProps={{ keepMounted: true }}
>
<DrawerContent />
</Drawer>
</Hidden>
<Hidden xsDown implementation="css">
<Drawer anchor="left" variant="permanent">
<DrawerContent />
</Drawer>
</Hidden>
</>
);
}
Example #4
Source File: Navbar.tsx From knboard with MIT License | 6 votes |
Navbar = () => {
const dispatch = useDispatch();
return (
<Container>
<Item>
<Icons>
<Hidden smUp implementation="css">
<FontAwesomeIcon
icon={faBars}
onClick={() => dispatch(setMobileDrawerOpen(true))}
/>
</Hidden>
<Hidden xsDown implementation="css">
<FontAwesomeIcon icon={faRocket} />
</Hidden>
</Icons>
</Item>
<Item>Knboard</Item>
<Item>
<UserMenu />
</Item>
</Container>
);
}
Example #5
Source File: body.tsx From aqualink-app with MIT License | 6 votes |
RowNumberCell = ({
color,
unit,
decimalPlaces,
value,
classes,
isExtended,
}: {
color?: string;
unit?: string;
value: number | null;
decimalPlaces?: number;
classes: SiteTableBodyProps["classes"];
isExtended?: boolean;
}) => {
return (
<TableCell
className={
isExtended ? classes.cellTextAlignExtended : classes.cellTextAlign
}
>
<Typography
variant="h6"
style={{ color }}
className={classes.numberCellsTitle}
>
{formatNumber(value, decimalPlaces)}
<Hidden smUp>
<Typography variant="h6" component="span">
{unit}
</Typography>
</Hidden>
</Typography>
</TableCell>
);
}
Example #6
Source File: Topbar.tsx From knests with MIT License | 5 votes |
Topbar = (props) => {
const { className, onSidebarOpen, ...rest } = props;
const classes = useStyles();
const [notifications] = useState([]);
const router = useRouter();
const handleSignOut = () => {
router.push('/login');
localStorage.removeItem('token');
};
return (
<AppBar
{...rest}
className={clsx(classes.root, className)}
>
<Toolbar>
<Link href="/">
<a >
<img
alt="Logo"
src="/images/logos/logo--white.svg"
/>
</a>
</Link>
<div className={classes.flexGrow} />
<Hidden mdDown>
<IconButton color="inherit">
<Badge
badgeContent={notifications.length}
color="primary"
variant="dot"
>
<NotificationsIcon />
</Badge>
</IconButton>
<IconButton
className={classes.signOutButton}
color="inherit"
onClick={handleSignOut}
>
<InputIcon />
</IconButton>
</Hidden>
<Hidden lgUp>
<IconButton
color="inherit"
onClick={onSidebarOpen}
>
<MenuIcon />
</IconButton>
</Hidden>
</Toolbar>
</AppBar>
);
}
Example #7
Source File: ModeTabs.tsx From prompts-ai with MIT License | 5 votes |
export default function ModeTabs() {
const dispatch = useDispatch();
const classes = useStyles();
const tabIndex = useSelector(selectTabIndex);
const handleTabIndexChange = (event: React.ChangeEvent<{}>, newValue: number) => {
dispatch(updateTabIndex(newValue));
};
return (
<div className={classes.root}>
<AppBar position="static">
<Grid
justify="space-between" // Add it here :)
alignItems="center"
container
spacing={1}
>
<Grid item>
<Tabs value={tabIndex} onChange={handleTabIndexChange} aria-label="simple tabs example">
<Tab label="Simple" {...a11yProps(TabIndex.basic)} />
<Tab label="Examples" {...a11yProps(TabIndex.multipleExamples)} />
<Tab label="Variations" {...a11yProps(TabIndex.variations)} />
<Tab label="Conversations" {...a11yProps(TabIndex.conversations)} />
</Tabs>
</Grid>
<Hidden smDown>
<Grid item className={classes.additionalItemsGridItem}>
<CodeGeneratorButton/>
</Grid>
</Hidden>
</Grid>
</AppBar>
<TabPanel value={tabIndex} index={TabIndex.basic}>
<BasicTab/>
</TabPanel>
<TabPanel value={tabIndex} index={TabIndex.multipleExamples}>
<ExamplesTab/>
</TabPanel>
<TabPanel value={tabIndex} index={TabIndex.variations}>
<VariationsTab/>
</TabPanel>
<TabPanel value={tabIndex} index={TabIndex.conversations}>
<ConversationsTab/>
</TabPanel>
</div>
);
}
Example #8
Source File: LabelDialog.tsx From knboard with MIT License | 5 votes |
LabelDialog = () => {
const theme = useTheme();
const dispatch = useDispatch();
const open = useSelector((state: RootState) => state.label.dialogOpen);
const labels = useSelector(selectAllLabels);
const [searchValue, setSearchValue] = useState("");
const [creating, setCreating] = useState(false);
const xsDown = useMediaQuery(theme.breakpoints.down("xs"));
const filteredLabels = labels.filter((label) =>
label.name.toLowerCase().match(searchValue.trim().toLowerCase())
);
const handleClose = () => {
dispatch(setDialogOpen(false));
};
return (
<Dialog
open={open}
onClose={handleClose}
maxWidth="sm"
fullWidth
fullScreen={xsDown}
>
<Close onClose={handleClose} />
<DialogTitle id="edit-labels">Edit labels</DialogTitle>
<Container>
<Flex
css={css`
align-items: flex-end;
${creating && "margin-bottom: 1rem;"}
`}
>
<LabelCount>
{filteredLabels.length} label{filteredLabels.length !== 1 && "s"}
</LabelCount>
<div>
<Hidden xsDown implementation="css">
<TextField
value={searchValue}
onChange={(e) => setSearchValue(e.target.value)}
placeholder="Search labels"
InputProps={{
startAdornment: (
<InputAdornment
position="start"
css={css`
color: #ccc;
`}
>
<FontAwesomeIcon icon={faSearch} />
</InputAdornment>
),
}}
/>
</Hidden>
</div>
<Button
size="small"
color="primary"
variant="contained"
onClick={() => setCreating(true)}
css={css`
margin-right: 1rem;
`}
>
New label
</Button>
</Flex>
{creating && <LabelCreate setCreating={setCreating} />}
<Table>
{filteredLabels.map((label) => (
<LabelRow key={label.id + label.color + label.name} label={label} />
))}
</Table>
</Container>
</Dialog>
);
}
Example #9
Source File: CreatePage.tsx From clearflask with Apache License 2.0 | 5 votes |
CreateLayout = (props: {
title: string;
isOnboarding?: boolean;
description: React.ReactNode;
stretchContent?: boolean;
content?: React.ReactNode;
actions?: React.ReactNode[];
img?: Img;
}) => {
const classes = useStyles();
return (
<div className={classes.layout}>
{props.isOnboarding && (
<div className={classes.layoutHeader}>
<div className={classes.layoutHeaderLogo}><Logo /></div>
</div>
)}
<div className={classes.layoutContentAndImage}>
<div className={classes.layoutContentContainer}>
<div className={classes.layoutLimitWidth}>
<Typography variant='h3' component='h1' className={classes.layoutContentTitle}>{props.title}</Typography>
<Typography variant='h6' component='div' className={classes.layoutContentDescription}>{props.description}</Typography>
</div>
{!!props.content && (
<div className={classNames(
classes.layoutContent,
!props.stretchContent && classes.layoutLimitWidth,
)}>{props.content}</div>
)}
{!!props.actions?.length && (
<div className={classNames(classes.layoutContentActions, classes.layoutLimitWidth)}>
{props.actions.map(action => (
<div className={classes.layoutContentAction}>
{action}
</div>
))}
</div>
)}
</div>
{!!props.img && (
<Hidden mdDown>
<ImgIso
alt=''
className={classes.layoutImage}
src={props.img.src}
aspectRatio={props.img.aspectRatio}
width={props.img.width}
height={props.img.height}
maxWidth={props.img.width}
maxHeight={props.img.height}
/>
</Hidden>
)}
</div>
</div>
);
}
Example #10
Source File: index.tsx From aqualink-app with MIT License | 5 votes |
Homepage = ({ classes }: HomepageProps) => {
const dispatch = useDispatch();
const siteOnMap = useSelector(siteOnMapSelector);
const { initialZoom, initialSiteId, initialCenter }: MapQueryParams =
useQuery();
useEffect(() => {
dispatch(sitesRequest());
}, [dispatch]);
useEffect(() => {
if (!siteOnMap && initialSiteId) {
dispatch(siteRequest(initialSiteId));
dispatch(surveysRequest(initialSiteId));
} else if (siteOnMap) {
dispatch(siteRequest(`${siteOnMap.id}`));
dispatch(surveysRequest(`${siteOnMap.id}`));
}
}, [dispatch, initialSiteId, siteOnMap]);
const [isDrawerOpen, setDrawerOpen] = useState(false);
const toggleDrawer = () => {
setDrawerOpen(!isDrawerOpen);
};
// scroll drawer to top when its closed.
// the lib we use doesn't support passing ID or ref, so we rely on class name here.
// scrollTopAtClose prop doesn't work with manually controlled state
useEffect(() => {
if (isDrawerOpen) return;
const className = "ReactSwipeableBottomSheet";
const drawer =
document.getElementsByClassName(`${className}--opened`)[0] ||
document.getElementsByClassName(`${className}--closed`)[0];
if (!drawer) return;
// eslint-disable-next-line fp/no-mutation
drawer.scrollTop = 0;
});
return (
<>
<div role="presentation" onClick={isDrawerOpen ? toggleDrawer : () => {}}>
<HomepageNavBar searchLocation geocodingEnabled />
</div>
<div className={classes.root}>
<Grid container>
<Grid className={classes.map} item xs={12} md={6}>
<HomepageMap
initialZoom={initialZoom}
initialCenter={initialCenter}
/>
</Grid>
<Hidden smDown>
<Grid className={classes.siteTable} item md={6}>
<SiteTable />
</Grid>
</Hidden>
<Hidden mdUp>
<SwipeableBottomSheet
overflowHeight={60}
bodyStyle={{
borderTopLeftRadius: "25px",
borderTopRightRadius: "25px",
maxHeight: "80vh",
}}
onChange={setDrawerOpen}
open={isDrawerOpen}
>
<div role="presentation" onClick={toggleDrawer}>
<SiteTable isDrawerOpen={isDrawerOpen} />
</div>
</SwipeableBottomSheet>
</Hidden>
</Grid>
</div>
</>
);
}
Example #11
Source File: index.tsx From aqualink-app with MIT License | 5 votes |
SurveyTimeline = ({
loading,
isAdmin,
siteId,
addNewButton,
timeZone,
observation,
pointName,
pointId,
classes,
}: SurveyTimelineProps) => {
const surveyList = useSelector(surveyListSelector);
const displayAddButton =
isAdmin &&
addNewButton &&
!(window && window.location.pathname.includes("new_survey"));
// If the site is loading, then display two survey card skeletons,
// else display the actual survey cards.
const filteredSurveys = loading
? [null, null]
: filterSurveys(surveyList, observation, pointId);
const timelineProps: TimelineProps = {
siteId,
loading,
isAdmin,
pointId,
pointName,
surveys: filteredSurveys,
timeZone,
displayAddButton,
};
return (
<div className={classes.root}>
<Hidden mdDown>
<TimelineDesktop {...timelineProps} />
</Hidden>
<Hidden lgUp>
<TimelineTablet {...timelineProps} />
</Hidden>
</div>
);
}
Example #12
Source File: Table.tsx From firetable with Apache License 2.0 | 5 votes |
export default function TablePage() {
const router = useRouter();
const tableCollection = decodeURIComponent(router.match.params.id);
const { tableState, tableActions, sideDrawerRef } = useFiretableContext();
const { userDoc } = useAppContext();
let filters: FireTableFilter[] = [];
const parsed = queryString.parse(router.location.search);
if (typeof parsed.filters === "string") {
filters = JSON.parse(parsed.filters);
// TODO: json schema validator
}
useEffect(() => {
if (
tableActions &&
tableState &&
tableState.tablePath !== tableCollection
) {
tableActions.table.set(tableCollection, filters);
if (filters && filters.length !== 0) {
userDoc.dispatch({
action: DocActions.update,
data: {
tables: { [`${tableState.tablePath}`]: { filters } },
},
});
}
if (sideDrawerRef?.current) sideDrawerRef.current.setCell!(null);
}
}, [tableCollection]);
if (!tableState) return null;
return (
<Navigation tableCollection={tableCollection}>
<ActionParamsProvider>
{tableState.loadingColumns && (
<>
<TableHeaderSkeleton />
<HeaderRowSkeleton />
</>
)}
{!tableState.loadingColumns && !_isEmpty(tableState.columns) && (
<Table key={tableCollection} />
)}
{!tableState.loadingColumns && _isEmpty(tableState.columns) && (
<EmptyTable />
)}
<Hidden smDown>
<SideDrawer />
</Hidden>
</ActionParamsProvider>
</Navigation>
);
}
Example #13
Source File: index.tsx From wonderland-frontend with MIT License | 5 votes |
function ViewBase({ children }: IViewBaseProps) {
const classes = useStyles();
const [mobileOpen, setMobileOpen] = useState(false);
const isSmallerScreen = useMediaQuery("(max-width: 960px)");
const isSmallScreen = useMediaQuery("(max-width: 600px)");
const handleDrawerToggle = () => {
setMobileOpen(!mobileOpen);
};
return (
<div className="view-base-root">
<Messages />
<Header drawe={!isSmallerScreen} handleDrawerToggle={handleDrawerToggle} />
<div className={classes.drawer}>
<Hidden mdUp>
<MobileDrawer mobileOpen={mobileOpen} handleDrawerToggle={handleDrawerToggle} />
</Hidden>
<Hidden smDown>
<Drawer />
</Hidden>
</div>
<div className={`${classes.content} ${isSmallerScreen && classes.contentShift}`}>
{!isSmallerScreen && (
<div className="cubes-top">
<p>{cubesImage}</p>
</div>
)}
{!isSmallScreen && (
<div className="cubes-bottom">
<p>{cubesImage}</p>
</div>
)}
{children}
</div>
</div>
);
}
Example #14
Source File: MetaMaskConnector.tsx From metamask-snap-polkadot with Apache License 2.0 | 5 votes |
MetaMaskConnector = () => {
const [state, dispatch] = useContext(MetaMaskContext);
useEffect( () => {
(async () => {
if(await isPolkadotSnapInstalled()) {
dispatch({type: MetamaskActions.SET_INSTALLED_STATUS, payload: {isInstalled: true}});
}
})();
}, [dispatch]);
const installSnap = useCallback(async () => {
const isInitiated = await installPolkadotSnap();
if(!isInitiated) {
dispatch({type: MetamaskActions.SET_INSTALLED_STATUS, payload: {isInstalled: false, message: "Please accept snap installation prompt"}})
} else {
dispatch({type: MetamaskActions.SET_INSTALLED_STATUS, payload: {isInstalled: true}});
}
}, [dispatch]);
const handleClose = (event: React.SyntheticEvent | React.MouseEvent, reason?: string) => {
if (reason === 'clickaway') {
return;
}
dispatch({type: MetamaskActions.SET_INSTALLED_STATUS, payload: false})
};
const shouldDisplaySnackbar = (): boolean => {
if (!state.polkadotSnap.isInstalled && state.polkadotSnap.message) return true;
else return false;
}
return(
<div>
<Snackbar
anchorOrigin={{
vertical: 'bottom',
horizontal: 'left',
}}
open={shouldDisplaySnackbar()}
autoHideDuration={6000}
onClose={handleClose}
message={state.polkadotSnap.message}
action={
<React.Fragment>
<IconButton size="small" aria-label="close" color="inherit" onClick={handleClose}>
<CloseIcon fontSize="small" />
</IconButton>
</React.Fragment>
}
/>
<Hidden xsUp={state.hasMetaMask}>
<Alert severity="warning">Ensure that MetaMask is installed!</Alert>
<Box mt={"1rem"} />
</Hidden>
<Button
disabled={!state.hasMetaMask}
onClick={installSnap}
variant="contained"
size={"large"}
color="primary"
>
Connect to MetaMask
</Button>
</div>
);
}
Example #15
Source File: index.tsx From rugenerous-frontend with MIT License | 5 votes |
function ViewBase({ children }: IViewBaseProps) {
const classes = useStyles();
const [mobileOpen, setMobileOpen] = useState(false);
const isSmallerScreen = useMediaQuery("(max-width: 960px)");
const isSmallScreen = useMediaQuery("(max-width: 600px)");
const handleDrawerToggle = () => {
setMobileOpen(!mobileOpen);
};
return (
<div className="view-base-root">
<Messages />
<Header drawe={!isSmallerScreen} handleDrawerToggle={handleDrawerToggle} />
<div className={classes.drawer}>
<Hidden mdUp>
<MobileDrawer mobileOpen={mobileOpen} handleDrawerToggle={handleDrawerToggle} />
</Hidden>
<Hidden smDown>
<Drawer />
</Hidden>
</div>
<div className={`${classes.content} ${isSmallerScreen && classes.contentShift}`}>
{!isSmallerScreen && (
<div className="cubes-top">
<p>{cubesImage}</p>
</div>
)}
{!isSmallScreen && (
<div className="cubes-bottom">
<p>{cubesImage}</p>
</div>
)}
{children}
</div>
</div>
);
}
Example #16
Source File: index.tsx From gatsby-theme-pristine with Apache License 2.0 | 4 votes |
Layout: React.FC = ({ children }) => { const darkMode = useDarkMode(); const theme = darkMode.value ? darkTheme : lightTheme; const components = { h1: (props: any) => <Typography variant={"h1"} {...props} gutterBottom={true} />, h2: (props: any) => <Typography variant={"h2"} {...props} gutterBottom={true} />, h3: (props: any) => <Typography variant={"h3"} {...props} gutterBottom={true} />, h4: (props: any) => <Typography variant={"h4"} {...props} gutterBottom={true} />, h5: (props: any) => <Typography variant={"h5"} {...props} gutterBottom={true} />, h6: (props: any) => <Typography variant={"h6"} {...props} gutterBottom={true} />, Demo: (props: any) => <h1>This is a demo component</h1>, code: (props: any) => <CodeBlock darkMode={darkMode.value} {...props} />, thematicBreak: (props: any) => <Divider {...props} />, a: (props: any) => <Link {...props} />, table: (props: any) => <Table {...props} style={{ marginBottom: "15px", ...props.style }} />, thead: (props: any) => <TableHead {...props} />, tr: (props: any) => <TableRow {...props} />, tableBody: (props: any) => <TableBody {...props} />, td: (props: any) => { return ( <TableCell> {props.children || ""} </TableCell> ); }, }; const [open, setOpen] = useState(); const data = useStaticQuery(graphql` query LayoutQuery { site { siteMetadata { title description logoUrl primaryColor secondaryColor footerLinks { name link } } } } `); return ( <MDXProvider components={components}> <MuiThemeProvider theme={{ ...theme, palette: { ...theme.palette, primary: { ...theme.palette.primary, main: data.site.siteMetadata.primaryColor, }, secondary: { ...theme.palette.secondary, main: data.site.siteMetadata.secondaryColor, } } }}> <Sidebar open={open} onClose={() => setOpen(false)} /> <AppBar position="fixed" color="default" elevation={0}> <Toolbar> <IconButton onClick={() => setOpen(true)}> <MenuIcon fontSize="small" /> </IconButton> <Grid container alignContent="center" alignItems="center" justify="space-between"> <Grid item container direction="row" xs={5}> <Grid style={{ paddingRight: "5px" }}> <img alt="logo" height="30" style={{ marginTop: "6px", }} src={data.site.siteMetadata.logoUrl} /> </Grid> <Grid style={{ marginTop: "7px" }}> <GatsbyLink to="/" style={{ textDecoration: "none" }}> <Typography color="textSecondary" variant="h6"> {data.site.siteMetadata.title} </Typography> </GatsbyLink> </Grid> </Grid> <Grid item container direction="row" xs={7} justify="flex-end" alignItems="center"> <Hidden only="xs"> <Search /> </Hidden> <Tooltip title={"Toggle Dark Mode"}> <IconButton onClick={darkMode.toggle}> {darkMode.value ? <Brightness3Icon fontSize="small" /> : <WbSunnyIcon fontSize="small" />} </IconButton> </Tooltip> </Grid> </Grid> </Toolbar> </AppBar> <Container> <CssBaseline /> <div style={{ padding: "30px", paddingTop: "64px" }}> {children} <Footer footerLinks={data.site.siteMetadata.footerLinks} /> </div> </Container> </MuiThemeProvider > </MDXProvider > ); }
Example #17
Source File: AdrScene.tsx From log4brains with Apache License 2.0 | 4 votes |
export function AdrScene({ projectName, currentAdr }: AdrSceneProps) {
const classes = useStyles();
const mode = React.useContext(Log4brainsModeContext);
const adrNav = React.useContext(AdrNavContext);
const [mdContent, setMdContent] = React.useState<
React.ReactElement | undefined
>(undefined);
if (!currentAdr) {
return null; // Happens during Next.js initial build
}
let alert;
if (currentAdr.status === "superseded") {
alert = (
<Alert severity="warning" className={classes.alert}>
This ADR is <strong>superseded</strong>
{currentAdr.supersededBy ? (
<>
{" by "}
<Link href={buildAdrUrl(currentAdr.supersededBy)} passHref>
<MuiLink>{currentAdr.supersededBy.title || "Untitled"}</MuiLink>
</Link>
</>
) : null}
.
</Alert>
);
} else if (currentAdr.status === "deprecated") {
alert = (
<Alert severity="warning" className={classes.alert}>
This ADR is <strong>deprecated</strong>.
</Alert>
);
} else if (currentAdr.status === "rejected") {
alert = (
<Alert severity="error" className={classes.alert}>
This ADR was <strong>rejected</strong>.
</Alert>
);
}
return (
<>
<Head>
<title>
{currentAdr.title || "Untitled"} ADR - Architecture knowledge base of{" "}
{projectName}
</title>
</Head>
<TwoColContent
rightColContent={<MarkdownToc content={mdContent} levelStart={2} />}
>
<Typography variant="h3" gutterBottom>
{currentAdr.title || "Untitled"}
</Typography>
<Divider />
<AdrHeader
adr={currentAdr}
className={classes.header}
locallyEditable={mode === Log4brainsMode.preview}
/>
{alert}
<Markdown onCompiled={setMdContent}>
{currentAdr.body.enhancedMdx}
</Markdown>
<Divider className={classes.bottomNavDivider} />
<nav className={classes.bottomNav}>
{adrNav.previousAdr ? (
<Link href={buildAdrUrl(adrNav.previousAdr)} passHref>
<Tooltip
title={adrNav.previousAdr.title || ""}
aria-label="previous"
>
<Button startIcon={<ArrowBackIcon />}>
<Hidden xsDown implementation="css">
Previous
</Hidden>
</Button>
</Tooltip>
</Link>
) : (
<div />
)}
<div className={classes.bottomInfo}>
<Typography className={classes.bottomInfoText}>
Last edited by {currentAdr.lastEditAuthor}
</Typography>
<Typography className={classes.bottomInfoText}>
on {moment(currentAdr.lastEditDate).format("lll")}
</Typography>
</div>
{adrNav.nextAdr ? (
<Link href={buildAdrUrl(adrNav.nextAdr)} passHref>
<Tooltip title={adrNav.nextAdr.title || ""} aria-label="next">
<Button endIcon={<ArrowForwardIcon />}>
<Hidden xsDown implementation="css">
Next
</Hidden>
</Button>
</Tooltip>
</Link>
) : (
<div />
)}
</nav>
</TwoColContent>
</>
);
}
Example #18
Source File: AdrBrowserLayout.tsx From log4brains with Apache License 2.0 | 4 votes |
export function AdrBrowserLayout({
projectName,
adrs,
adrsReloading = false,
currentAdr,
children,
routing = false,
l4bVersion
}: AdrBrowserLayoutProps) {
const classes = useStyles();
const router = useRouter();
const [mobileDrawerOpen, setMobileDrawerOpen] = React.useState(false);
const handleMobileDrawerToggle = () => {
setMobileDrawerOpen(!mobileDrawerOpen);
};
React.useEffect(() => {
const closeMobileDrawer = () => setMobileDrawerOpen(false);
router?.events.on("routeChangeStart", closeMobileDrawer);
return () => {
router?.events.off("routeChangeStart", closeMobileDrawer);
};
}, [router]);
const [searchOpen, setSearchOpenState] = React.useState(false);
const [searchReallyOpen, setSearchReallyOpenState] = React.useState(false);
const drawer = (
<div className={classes.drawerContainer}>
<Toolbar className={classes.drawerToolbar}>
<div />
<Link href="/" passHref>
<IconButton
size="small"
color="inherit"
aria-label="go to homepage"
title={`Architecture knowledge base of ${projectName}`}
>
<img
src={`${router?.basePath}/l4b-static/Log4brains-logo.png`}
alt="Log4brains logo"
width={40}
height={40}
/>
</IconButton>
</Link>
<IconButton
size="small"
color="inherit"
aria-label="close drawer"
title="Close"
onClick={handleMobileDrawerToggle}
>
<CloseIcon fontSize="small" />
</IconButton>
</Toolbar>
<div className={classes.adlTitleAndSpinner}>
<Typography variant="subtitle2" className={classes.adlTitle}>
Decision log
</Typography>
<Fade in={adrsReloading}>
<CircularProgress size={13} />
</Fade>
</div>
<Grow in={adrs !== undefined} style={{ transformOrigin: "center left" }}>
<AdrMenu
adrs={adrs}
currentAdrSlug={currentAdr?.slug}
className={classes.adrMenu}
/>
</Grow>
{adrs === undefined && (
<CircularProgress size={30} className={classes.adrMenuSpinner} />
)}
<List className={classes.bottomMenuList}>
{/* <Divider />
<ListItem button>
<ListItemIcon>
<ChevronRightIcon />
</ListItemIcon>
<ListItemText>
<Badge badgeContent={0} color="primary">
<Typography>Filters</Typography>
</Badge>
</ListItemText>
</ListItem> */}
{/* <Divider />
<Link href="/decision-backlog" passHref>
<ListItem button selected={backlog} component="a">
<ListItemIcon>
<PlaylistAddCheckIcon />
</ListItemIcon>
<ListItemText primary="Decision backlog" />
</ListItem>
</Link> */}
</List>
</div>
);
return (
<div className={classes.root}>
<AppBar position="fixed" className={classes.appBar}>
{routing && <RoutingProgress />}
<Toolbar>
<IconButton
color="inherit"
aria-label="open drawer"
edge="start"
onClick={handleMobileDrawerToggle}
className={classes.appBarMenuButton}
>
<MenuIcon />
</IconButton>
<Link href="/">
<div className={classes.appBarTitle}>
<div>
<img
src={`${router?.basePath}/l4b-static/Log4brains-logo-dark.png`}
alt="Log4brains logo"
width={50}
height={50}
/>
</div>
<div>
<Link href="/" passHref>
<MuiLink
variant="h6"
noWrap
className={classes.appBarTitleLink}
>
{projectName}
</MuiLink>
</Link>
<Link href="/" passHref>
<MuiLink
variant="body2"
noWrap
className={classes.appBarTitleLink}
>
Architecture knowledge base
</MuiLink>
</Link>
</div>
</div>
</Link>
<div className={classes.layoutLeftCol} />
<div className={clsx(classes.layoutCenterCol)}>
<Backdrop open={searchOpen} className={classes.searchBackdrop} />
<NoSsr>
<ConnectedSearchBox
onOpen={() => {
setSearchOpenState(true);
// Delayed real opening because otherwise the dropdown width is bugged
setTimeout(
() => setSearchReallyOpenState(true),
searchTransitionDuration + 100
);
}}
onClose={() => {
setSearchOpenState(false);
setSearchReallyOpenState(false);
}}
open={searchReallyOpen}
className={clsx(classes.searchBox, {
[classes.searchBoxOpen]: searchOpen
})}
/>
</NoSsr>
</div>
<div className={classes.layoutRightCol} />
</Toolbar>
</AppBar>
<nav
className={classes.drawer}
aria-label="architecture decision records list"
>
<Hidden smUp implementation="css">
<Drawer
variant="temporary"
anchor="left"
open={mobileDrawerOpen}
onClose={handleMobileDrawerToggle}
classes={{
paper: classes.drawerPaper
}}
ModalProps={{
keepMounted: true // Better open performance on mobile.
}}
>
{drawer}
</Drawer>
</Hidden>
<Hidden xsDown implementation="css">
<Drawer
variant="permanent"
open
classes={{
paper: classes.drawerPaper
}}
>
{drawer}
</Drawer>
</Hidden>
</nav>
<div className={classes.container}>
<Toolbar />
<main className={classes.content}>
<AdrNavContext.Provider
value={currentAdr && adrs ? buildAdrNav(currentAdr, adrs) : {}}
>
{children}
</AdrNavContext.Provider>
</main>
<footer className={classes.footer}>
<div className={classes.layoutLeftCol} />
<div className={clsx(classes.layoutCenterCol, classes.footerContent)}>
<Typography className={classes.footerText}>
Powered by{" "}
<MuiLink
href="https://github.com/thomvaill/log4brains"
className={classes.footerLink}
target="_blank"
rel="noopener"
>
Log4brains
</MuiLink>{" "}
<span style={{ fontSize: "0.8em" }}>
{l4bVersion ? `(v${l4bVersion})` : null}
</span>
</Typography>
</div>
<div className={classes.layoutRightCol} />
</footer>
</div>
</div>
);
}
Example #19
Source File: index.tsx From prism-frontend with MIT License | 4 votes |
function DateSelector({ availableDates = [], classes }: DateSelectorProps) {
const { startDate: stateStartDate } = useSelector(dateRangeSelector);
const { t, i18n } = useSafeTranslation();
const [dateRange, setDateRange] = useState<DateRangeType[]>([
{
value: 0,
label: '',
month: '',
isFirstDay: false,
},
]);
const [timelinePosition, setTimelinePosition] = useState<Point>({
x: 0,
y: 0,
});
const [pointerPosition, setPointerPosition] = useState<Point>({ x: 0, y: 0 });
const dateRef = useRef(availableDates);
const timeLine = useRef(null);
const timeLineWidth = get(timeLine.current, 'offsetWidth', 0);
const { updateHistory } = useUrlHistory();
// Move the slider automatically so that the pointer always visible
useEffect(() => {
let x = 0;
if (
pointerPosition.x >=
dateRange.length * TIMELINE_ITEM_WIDTH - timeLineWidth
) {
// eslint-disable-next-line fp/no-mutation
x = timeLineWidth - dateRange.length * TIMELINE_ITEM_WIDTH;
} else if (pointerPosition.x > timeLineWidth) {
// eslint-disable-next-line fp/no-mutation
x = -pointerPosition.x + timeLineWidth / 2;
}
if (
-timelinePosition.x > pointerPosition.x ||
-timelinePosition.x + timeLineWidth < pointerPosition.x
) {
setTimelinePosition({ x, y: 0 });
}
}, [dateRange.length, pointerPosition, timeLineWidth, timelinePosition.x]);
// Create timeline range and set pointer position
useEffect(() => {
const locale = t('date_locale') ? t('date_locale') : 'en';
const range = Array.from(
moment()
.range(
moment(stateStartDate).startOf('year'),
moment(stateStartDate).endOf('year'),
)
.by('days'),
).map(date => {
date.locale(locale);
return {
value: date.valueOf(),
label: date.format(MONTH_FIRST_DATE_FORMAT),
month: date.format(MONTH_ONLY_DATE_FORMAT),
isFirstDay: date.date() === date.startOf('month').date(),
};
});
setDateRange(range);
const dateIndex = findIndex(range, date => {
return (
date.label ===
moment(stateStartDate).locale(locale).format(MONTH_FIRST_DATE_FORMAT)
);
});
setPointerPosition({
x: dateIndex * TIMELINE_ITEM_WIDTH,
y: 0,
});
}, [stateStartDate, t, i18n]);
function updateStartDate(date: Date) {
const time = date.getTime();
// This updates state because a useEffect in MapView updates the redux state
// TODO this is convoluted coupling, we should update state here if feasible.
updateHistory('date', moment(time).format(DEFAULT_DATE_FORMAT));
}
function setDatePosition(date: number | undefined, increment: number) {
const dates = availableDates.map(d => {
return d + USER_DATE_OFFSET;
});
const selectedIndex = findDateIndex(dates, date);
if (dates[selectedIndex + increment]) {
updateStartDate(new Date(dates[selectedIndex + increment]));
}
}
// move pointer to closest date when change map layer
useEffect(() => {
if (!isEqual(dateRef.current, availableDates)) {
setDatePosition(stateStartDate, 0);
dateRef.current = availableDates;
}
});
function incrementDate() {
setDatePosition(stateStartDate, 1);
}
function decrementDate() {
setDatePosition(stateStartDate, -1);
}
// Click on available date to move the pointer
const clickDate = (index: number) => {
const dates = availableDates.map(date => {
return date + USER_DATE_OFFSET;
});
const selectedIndex = findDateIndex(dates, dateRange[index].value);
if (selectedIndex >= 0 && dates[selectedIndex] !== stateStartDate) {
setPointerPosition({ x: index * TIMELINE_ITEM_WIDTH, y: 0 });
updateStartDate(new Date(dates[selectedIndex]));
}
};
// Set timeline position after being dragged
const onTimelineStop = (e: DraggableEvent, position: Point) => {
setTimelinePosition(position);
};
// Set pointer position after being dragged
const onPointerStop = (e: DraggableEvent, position: Point) => {
const exactX = Math.round(position.x / TIMELINE_ITEM_WIDTH);
if (exactX >= dateRange.length) {
return;
}
const dates = availableDates.map(date => {
return date + USER_DATE_OFFSET;
});
const selectedIndex = findDateIndex(dates, dateRange[exactX].value);
if (selectedIndex >= 0 && dates[selectedIndex] !== stateStartDate) {
setPointerPosition({ x: exactX * TIMELINE_ITEM_WIDTH, y: position.y });
updateStartDate(new Date(dates[selectedIndex]));
}
};
return (
<div className={classes.container}>
<Grid
container
alignItems="center"
justify="center"
className={classes.datePickerContainer}
>
<Grid item xs={12} sm={1} className={classes.datePickerGrid}>
<Hidden smUp>
<Button onClick={decrementDate}>
<ChevronLeft />
</Button>
</Hidden>
<DatePicker
locale={t('date_locale')}
dateFormat="PP"
className={classes.datePickerInput}
selected={moment(stateStartDate).toDate()}
onChange={updateStartDate}
maxDate={new Date()}
todayButton={t('Today')}
peekNextMonth
showMonthDropdown
showYearDropdown
dropdownMode="select"
customInput={<Input />}
includeDates={availableDates.map(
d => new Date(d + USER_DATE_OFFSET),
)}
/>
<Hidden smUp>
<Button onClick={incrementDate}>
<ChevronRight />
</Button>
</Hidden>
</Grid>
<Grid item xs={12} sm className={classes.slider}>
<Hidden xsDown>
<Button onClick={decrementDate}>
<ChevronLeft />
</Button>
</Hidden>
<Grid className={classes.dateContainer} ref={timeLine}>
<Draggable
axis="x"
handle={`#${TIMELINE_ID}`}
bounds={{
top: 0,
bottom: 0,
right: 0,
left: timeLineWidth - dateRange.length * TIMELINE_ITEM_WIDTH,
}}
position={timelinePosition}
onStop={onTimelineStop}
>
<div className={classes.timeline} id={TIMELINE_ID}>
<Grid
container
alignItems="stretch"
className={classes.dateLabelContainer}
>
<TimelineItems
dateRange={dateRange}
availableDates={availableDates}
clickDate={clickDate}
/>
</Grid>
<Draggable
axis="x"
handle={`#${POINTER_ID}`}
bounds={{
top: 0,
bottom: 0,
left: 0,
right: dateRange.length * TIMELINE_ITEM_WIDTH,
}}
grid={[TIMELINE_ITEM_WIDTH, 1]}
position={pointerPosition}
onStart={(e: DraggableEvent) => e.stopPropagation()}
onStop={onPointerStop}
>
<div className={classes.pointer} id={POINTER_ID}>
<FontAwesomeIcon
icon={faCaretUp}
style={{ fontSize: 40 }}
color="white"
/>
</div>
</Draggable>
</div>
</Draggable>
</Grid>
<Hidden xsDown>
<Button onClick={incrementDate}>
<ChevronRight />
</Button>
</Hidden>
</Grid>
</Grid>
</div>
);
}
Example #20
Source File: index.tsx From prism-frontend with MIT License | 4 votes |
function Download({ classes }: DownloadProps) {
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const [open, setOpen] = useState(false);
const selectedMap = useSelector(mapSelector);
const previewRef = useRef<HTMLCanvasElement>(null);
const { t } = useSafeTranslation();
const handleClick = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const openModal = () => {
if (selectedMap) {
const activeLayers = selectedMap.getCanvas();
const canvas = previewRef.current;
if (canvas) {
canvas.setAttribute('width', activeLayers.width.toString());
canvas.setAttribute('height', activeLayers.height.toString());
const context = canvas.getContext('2d');
if (context) {
context.drawImage(activeLayers, 0, 0);
}
}
setOpen(true);
}
handleClose();
};
const download = (format: string) => {
const ext = format === 'pdf' ? 'png' : format;
const canvas = previewRef.current;
if (canvas) {
const file = canvas.toDataURL(`image/${ext}`);
if (format === 'pdf') {
// eslint-disable-next-line new-cap
const pdf = new jsPDF({
orientation: 'landscape',
});
const imgProps = pdf.getImageProperties(file);
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width;
pdf.addImage(file, 'PNG', 0, 0, pdfWidth, pdfHeight);
pdf.save('map.pdf');
} else {
const link = document.createElement('a');
link.setAttribute('href', file);
link.setAttribute('download', `map.${ext}`);
link.click();
}
setOpen(false);
handleClose();
}
};
return (
<Grid item>
<Button variant="contained" color="primary" onClick={handleClick}>
<CloudDownload fontSize="small" />
<Hidden smDown>
<Typography className={classes.label} variant="body2">
{t('Export')}
</Typography>
</Hidden>
<ArrowDropDown fontSize="small" />
</Button>
<ExportMenu
id="export-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleClose}
>
<ExportMenuItem onClick={openModal}>
<ListItemIcon>
<Image fontSize="small" style={{ color: 'white' }} />
</ListItemIcon>
<ListItemText primary={t('IMAGE')} />
</ExportMenuItem>
</ExportMenu>
<Dialog
maxWidth="xl"
open={open}
keepMounted
onClose={() => setOpen(false)}
aria-labelledby="dialog-preview"
>
<DialogTitle className={classes.title} id="dialog-preview">
{t('Map Preview')}
</DialogTitle>
<DialogContent>
<canvas ref={previewRef} />
</DialogContent>
<DialogActions>
<Button onClick={() => setOpen(false)} color="primary">
{t('Cancel')}
</Button>
<Button
variant="contained"
onClick={() => download('png')}
color="primary"
>
{t('Download PNG')}
</Button>
<Button
variant="contained"
onClick={() => download('jpeg')}
color="primary"
>
{t('Download JPEG')}
</Button>
<Button
variant="contained"
onClick={() => download('pdf')}
color="primary"
>
{t('Download PDF')}
</Button>
</DialogActions>
</Dialog>
</Grid>
);
}
Example #21
Source File: SideDrawer.tsx From glific-frontend with GNU Affero General Public License v3.0 | 4 votes |
SideDrawer: React.SFC<SideDrawerProps> = () => {
const location = useLocation();
const { drawerOpen, setDrawerOpen } = useContext(SideDrawerContext);
const classes = useStyles();
const [mobileOpen, setMobileOpen] = useState(false);
const { t } = useTranslation();
const { provider } = useContext(ProviderContext);
const drawer = (
<div>
<Toolbar className={classes.anotherToolBar}>
{drawerOpen ? (
<div className={classes.outerBox}>
<ThemeProvider theme={themeUI}>
<Typography variant="h6" className={classes.title}>
<img src={GlificLogo} className={styles.GlificLogo} alt="Glific" />
</Typography>
</ThemeProvider>
<IconButton
className={classes.iconButton}
onClick={() => setDrawerOpen(false)}
data-testid="drawer-button"
>
<MenuIcon />
</IconButton>
</div>
) : (
<IconButton
color="inherit"
aria-label="open drawer"
data-testid="drawer-button-closed"
style={{ margin: 'auto' }}
onClick={() => setDrawerOpen(true)}
>
<MenuIcon />
</IconButton>
)}
</Toolbar>
<SideMenus opened={drawerOpen} />
</div>
);
const container = window !== undefined ? () => window.document.body : undefined;
let settingMenu;
const userRolePermissions = getUserRolePermissions();
if (userRolePermissions.accessSettings) {
settingMenu = (
<div>
<Tooltip title={t('Settings')} placement="top">
<Link to="/settings">
<IconButton data-testid="settingsMenu">
<img
src={location.pathname === '/settings' ? ActiveIcon : InactiveIcon}
className={styles.UserIcon}
alt="settings"
/>
</IconButton>
</Link>
</Tooltip>
</div>
);
}
// set the appropriate classes to display bottom menus correctly
const bottonMenuClasses = [classes.BottomMenus];
if (provider === GUPSHUP_ENTERPRISE_SHORTCODE) {
bottonMenuClasses.unshift(classes.BottomMenusWithoutWallet);
}
if (!drawerOpen) {
bottonMenuClasses.unshift(classes.BottomMenusVertical);
}
return (
<nav
className={clsx({
[classes.drawer]: drawerOpen,
[classes.navClose]: !drawerOpen,
})}
aria-label="navigation menus"
data-testid="navbar"
>
<Hidden smUp implementation="css">
<Drawer
container={container}
variant="temporary"
anchor={themeUI.direction === 'rtl' ? 'right' : 'left'}
open={mobileOpen}
onClose={() => {
setMobileOpen(!mobileOpen);
}}
classes={{
paper: classes.drawerPaper,
}}
ModalProps={{
keepMounted: true,
}}
>
{drawer}
</Drawer>
</Hidden>
<Drawer
className={clsx(classes.drawer, {
[classes.drawerOpen]: drawerOpen,
[classes.drawerClose]: !drawerOpen,
})}
classes={{
paper: clsx({
[classes.drawerOpen]: drawerOpen,
[classes.drawerClose]: !drawerOpen,
}),
}}
variant="permanent"
>
<div className={bottonMenuClasses.join(' ')}>
{settingMenu}
<div>
<Menu
menus={getStaffManagementMenus()}
eventType="MouseEnter"
placement={drawerOpen ? 'top' : 'right-end'}
>
<IconButton data-testid="staffManagementMenu">
<img
src={
[
'/collection',
'/staff-management',
'/blocked-contacts',
'/consulting-hours',
].includes(location.pathname)
? ActiveStaffIcon
: InactiveStaffIcon
}
className={styles.StaffIcon}
alt="staff icon"
/>
</IconButton>
</Menu>
</div>
<div>
<Menu
menus={getUserAccountMenus()}
eventType="MouseEnter"
placement={drawerOpen ? 'top' : 'right-end'}
>
<IconButton data-testid="profileMenu">
<img
src={location.pathname === '/user-profile' ? ActiveUserIcon : InactiveUserIcon}
className={styles.UserIcon}
alt="user icon"
/>
</IconButton>
</Menu>
</div>
</div>
{drawer}
<WalletBalance fullOpen={drawerOpen} />
</Drawer>
</nav>
);
}
Example #22
Source File: index.tsx From aqualink-app with MIT License | 4 votes |
PointSelector = ({
siteId,
pointOptions,
point,
pointId,
editSurveyPointNameDraft,
isSiteAdmin,
editSurveyPointNameLoading,
onChangeSurveyPointName,
handlePointChange,
enableeditSurveyPointName,
disableeditSurveyPointName,
submitSurveyPointNameUpdate,
onDeleteButtonClick,
}: PointSelectorProps) => {
const classes = useStyles();
const [editDialogOpen, setEditDialogOpen] = useState(false);
const [editSurveyPoint, seteditSurveyPoint] = useState<SurveyPoints>();
const errored =
!editSurveyPointNameDraft ||
editSurveyPointNameDraft.length > maxLengths.SURVEY_POINT_NAME;
const onEditDialogClose = () => {
disableeditSurveyPointName();
seteditSurveyPoint(undefined);
setEditDialogOpen(false);
};
const onEditSurveyPointSubmit = () => {
if (editSurveyPoint) {
submitSurveyPointNameUpdate(editSurveyPoint.id);
}
};
const getHelperText = () => {
switch (true) {
case !editSurveyPointNameDraft:
return "Cannot be empty";
case editSurveyPointNameDraft &&
editSurveyPointNameDraft.length > maxLengths.SURVEY_POINT_NAME:
return `Must not exceed ${maxLengths.SURVEY_POINT_NAME} characters`;
default:
return "";
}
};
useEffect(() => {
if (!editSurveyPointNameLoading) {
seteditSurveyPoint(undefined);
setEditDialogOpen(false);
}
}, [editSurveyPointNameLoading]);
const editDialogActions: Action[] = [
{
size: "small",
variant: "contained",
color: "secondary",
text: "Close",
action: onEditDialogClose,
},
{
size: "small",
variant: "contained",
color: "primary",
text: editSurveyPointNameLoading ? "Updating..." : "Save",
action: onEditSurveyPointSubmit,
disabled: editSurveyPointNameLoading || (editSurveyPoint && errored),
},
];
return (
<>
{editSurveyPoint && (
<EditDialog
actions={editDialogActions}
open={editDialogOpen}
header={editSurveyPoint.name || ""}
onClose={onEditDialogClose}
content={
<TextField
variant="outlined"
autoFocus
className={classes.editSurveyPointTextField}
fullWidth
value={editSurveyPointNameDraft}
onChange={onChangeSurveyPointName}
error={errored}
helperText={getHelperText()}
/>
}
/>
)}
<Grid container alignItems="center" item md={12} lg={5} spacing={1}>
<Grid item>
<Typography variant="h6" className={classes.subTitle}>
Survey Point:
</Typography>
</Grid>
<Grid item className={classes.selectorWrapper}>
<Grid container alignItems="center">
<Grid item>
<Select
className={classes.selector}
labelId="survey-point"
id="survey-point"
name="survey-point"
value={
pointOptions.some((item) => item.name === point)
? point
: "All"
}
onChange={handlePointChange}
onClose={() => disableeditSurveyPointName()}
renderValue={(selected) => selected as string}
>
<MenuItem value="All">
<Typography className={classes.menuItem} variant="h6">
All
</Typography>
</MenuItem>
{pointOptions.map(
(item) =>
item.name !== null && (
<MenuItem
className={classes.menuItem}
value={item.name}
key={item.id}
>
<Grid
container
alignItems="center"
justify="space-between"
spacing={1}
>
<Grid className={classes.itemName} item>
{item.name}
</Grid>
<Grid item>
<Grid container item spacing={1}>
<Grid item>
<CustomLink
to={`/sites/${siteId}/points/${item.id}`}
isIcon
tooltipTitle="View survey point"
/>
</Grid>
{isSiteAdmin && (
<>
<Grid item>
<Tooltip
title="Edit survey point name"
placement="top"
arrow
>
<IconButton
className={classes.menuButton}
onClick={(event) => {
enableeditSurveyPointName(item.id);
setEditDialogOpen(true);
seteditSurveyPoint(item);
event.stopPropagation();
}}
>
<Create color="primary" />
</IconButton>
</Tooltip>
</Grid>
<Grid item>
<Tooltip
title="Delete survey point"
placement="top"
arrow
>
<IconButton
className={classes.menuButton}
onClick={(event) => {
onDeleteButtonClick(item.id);
event.stopPropagation();
}}
>
<DeleteOutline color="primary" />
</IconButton>
</Tooltip>
</Grid>
</>
)}
</Grid>
</Grid>
</Grid>
</MenuItem>
)
)}
</Select>
</Grid>
{pointId !== -1 && (
<Grid item>
<Hidden smUp>
<CustomLink
to={`/sites/${siteId}/points/${pointId}`}
isIcon
tooltipTitle="View survey point"
/>
</Hidden>
<Hidden xsDown>
<Button
variant="outlined"
color="primary"
size="small"
component={Link}
to={`/sites/${siteId}/points/${pointId}`}
>
View Survey Point
</Button>
</Hidden>
</Grid>
)}
</Grid>
</Grid>
</Grid>
</>
);
}
Example #23
Source File: index.tsx From prism-frontend with MIT License | 4 votes |
function Legends({ classes, layers, extent }: LegendsProps) {
const [open, setOpen] = useState(true);
const isAnalysisLayerActive = useSelector(isAnalysisLayerActiveSelector);
const analysisResult = useSelector(analysisResultSelector);
const features = analysisResult?.featureCollection.features;
const hasData = features ? features.length > 0 : false;
const { t } = useSafeTranslation();
const handleAnalysisDownload = (e: React.ChangeEvent<{}>): void => {
e.preventDefault();
downloadToFile(
{
content: JSON.stringify(features),
isUrl: false,
},
analysisResult ? analysisResult.getTitle() : 'prism_extract',
'application/json',
);
};
const legendItems = [
...layers.map(layer => {
if (!layer.legend || !layer.legendText) {
// this layer doesn't have a legend (likely boundary), so lets ignore.
return null;
}
// If legend array is empty, we fetch from remote server the legend as GetLegendGraphic request.
const legendUrl =
layer.type === 'wms' && layer.legend.length === 0
? formatWMSLegendUrl(layer.baseUrl, layer.serverLayerName)
: undefined;
const exposure = GetExposureFromLayer(layer);
return (
<LegendItem
classes={classes}
key={layer.id}
id={layer.id}
title={layer.title ? t(layer.title) : undefined}
legend={layer.legend}
legendUrl={legendUrl}
type={layer.type}
opacity={layer.opacity}
exposure={exposure}
extent={extent}
>
{t(layer.legendText)}
</LegendItem>
);
}),
// add analysis legend item if layer is active and analysis result exists
...(isAnalysisLayerActive && hasData
? [
<LegendItem
key={analysisResult?.key}
legend={analysisResult?.legend}
title={analysisResult?.getTitle(t)}
classes={classes}
opacity={0.5} // TODO: initial opacity value
>
{analysisResult instanceof BaselineLayerResult && (
<LegendImpactResult result={analysisResult} />
)}
<Divider />
<Grid item>
<Button
variant="contained"
color="primary"
size="small"
onClick={e => handleAnalysisDownload(e)}
fullWidth
>
{t('Download')}
</Button>
</Grid>
</LegendItem>,
]
: []),
];
return (
<Grid item className={classes.container}>
<Button
variant="contained"
color="primary"
onClick={() => setOpen(!open)}
>
{open ? (
<VisibilityOff fontSize="small" />
) : (
<Visibility fontSize="small" />
)}
<Hidden smDown>
<Typography className={classes.label} variant="body2">
{t('Legend')}
</Typography>
</Hidden>
</Button>
{open && <List className={classes.list}>{legendItems}</List>}
</Grid>
);
}
Example #24
Source File: Site.tsx From clearflask with Apache License 2.0 | 4 votes |
render() {
const isSingleCustomer = detectEnv() === Environment.PRODUCTION_SELF_HOST;
if (isSingleCustomer) {
return (
<RedirectIso to='/login' />
);
}
const menuItemsLeft: Array<MenuButton | MenuDropdown> = [
{
type: 'dropdown', title: this.props.t('product'), items: [
{ type: 'button', link: '/product/demo', title: this.props.t('demo'), icon: DemoIcon },
{ type: 'divider' },
{ type: 'button', link: '/product/ask', title: this.props.t('collect-feedback'), icon: CollectIcon },
{ type: 'button', link: '/product/analyze', title: this.props.t('manage-and-analyze'), icon: AnalyzeIcon },
{ type: 'button', link: '/product/act', title: this.props.t('respond-and-inform'), icon: ActIcon },
{ type: 'divider' },
{ type: 'button', link: '/product/integrations', title: this.props.t('integrations') },
{ type: 'button', link: '/product/scale-with-us', title: this.props.t('scale-with-us') },
{ type: 'divider' },
{ type: 'button', link: '/product/compare', title: this.props.t('competing-products'), icon: CompareIcon },
]
},
{ type: 'button', link: '/pricing', title: this.props.t('pricing') },
// TODO Needs a complete SEO revamp
// {
// type: 'dropdown', title: 'Solutions', items: [
// { type: 'button', link: '/solutions/feature-request-tracking', title: 'Feature Request Tracking', icon: RequestTrackingIcon },
// { type: 'button', link: '/solutions/product-roadmap', title: 'Product Roadmap', icon: RoadmapIcon, iconClassName: this.props.classes.roadmapIcon },
// // TODO Re-enable once Crowd-funding gets a revamp
// // import CrowdfundingIcon from '@material-ui/icons/MonetizationOn';
// // { type: 'button', link: '/solutions/feature-crowdfunding', title: 'Feature Crowdfunding', icon: CrowdfundingIcon },
// { type: 'divider' },
// { type: 'button', link: '/solutions/idea-management', title: 'Idea Management' },
// // TODO Re-enable once Crowd-funding gets a revamp
// // { type: 'button', link: '/solutions/content-creator-forum', title: 'Content Creator Forum' },
// { type: 'button', link: '/solutions/internal-feedback', title: 'Internal Feedback' },
// ]
// },
{
type: 'dropdown', title: this.props.t('resources'), items: [
{ type: 'button', link: `/open-source`, title: this.props.t('open-source'), icon: OpenSourceIcon },
{ type: 'button', link: '/roadmap', title: this.props.t('our-roadmap'), icon: RoadmapIcon, iconClassName: this.props.classes.roadmapIcon },
{ type: 'button', link: '/feedback', title: this.props.t('feedback'), icon: FeedbackIcon },
{ type: 'button', link: '/blog', title: this.props.t('blog'), icon: BlogIcon },
// { type: 'button', link: urlAddCfJwt(`${windowIso.location.protocol}//product.${windowIso.location.host}/blog`, this.props.account), linkIsExternal: true, title: 'Blog', icon: BlogIcon },
{ type: 'divider' },
{ type: 'button', link: urlAddCfJwt(`${windowIso.location.protocol}//product.${windowIso.location.host}/docs`, this.props.account), linkIsExternal: true, title: 'Docs', icon: DocsIcon },
{ type: 'button', link: `${windowIso.location.protocol}//${windowIso.location.host}/api`, linkIsExternal: true, title: 'API', icon: CodeIcon },
{ type: 'button', link: 'https://stats.uptimerobot.com/jM01vFY31w/', linkIsNewWindowNoFollow: true, title: 'Status', icon: StatusIcon },
]
},
];
const menuItemsRight: Array<MenuButton> = [
(!!this.props.account
? { type: 'button', link: '/dashboard', title: this.props.t('dashboard') }
: { type: 'button', link: '/login', title: this.props.t('log-in') }),
{ type: 'button', link: '/signup', title: this.props.t('get-started'), primary: true, },
];
const bottomNavigation: Array<MenuButton | MenuDropdown> = [
...menuItemsLeft,
{
type: 'dropdown', title: `© ${this.props.t('smotana')}`, items: [
{ type: 'button', link: 'https://smotana.com', linkIsExternal: true, title: 'Smotana.com' },
{ type: 'button', link: '/contact', title: this.props.t('contact') },
{ type: 'divider' },
{ type: 'button', link: '/signup', title: this.props.t('sign-up') },
{ type: 'button', link: '/dashboard', title: this.props.t('dashboard') },
{ type: 'divider' },
{ type: 'button', link: '/privacy-policy', title: this.props.t('privacy-policy') },
{ type: 'button', link: '/terms-of-service', title: this.props.t('terms-of-service') },
]
}
];
return (
<div className={this.props.classes.growAndFlex}>
<ClearFlaskEmbedHoverFeedback path='embed/feedback' Icon={FeedbackIcon} />
<AppBar position='fixed' color='inherit' elevation={0} variant='elevation' className={this.props.classes.appBar}>
<Container maxWidth='md' disableGutters>
<Toolbar className={this.props.classes.toolbar}>
<Hidden mdUp implementation='css'>
<IconButton
aria-label='Menu'
onClick={() => this.setState({ menuOpen: true })}
>
<MenuIcon />
</IconButton>
<Drawer
variant='temporary'
open={this.state.menuOpen}
onClose={() => this.setState({ menuOpen: false })}
ModalProps={{
keepMounted: true,
}}
classes={{ paper: this.props.classes.menuItemsDrawer }}
>
<MenuItems
items={[
{ type: 'header', title: 'ClearFlask' },
...menuItemsRight,
...menuItemsLeft]}
insideDrawer
onClick={() => this.setState({ menuOpen: false })}
/>
</Drawer>
</Hidden>
<Link to='/' className={this.props.classes.logoLink}>
<Logo />
</Link>
<Hidden smDown implementation='css'>
<div className={this.props.classes.menuItemsContainer}>
<MenuItems
items={menuItemsLeft}
/>
</div>
</Hidden>
<div className={this.props.classes.grow} />
<Hidden smDown implementation='css'>
<div className={this.props.classes.menuItemsContainer}>
<MenuItems
items={menuItemsRight}
/>
</div>
</Hidden>
<LanguageSelect />
</Toolbar>
</Container>
</AppBar>
<div className={this.props.classes.appBarSpacer} />
<div className={classNames(this.props.classes.growAndFlex, this.props.classes.page)}>
<MuiAnimatedSwitch>
<Route path='/contact'>
<SetTitle title={this.props.t('contact')} />
<ContactPage />
</Route>
<Route exact path='/sso-demo'>
<SetTitle title='Single Sign-On' />
<DemoOnboardingLogin type='sso' />
</Route>
<Route path='/oauth-demo'>
<SetTitle title='OAuth' />
<DemoOnboardingLogin type='oauth' />
</Route>
<Route exact path='/terms-of-service'>
<SetTitle title={this.props.t('terms-of-service')} />
<LegalPage type='terms' />
</Route>
<Route exact path='/(tos|terms)'>
<RedirectIso to='/terms-of-service' />
</Route>
<Route exact path='/privacy-policy'>
<SetTitle title={this.props.t('terms-of-service')} />
<LegalPage type='privacy' />
</Route>
<Route exact path='/(privacy|policy)'>
<RedirectIso to='/privacy-policy' />
</Route>
<Route exact path='/'>
<SetTitle />
<Landing />
</Route>
<Route exact path='/product/ask'>
<SetTitle title={this.props.t('ask-your-users')} />
<LandingCollectFeedback />
</Route>
<Route exact path='/product/analyze'>
<SetTitle title={this.props.t('analyze-feedback')} />
<LandingPrioritization />
</Route>
<Route exact path='/product/act'>
<SetTitle title={this.props.t('take-action')} />
<LandingEngagement />
</Route>
<Route exact path='/product/integrations'>
<SetTitle title={this.props.t('integrations')} />
<LandingIntegrations />
</Route>
<Route exact path='/product/compare'>
<SetTitle title='30+ Customer Feedback Tools comparison' />
<LandingCompare />
</Route>
<Route exact path='/product/scale-with-us'>
<SetTitle title='Scale with us' />
<LandingGrowWithUs />
</Route>
<Route exact path='/product/demo'>
<SetTitle title={this.props.t('demo')} />
<LandingDemo />
</Route>
<Route exact path='/solutions/feature-request-tracking'>
<SetTitle title={this.props.t('feature-request-tracking')} />
<LandingFeatureRequestTracking />
</Route>
<Route exact path='/solutions/product-roadmap'>
<SetTitle title={this.props.t('product-roadmap')} />
<LandingPublicRoadmap />
</Route>
<Route exact path='/solutions/feature-crowdfunding'>
<SetTitle title='Feature Crowdfunding' />
<LandingCrowdFunding />
</Route>
<Route exact path='/solutions/idea-management'>
<SetTitle title='Idea Management' />
<LandingIdeaManagement />
</Route>
<Route exact path='/solutions/content-creator-forum'>
<SetTitle title='Content Creator Forum' />
<LandingContentCreator />
</Route>
<Route exact path='/solutions/internal-feedback'>
<SetTitle title='Internal Feedback' />
<LandingInternalFeedback />
</Route>
<Route exact path='/open-source'>
<SetTitle title={this.props.t('open-source')} />
<LandingOpenSource />
</Route>
<Route exact path='/pricing'>
<SetTitle title={this.props.t('pricing')} />
<PricingPage />
</Route>
{!isProd() && (
<Route exact path='/promo'>
<SetTitle title='Promo' />
<LandingPromo />
</Route>
)}
<Route path='/(post|user|blog|feedback|roadmap|changelog|announcements|docs|account|issue|account|sso|oauth)'>
<App slug={`product.${windowIso.parentDomain}`} settings={{ forceEmbed: true }} />
</Route>
<Route path='/e'>
<LandingEmbedFeedbackPage browserPathPrefix='/e' embed />
</Route>
<RouteWithStatus httpCode={404} >
<SetTitle title={this.props.t('page-not-found')} />
<ErrorPage pageNotFound />
</RouteWithStatus>
</MuiAnimatedSwitch>
</div>
<div className={this.props.classes.bottomBar}>
<Container maxWidth='md' disableGutters>
<Grid container justify='center' alignContent='center' spacing={6}>
{bottomNavigation.map((item, index) => {
if (item.type === 'dropdown') {
return (
<Grid key={index} item xs={6} sm={3} md={3} lg={2}>
<div key='header' className={this.props.classes.bottomHeader}>{item.title}</div>
{item.items.map((subItem, subIndex) => {
switch (subItem.type) {
case 'header':
return (
<div key={subIndex} className={this.props.classes.bottomHeader}>{subItem.title}</div>
);
case 'button':
if (subItem['linkIsExternal'] !== undefined) {
return (<MuiLink key={subIndex} href={subItem['link']} className={this.props.classes.bottomItem} underline='none'>{subItem.title}</MuiLink>);
} else if (subItem['linkIsNewWindowNoFollow'] !== undefined) {
return (<MuiLink key={subIndex} href={subItem['link']} target='_blank' rel='noopener nofollow' className={this.props.classes.bottomItem} underline='none'>{subItem.title}</MuiLink>);
} else if (subItem['link'] !== undefined) {
return (<NavLink key={subIndex} to={subItem['link']} className={this.props.classes.bottomItem}>{subItem.title}</NavLink>);
} else {
return (<MuiLink key={subIndex} onClick={subItem['onClick']} className={this.props.classes.bottomItem} underline='none'>{subItem.title}</MuiLink>);
}
case 'divider':
return (
<div className={this.props.classes.bottomNavigationDivider} />
);
default:
return null;
}
})}
</Grid>
);
}
return null;
})}
</Grid>
</Container>
</div>
</div >
);
}
Example #25
Source File: index.tsx From prism-frontend with MIT License | 4 votes |
function NavBar({ classes }: NavBarProps) {
const { t } = useSafeTranslation();
const rightSideLinks = [
{
title: t('about'),
icon: faInfoCircle,
href: 'https://innovation.wfp.org/project/prism',
},
{
title: 'GitHub',
icon: faGithub,
href: 'https://github.com/oviohub/prism-frontend',
},
];
const [openMobileMenu, setOpenMobileMenu] = useState(false);
const menu = menuList.map(({ title, ...category }) => (
<MenuItem key={title} title={title} {...category} />
));
// menu for mobile, 1 active accordion at a time so I put the state in here
const [expanded, setExpanded] = useState('');
const selectAccordion = (title: string) => {
setExpanded(title);
};
const menuMobile = menuList.map(({ title, ...category }) => (
<MenuItemMobile
expanded={expanded}
selectAccordion={selectAccordion}
key={title}
title={title}
{...category}
/>
));
const buttons = rightSideLinks.map(({ title, icon, href }) => (
<Grid item key={title}>
<Typography
variant="body2"
component="a"
target="_blank"
href={href}
onClick={() => setOpenMobileMenu(false)}
>
<FontAwesomeIcon icon={icon} /> {title}
</Typography>
</Grid>
));
return (
<AppBar position="static" className={classes.appBar}>
<Toolbar variant="dense">
<Grid container>
<Grid item xs={3} className={classes.logoContainer}>
<Typography
variant="h6"
className={classes.logo}
component={Link}
to="/"
>
{t('Prism')}
</Typography>
</Grid>
<Hidden smDown>
<Grid className={classes.menuContainer} item xs={6}>
{menu}
</Grid>
<Grid
spacing={3}
container
justify="flex-end"
alignItems="center"
item
xs={3}
>
{buttons}
<LanguageSelector />
</Grid>
</Hidden>
<Hidden mdUp>
<Grid item xs={9} className={classes.mobileMenuContainer}>
<Button
onClick={() => setOpenMobileMenu(prevOpen => !prevOpen)}
aria-controls={openMobileMenu ? 'mobile-menu-list' : undefined}
aria-haspopup="true"
className={classes.menuBars}
>
<FontAwesomeIcon icon={faBars} />
</Button>
<Drawer
anchor="right"
open={openMobileMenu}
onClose={() => setOpenMobileMenu(false)}
>
<div className={classes.mobileDrawerContent}>
<Grid container spacing={3}>
<Grid container justify="space-around" item>
{buttons}
</Grid>
<Grid container direction="column" item>
{menuMobile}
</Grid>
</Grid>
</div>
</Drawer>
</Grid>
</Hidden>
</Grid>
</Toolbar>
</AppBar>
);
}
Example #26
Source File: index.tsx From aqualink-app with MIT License | 4 votes |
SiteTable = ({
isDrawerOpen,
showCard,
showSpottersOnlySwitch,
isExtended,
collection,
scrollTableOnSelection,
scrollPageOnSelection,
classes,
}: SiteTableProps) => {
const loading = useSelector(sitesListLoadingSelector);
const siteOnMap = useSelector(siteOnMapSelector);
const withSpotterOnly = useSelector(withSpotterOnlySelector);
const dispatch = useDispatch();
const { height } = useWindowSize() || {};
const [order, setOrder] = useState<Order>("desc");
const [orderBy, setOrderBy] = useState<OrderKeys>(OrderKeys.ALERT);
const handleRequestSort = (event: unknown, property: OrderKeys) => {
const isAsc = orderBy === property && order === "asc";
setOrder(isAsc ? "desc" : "asc");
setOrderBy(property);
};
const toggleSwitch = (event: ChangeEvent<HTMLInputElement>) => {
const {
target: { checked },
} = event;
dispatch(filterSitesWithSpotter(checked));
dispatch(setWithSpotterOnly(checked));
};
// This function is used to prevent the drawer onClick close effect on mobile
const onInteractiveClick = (
event: React.MouseEvent<HTMLButtonElement, MouseEvent>
) => {
event.stopPropagation();
};
const onMobileSelectChange: SelectProps["onChange"] = (newValue) => {
const value = newValue.target.value as string;
const [newOrderBy, newOrder] = value.split("-") as [OrderKeys, Order];
setOrder(newOrder);
setOrderBy(newOrderBy);
};
return (
<>
{/* Holds drawer handle and site name text on mobile */}
{showCard && (
<Hidden mdUp>
<Box
width="100vw"
display="flex"
justifyContent="center"
marginTop={2}
marginBottom={3}
>
<Box
className={classNames(classes.topHandle, {
[classes.bounce]: !!siteOnMap && !isDrawerOpen,
})}
/>
{!isDrawerOpen && (
<Typography
className={classes.allSitesText}
variant="h5"
color="textSecondary"
>
{siteOnMap ? getSiteNameAndRegion(siteOnMap).name : "All Sites"}
</Typography>
)}
</Box>
</Hidden>
)}
{showCard && <SelectedSiteCard />}
{showSpottersOnlySwitch && (
<Box className={classes.switchWrapper}>
<Switch
checked={withSpotterOnly}
onClick={onInteractiveClick}
onChange={toggleSwitch}
color="primary"
/>
<Typography color="textSecondary" variant="h6">
deployed buoys only
</Typography>
</Box>
)}
{/* Holds sort selector on mobile. Sorting on desktop uses table headers. */}
{!isExtended && (
<Hidden mdUp>
<Box
paddingX={2}
paddingY={3}
display="flex"
alignItems="center"
onClick={onInteractiveClick}
>
<Typography variant="h5">Sort By: </Typography>
<Select
value={`${orderBy}-${order}`}
className={classes.mobileSortSelect}
onChange={onMobileSelectChange}
>
{MOBILE_SELECT_MENU_ITEMS}
</Select>
</Box>
</Hidden>
)}
<Box
className={
height && height > SMALL_HEIGHT
? `${classes.tableHolder} ${classes.scrollable}`
: `${classes.tableHolder}`
}
display="flex"
flexDirection="column"
flex={1}
>
<TableContainer>
<Table
stickyHeader
className={isExtended ? classes.extendedTable : classes.table}
>
<Hidden smDown={!isExtended}>
<EnhancedTableHead
order={order}
orderBy={orderBy}
onRequestSort={handleRequestSort}
isExtended={isExtended}
/>
</Hidden>
<SiteTableBody
order={order}
orderBy={orderBy}
isExtended={isExtended}
collection={collection}
scrollTableOnSelection={scrollTableOnSelection}
scrollPageOnSelection={scrollPageOnSelection}
/>
</Table>
</TableContainer>
{loading && (
<Box
display="flex"
flex={1}
alignItems="center"
justifyContent="center"
>
<CircularProgress size="4rem" thickness={1} />
</Box>
)}
</Box>
</>
);
}
Example #27
Source File: CardContent.tsx From aqualink-app with MIT License | 4 votes |
SelectedSiteCardContent = ({
site,
loading,
error,
imageUrl = null,
}: SelectedSiteCardContentProps) => {
const classes = useStyles({ imageUrl, loading });
const theme = useTheme();
const isTablet = useMediaQuery(theme.breakpoints.down("sm"));
const sortedDailyData = sortByDate(site?.dailyData || [], "date");
const dailyDataLen = sortedDailyData.length;
const { maxBottomTemperature, satelliteTemperature, degreeHeatingDays } =
(dailyDataLen && sortedDailyData[dailyDataLen - 1]) || {};
const useCardWithImageLayout = Boolean(loading || imageUrl);
const metrics = [
{
label: "SURFACE TEMP",
value: formatNumber(satelliteTemperature, 1),
unit: " °C",
display: isNumber(satelliteTemperature),
},
{
label: "HEAT STRESS",
value: formatNumber(degreeHeatingWeeksCalculator(degreeHeatingDays), 1),
unit: " DHW",
display: isNumber(degreeHeatingDays),
},
{
label: `TEMP AT ${site?.depth}m`,
value: formatNumber(maxBottomTemperature, 1),
unit: " °C",
display: isNumber(maxBottomTemperature) && isNumber(site?.depth),
},
];
const { name, region: regionName } = site
? getSiteNameAndRegion(site)
: { name: null, region: null };
const chartDataset = site
? standardDailyDataDataset(
site.dailyData,
site.maxMonthlyMean,
false,
site.timezone
)
: undefined;
const ChartComponent =
site && chartDataset ? (
<Chart
siteId={site.id}
datasets={[chartDataset]}
surveys={[]}
temperatureThreshold={
site.maxMonthlyMean ? site.maxMonthlyMean + 1 : null
}
maxMonthlyMean={site.maxMonthlyMean || null}
background
/>
) : null;
const onExploreButtonClick = () => {
trackButtonClick(
GaCategory.BUTTON_CLICK,
GaAction.MAP_PAGE_BUTTON_CLICK,
"Explore"
);
};
if (error) {
return <Alert severity="error">{error}</Alert>;
}
if (!loading && !site) {
return <Alert severity="error">Featured site is not available</Alert>;
}
return (
<Grid
className={classes.cardWrapper}
container
justify="space-between"
spacing={1}
>
{useCardWithImageLayout && (
<Grid item xs={12} md={6} lg={4}>
<Box position="relative" height="100%" minHeight={300}>
<LoadingSkeleton
className={classes.imageBorderRadius}
image={featuredImageLoading}
loading={loading}
variant="rect"
height="100%"
>
{site && imageUrl && (
<Link to={`/sites/${site.id}`}>
<CardMedia
className={classNames(
classes.cardImage,
classes.imageBorderRadius
)}
image={imageUrl}
/>
</Link>
)}
<Hidden mdUp>
<Box
bgcolor="rgba(3, 48, 66, 0.75)"
height="55%"
width="100%"
position="absolute"
top={0}
left={0}
>
<Box className={classes.cardImageTextWrapper}>
<Typography variant="h5">{name}</Typography>
{regionName && (
<Typography variant="h6">{regionName}</Typography>
)}
</Box>
</Box>
</Hidden>
{site && (
<Box position="absolute" bottom={16} px={2} width="100%">
<Grid
container
alignItems="center"
justify={
site.videoStream && isTablet
? "space-between"
: "flex-end"
}
>
{site.videoStream && isTablet && (
<Chip
live
liveText="LIVE VIDEO"
to={`/sites/${site.id}`}
width={80}
/>
)}
<Grid item>
<Button
className={classes.exporeButton}
component={Link}
to={`/sites/${site.id}`}
onClick={onExploreButtonClick}
size="small"
variant="contained"
color="primary"
>
EXPLORE
</Button>
</Grid>
</Grid>
</Box>
)}
</LoadingSkeleton>
</Box>
</Grid>
)}
<Grid
item
xs={12}
md={useCardWithImageLayout ? 6 : 12}
lg={useCardWithImageLayout ? 6 : 10}
className={classes.cardAnalyticsWrapper}
>
<Box pb="0.5rem" pl="0.5rem" pt="1.5rem" fontWeight={400}>
<Hidden smDown={useCardWithImageLayout}>
<LoadingSkeleton
loading={loading}
variant="text"
lines={1}
textHeight={28}
longText
>
<Grid container alignItems="center">
<Grid item className={classes.cardTitleWrapper}>
<Typography
className={classes.cardTitle}
color="textSecondary"
variant="h5"
>
<span title={name || ""}>{name}</span>
</Typography>
</Grid>
{site?.videoStream && (
<Chip
live
liveText="LIVE VIDEO"
to={`/sites/${site.id}`}
width={80}
/>
)}
</Grid>
</LoadingSkeleton>
<LoadingSkeleton
loading={loading}
variant="text"
lines={1}
textHeight={19}
className={classes.siteRegionName}
>
<Typography
color="textSecondary"
variant="h6"
className={classNames(
classes.cardTitle,
classes.siteRegionName
)}
>
<span title={regionName || ""}>{regionName}</span>
</Typography>
</LoadingSkeleton>
</Hidden>
<LoadingSkeleton
loading={loading}
variant="text"
lines={1}
textHeight={12}
>
<Typography color="textSecondary" variant="caption">
DAILY SURFACE TEMP. (°C)
</Typography>
</LoadingSkeleton>
</Box>
<Hidden smDown>
<LoadingSkeleton
image={chartLoading}
loading={loading}
variant="rect"
width="98%"
height={180}
>
<div>{ChartComponent}</div>
</LoadingSkeleton>
</Hidden>
<Hidden mdUp>
<LoadingSkeleton
className={classes.mobileChartLoading}
image={chartLoading}
loading={loading}
variant="rect"
width="98%"
height={200}
>
{ChartComponent}
</LoadingSkeleton>
</Hidden>
</Grid>
<Grid item xs={12} lg={2} container>
<div className={classes.metricsContainer}>
{metrics.map(({ label, value, unit, display }) => (
<div key={label} className={classes.metric}>
<LoadingSkeleton
longText
loading={loading}
variant="text"
lines={1}
textHeight={12}
>
{display && (
<Typography variant="caption" color="textSecondary">
{label}
</Typography>
)}
</LoadingSkeleton>
<LoadingSkeleton
loading={loading}
variant="rect"
width={80}
height={32}
>
{display && (
<Typography variant="h4" color="primary">
{value}
<Typography variant="h6" component="span">
{unit}
</Typography>
</Typography>
)}
</LoadingSkeleton>
</div>
))}
</div>
</Grid>
</Grid>
);
}
Example #28
Source File: index.tsx From aqualink-app with MIT License | 4 votes |
NavBar = ({
searchLocation,
geocodingEnabled,
routeButtons,
loading,
classes,
}: NavBarProps) => {
const user = useSelector(userInfoSelector);
const storedCollection = useSelector(collectionDetailsSelector);
const dispatch = useDispatch();
const theme = useTheme();
const isTablet = useMediaQuery(theme.breakpoints.up("md"));
const [registerDialogOpen, setRegisterDialogOpen] = useState<boolean>(false);
const [signInDialogOpen, setSignInDialogOpen] = useState<boolean>(false);
const [menuDrawerOpen, setMenuDrawerOpen] = useState<boolean>(false);
const [anchorEl, setAnchorEl] = React.useState<HTMLElement | null>(null);
const handleRegisterDialog = (open: boolean) => setRegisterDialogOpen(open);
const handleSignInDialog = (open: boolean) => setSignInDialogOpen(open);
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
setAnchorEl(event.currentTarget);
};
const handleMenuClose = () => {
setAnchorEl(null);
};
const onUserSignOut = () => {
// Clear collection if it belongs to the signed in user
if (storedCollection?.id === user?.collection?.id) {
dispatch(clearCollection());
}
dispatch(signOutUser());
handleMenuClose();
};
const onSiteChange = () => {
dispatch(unsetSelectedSite());
dispatch(unsetLiveData());
dispatch(unsetLatestData());
};
return (
<>
<AppBar
className={classNames(classes.appBar, {
[classes.appBarXs]: searchLocation,
})}
position="static"
color="primary"
>
<Toolbar className={classes.toolbar}>
<MenuDrawer
open={menuDrawerOpen}
onClose={() => setMenuDrawerOpen(false)}
/>
<Grid
container
justify="space-between"
alignItems="center"
spacing={1}
>
<Grid
item
xs={5}
sm={2}
// eslint-disable-next-line no-nested-ternary
md={routeButtons ? 2 : searchLocation ? 6 : 4}
>
<Box display="flex" flexWrap="nowrap" alignItems="center">
<IconButton
edge="start"
color="inherit"
onClick={() => setMenuDrawerOpen(true)}
>
<MenuIcon />
</IconButton>
<MuiLink className={classes.navBarLink} href="/map">
<Typography color="textPrimary" variant="h4">
Aqua
</Typography>
<Typography style={{ color: "#8AC6DE" }} variant="h4">
link
</Typography>
</MuiLink>
</Box>
</Grid>
{searchLocation && (
<Hidden xsDown>
<Grid item sm={4} md={3}>
<Search geocodingEnabled={geocodingEnabled} />
</Grid>
</Hidden>
)}
{routeButtons && isTablet && <RouteButtons />}
<Grid
container
justify="flex-end"
item
xs={7}
sm={routeButtons && isTablet ? 3 : 4}
md={searchLocation || (routeButtons && isTablet) ? 3 : 8}
>
{user ? (
<>
<Box display="flex" flexWrap="nowrap" alignItems="center">
{user.fullName ? user.fullName : "My Profile"}
<IconButton
className={classes.button}
onClick={handleClick}
>
<ExpandMoreIcon className={classes.expandIcon} />
</IconButton>
<Menu
key="user-menu"
className={classes.userMenu}
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleMenuClose}
MenuListProps={{ className: classes.userMenu }}
PopoverClasses={{ paper: classes.userMenuWrapper }}
>
{sortBy(user.administeredSites, "id").map(
({ id, name, region }, index) => {
const siteIdentifier = name || region;
return (
<Link
to={`/sites/${id}`}
key={`site-link-${id}`}
className={classes.menuItemLink}
>
<MenuItem
onClick={() => onSiteChange()}
className={classes.menuItem}
>
{siteIdentifier || `Site ${index + 1}`}
</MenuItem>
</Link>
);
}
)}
<Divider className={classes.userMenuDivider} />
<Link to="/dashboard" className={classes.menuItemLink}>
<MenuItem
key="user-menu-dashboard"
className={classes.menuItem}
>
<Grid container spacing={1}>
<Grid item>
<DashboardTwoToneIcon fontSize="small" />
</Grid>
<Grid item>Dashboard</Grid>
</Grid>
</MenuItem>
</Link>
<Divider className={classes.userMenuDivider} />
<MenuItem
key="user-menu-logout"
className={classes.menuItem}
onClick={onUserSignOut}
>
<Grid container spacing={1}>
<Grid item>
<PowerSettingsNewIcon fontSize="small" />
</Grid>
<Grid item>Logout</Grid>
</Grid>
</MenuItem>
</Menu>
</Box>
</>
) : (
<>
<Grid item>
<Button onClick={() => handleSignInDialog(true)}>
SIGN IN
</Button>
</Grid>
<Grid item>
<Button onClick={() => handleRegisterDialog(true)}>
SIGN UP
</Button>
</Grid>
</>
)}
</Grid>
{searchLocation && (
<Hidden smUp>
<Grid item xs={12} style={{ margin: 0, paddingTop: 0 }}>
<Search geocodingEnabled={geocodingEnabled} />
</Grid>
</Hidden>
)}
</Grid>
</Toolbar>
</AppBar>
{loading && <LinearProgress />}
<RegisterDialog
open={registerDialogOpen}
handleRegisterOpen={handleRegisterDialog}
handleSignInOpen={handleSignInDialog}
/>
<SignInDialog
open={signInDialogOpen}
handleRegisterOpen={handleRegisterDialog}
handleSignInOpen={handleSignInDialog}
/>
</>
);
}