@material-ui/core#Zoom JavaScript Examples
The following examples show how to use
@material-ui/core#Zoom.
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: SocialIcons.js From personal-website-react with MIT License | 6 votes |
SocialIcons = () => {
const classes = useStyles();
const socialItems = Resume.basics.profiles.map((socialItem) => (
<Link
href={socialItem.url}
key={socialItem.network.toLowerCase()}
target='_blank'
rel='noopener noreferrer'
underline='none'
color='inherit'
>
<Tooltip
title={socialItem.username}
placement='left'
TransitionComponent={Zoom}
>
<IconButton
color='inherit'
aria-label={socialItem.network}
className={classes.iconButton}
>
<i className={`${classes.icon} ${socialItem.x_icon}`}></i>
</IconButton>
</Tooltip>
</Link>
));
return <div className={classes.socialIcons}>{socialItems}</div>;
}
Example #2
Source File: LogoLink.js From personal-website-react with MIT License | 6 votes |
LogoLink = () => {
const classes = useStyles();
return (
<Tooltip
title={Resume.basics.name}
placement="right"
TransitionComponent={Zoom}
>
<Link
variant="h6"
href={Resume.basics.url}
underline="none"
color="inherit"
noWrap
className={classes.svg}
>
<Logo />
</Link>
</Tooltip>
);
}
Example #3
Source File: ThemeToggle.js From personal-website-react with MIT License | 6 votes |
ThemeToggle = () => {
const { theme, toggleTheme } = useContext(ThemeContext);
const classes = useStyles();
return (
<Tooltip
title={"Toggle theme"}
placement="right"
TransitionComponent={Zoom}
>
<IconButton
color="inherit"
onClick={toggleTheme}
aria-label={"Toggle theme"}
className={classes.iconButton}
>
{theme === "light" ? (
<Brightness4 className={classes.icon} />
) : (
<Brightness7 className={classes.icon} />
)}
</IconButton>
</Tooltip>
);
}
Example #4
Source File: Lightbox.jsx From archeage-tools with The Unlicense | 6 votes |
render() {
const { image, title, caption, elevation, float } = this.props;
const { open } = this.state;
return (
<>
<Paper
className={cn('lightbox-thumb', { [float]: Boolean(float) })}
elevation={elevation}
>
<img src={image || NoImage} alt={title} onClick={this.handleOpen} />
<Typography variant="caption">{title}</Typography>
</Paper>
<Dialog
open={open}
onClose={this.handleClose}
maxWidth="xl"
TransitionComponent={Zoom}
>
<AppBar position="static">
<Toolbar variant="dense">
<Typography variant="subtitle1" className="title-text">{title}</Typography>
<IconButton color="inherit" aria-label="Close" onClick={this.handleClose}>
<CloseIcon />
</IconButton>
</Toolbar>
</AppBar>
<DialogContent>
<img src={image} alt={title} />
<Typography>{caption}</Typography>
</DialogContent>
</Dialog>
</>
);
}
Example #5
Source File: ScrollToTop.jsx From archeage-tools with The Unlicense | 6 votes |
render() {
const { scrollY, height } = this.state;
return (
<Zoom in={scrollY >= height * 0.5} unmountOnExit>
<Fab
color="primary"
className="fab"
onClick={this.handleClick}
>
<ExpandLessIcon />
</Fab>
</Zoom>
);
}
Example #6
Source File: index.js From News24x7-Client with MIT License | 6 votes |
// const NavButton = styled.button`
// align-content:center;
// color: ${colors.BASE_BLUE};
// background-color:white;
// margin-right:15px;
// `;
function ScrollTop(props) {
const { children } = props;
const classes = useStyles();
const trigger = useScrollTrigger({
disableHysteresis: true,
threshold: 100,
});
const handleClick = (event) => {
const anchor = (event.target.ownerDocument || document).querySelector(
"#back-to-top-anchor"
);
if (anchor) {
anchor.scrollIntoView({ behavior: "smooth", block: "center" });
}
};
return (
<Zoom in={trigger}>
<div onClick={handleClick} role="presentation" className={classes.root}>
{children}
</div>
</Zoom>
);
}
Example #7
Source File: Landing.js From Portfolio with MIT License | 5 votes |
export default function Landing() {
const classes = useStyles();
const theme = useTheme();
const mdDown = useMediaQuery(theme.breakpoints.down('sm'));
return (
<Grid container justify="center" alignItems="center" className={classes.cont}>
<Grid item xs={12} lg={6}>
<Typography variant={mdDown ? "h2" : "h1"}>
{landing.title}
</Typography>
<Typography variant={mdDown ? "h5" : "h4"} component="h2" className={classes.subtitle}>
<ReactTyped
strings={landing.subtitles}
typeSpeed={40}
backSpeed={50}
loop
/>
</Typography>
<Grid container direction="row" spacing={2}>
{
professionalDetails.map(({ alt, icon, link }, i) =>
<Grid item key={i}>
<a href={link} target="_blank" rel="noopener noreferrer">
<Zoom in={true} style={{ transitionDelay: `${100 * i}ms` }}>
<Tooltip title={alt} placement="top">
<Avatar variant="rounded" className={clsx([classes.avatar, classes[alt]])}>
{icon}
</Avatar>
</Tooltip>
</Zoom>
</a>
</Grid>
)
}
</Grid>
</Grid>
<Hidden mdDown>
<Fade in={true} style={{ transitionDelay: '100ms' }}>
<Grid item lg={6}>
<Image
src="/landing.svg"
alt="Landing"
width="900.94"
height="787"
/>
</Grid>
</Fade>
</Hidden>
</Grid>
)
}
Example #8
Source File: Skills.js From Portfolio with MIT License | 5 votes |
export default function Skills() {
const classes = useStyles()
const theme = useTheme()
const mdDown = useMediaQuery(theme.breakpoints.down('md'))
const align = mdDown ? "center" : "flex-end"
const textAlign = mdDown ? "center" : "right"
const animRef = useRef(null)
const animate = useAnimate(animRef)
return (
<Grid container justify="center" alignItems="center" spacing={10} className={classes.cont}>
<Grid item xs={12} lg={6} ref={animRef}>
<Typography variant="h2" gutterBottom align="center">
Skills
</Typography>
<Hidden mdDown>
<Fade in={animate} style={{ transitionDelay: '100ms' }}>
<div>
<Image
alt="Skills"
src="/skill.svg"
width="1139"
height="655"
/>
</div>
</Fade>
</Hidden>
</Grid>
<Grid container item xs={12} lg={6} direction="column" spacing={1} alignItems={align}>
{
Object.getOwnPropertyNames(wrappedSkills).map((title, id) =>
<Grid item key={id} className={classes.skobj}>
<Typography variant="h4" align={textAlign} gutterBottom component="p">
{title}
</Typography>
<Grid container item direction="row" spacing={1} justify="center">
{
wrappedSkills[title].map(({ alt, icon }, i) =>
<Grid item key={i}>
<Zoom in={animate} style={{ transitionDelay: `${150 * i}ms` }}>
<Tooltip title={alt.replace("_", " ")} placement="top">
<Avatar variant="rounded" className={clsx([classes.avatar, classes[alt]])}>
{icon}
</Avatar>
</Tooltip>
</Zoom>
</Grid>
)
}
</Grid>
</Grid>
)
}
</Grid>
</Grid>
)
}
Example #9
Source File: NewRequestPage.js From app with MIT License | 4 votes |
function NewRequestPage() {
const classes = useStyles();
const location = useLocation();
const qs = queryString.parse(location.search);
const defaultValues = {
needs: {},
immediacy: '1',
needFinancialAssistance: 'false',
};
// Append needs from query string type
if (qs && qs.type) {
defaultValues.needs = { [qs.type]: true };
}
const {
register,
handleSubmit,
errors,
watch,
control,
formState: { isValid, isSubmitting, dirty },
} = useForm({
validationSchema: requestValidationSchema,
defaultValues,
});
const {
submitRequest,
handleLocationChange,
requestLocation,
requestLocationLoading,
} = useNewRequestPage();
const currentNeeds = watch('needs');
const groceryPickup = currentNeeds && currentNeeds['grocery-pickup'];
return (
<Container maxWidth="md">
<Helmet>
<title>Request Assistance</title>
</Helmet>
<Typography variant="h5" color="textPrimary" gutterBottom>
Request Help
</Typography>
<Paper className={classes.paper} data-test="request-form">
<div className={classes.heroContent}>
<Container maxWidth="md">
<form onSubmit={handleSubmit(submitRequest)}>
<Container>
<FormGroup>
<Typography
variant="h5"
gutterBottom
className={classes.otherComments}>
What do you need help with?
</Typography>
{Object.keys(activeCategoryMap).map((optionKey) => (
<FormControlLabel
key={optionKey}
control={
<Checkbox
inputRef={register}
name={`needs.${optionKey}`}
data-test={`need-${optionKey}`}
defaultChecked={defaultValues.needs[optionKey]}
/>
}
label={
activeCategoryMap[optionKey].inputCaption
? activeCategoryMap[optionKey].inputCaption
: activeCategoryMap[optionKey].description
}
/>
))}
</FormGroup>
{!!errors.needs && (
<FormHelperText error>{errors.needs.message}</FormHelperText>
)}
<Typography
variant="h5"
className={classes.otherComments}
gutterBottom={!groceryPickup}>
Details
</Typography>
<Zoom in={groceryPickup} unmountOnExit>
<Typography variant="subtitle1" gutterBottom>
For grocery pickup, please provide the list of groceries
that you would like the volunteer to get. Please be as
specific as possible.
</Typography>
</Zoom>
<Grid container spacing={3}>
<Grid item xs={12}>
<TextField
name="otherDetails"
data-test="otherDetails"
multiline
placeholder="Please be as specific as possible."
fullWidth
rows="4"
variant="outlined"
inputRef={register}
/>
</Grid>
</Grid>
{/* <Zoom in={hasFinancialComponent} unmountOnExit> */}
<div>
<Divider className={classes.optionalDivider} />
<Typography variant="h5" gutterBottom>
Will you be able to pay for your items?
</Typography>
<Typography variant="body1" gutterBottom>
This service is free, but the items still cost money. Are
you able to pay for your items? If not, we will do our best
to match you with organizations and volunteers who can also
provide financial assistance.
</Typography>
<Controller
as={
<RadioGroup
aria-label="Need Financial Assistance"
component="fieldset">
<FormControlLabel
value="false"
control={<Radio />}
label="Yes, I can pay and only need help with the delivery."
/>
<FormControlLabel
value="true"
control={<Radio />}
label="No, I need help paying for the items."
/>
</RadioGroup>
}
control={control}
onChange={([event]) => event.target.value}
name="needFinancialAssistance"
/>
{!!errors.needFinancialAssistance && (
<FormHelperText error>
{errors.needFinancialAssistance}
</FormHelperText>
)}
</div>
{/* </Zoom> */}
<Divider className={classes.optionalDivider} />
<Typography variant="h5" gutterBottom>
Immediacy of Need
</Typography>
<Typography variant="body1" gutterBottom>
Please let us know how urgently you need us to fulfill the
request. We will do our best to connect you with a volunteer
as soon as possible, however, we cannot guarantee anything
because we are dependent on volunteer availability.
</Typography>
<Controller
as={
<RadioGroup>
<FormControlLabel
value="1"
control={<Radio />}
label="Low"
/>
<FormControlLabel
value="5"
control={<Radio />}
label="Medium - Not very urgent"
/>
<FormControlLabel
value="10"
control={<Radio />}
label="High - Urgent"
/>
</RadioGroup>
}
control={control}
name="immediacy"
/>
{!!errors.immediacy && (
<FormHelperText error>
{errors.immediacy.message}
</FormHelperText>
)}
<Divider className={classes.optionalDivider} />
<Typography variant="h5" gutterBottom>
Your Location
</Typography>
<Typography className={classes.intro}>
A rough location is needed to allow us to efficiently and
quickly find a match for your need. You can do this in three
ways: by entering your address in the address field, by
clicking the "Detect Location" button, or by
clicking on the map. If you decide to enter the address, we
will not save the actual address and instead use it to get the
location.
</Typography>
<Grid container spacing={3}>
<Grid item xs={12}>
<Card>
{requestLocationLoading ? (
<LoadingSpinner />
) : (
<ClickableMap
locationInfo={requestLocation}
onLocationChange={handleLocationChange}
/>
)}
</Card>
</Grid>
</Grid>
<Divider className={classes.optionalDivider} />
<Typography variant="h5" gutterBottom>
Contact Information
</Typography>
<Typography gutterBottom>
To minimize exposing your contact information, we do not
display it unless a volunteer specifically requests to see it.
To further discourage any abuse, we do not display your last
name and also keep track of all the volunteers who have looked
up your contact information.
</Typography>
<Grid container spacing={2}>
<Grid item xs={12} sm={6}>
<TextField
name="firstName"
data-test="firstName"
type="text"
label="First Name"
variant="outlined"
inputRef={register}
error={!!errors.firstName}
fullWidth
helperText={errors?.firstName?.message}
/>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
name="lastName"
data-test="lastName"
type="text"
label="Last Name"
variant="outlined"
fullWidth
inputRef={register}
error={!!errors.lastName}
helperText={errors?.firstName?.message}
/>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
name="phone"
data-test="phone"
type="text"
label="Phone Number"
variant="outlined"
fullWidth
inputRef={register}
error={!!errors.phone}
helperText={errors?.phone?.message}
/>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
name="email"
type="text"
data-test="email"
label="Email"
variant="outlined"
fullWidth
inputRef={register}
error={!!errors.email}
helperText={errors?.email?.message}
/>
</Grid>
</Grid>
<Typography className={classes.warrantyInfo}>
Note: This website and all related work products are provided
"AS IS". The provider of this service makes no other
warranties, express or implied, and hereby disclaims all
implied warranties, including any warranty of merchantability
and warranty of fitness for a particular purpose.
</Typography>
{dirty && !!Object.keys(errors).length && !isValid && (
<Typography variant="body2" className={classes.errorText}>
Please fix the errors above.
</Typography>
)}
<div className={classes.buttons}>
<Button
type="submit"
variant="contained"
color="primary"
data-test="submit-request"
disabled={isSubmitting}>
Submit Request
</Button>
</div>
</Container>
</form>
</Container>
</div>
</Paper>
</Container>
);
}
Example #10
Source File: Mounts.jsx From archeage-tools with The Unlicense | 4 votes |
render() {
const { search, mountType, obtainTypes, speed, order, orderBy } = this.state;
const {
match: { params: { mount } },
displayGrid,
setDisplayGrid,
onlyObtainable,
setOnlyObtainable,
mobile,
} = this.props;
const { mounts: mountData, types, mountObtainTypes } = this.props;
if (!mount) {
setTitle('Mounts');
}
const mounts = Object.entries(mountData).filter(([, mountList]) => {
const [mount] = mountList;
const mountObtain = MOUNT_OBTAIN.find(m => m.name === mount.name);
if (search.length > 2 && mount.name.toLowerCase().indexOf(search.toLowerCase()) === -1 && pathOr('', ['itemName'])(mountObtain).toLowerCase().indexOf(search.toLowerCase()) === -1) {
return false;
}
if (mountType > 0 && !mount.typeIds.includes(mountType)) {
return false;
}
if (obtainTypes.length && !mount.obtainIds.some(r => obtainTypes.includes(r))) {
return false;
}
if (speed > 0 && Number.parseFloat(mount.moveSpeed) !== Number.parseFloat(speed)) {
return false;
}
return !(onlyObtainable && mount.obtainIds.length === 0);
}).sort(([, x], [, y]) => {
const [a] = x;
const [b] = y;
if (displayGrid) {
if (a.moveSpeed === b.moveSpeed) {
return this.sort(a.name.toLowerCase(), b.name.toLowerCase());
} else {
if (a.moveSpeed === 0) return 1;
if (b.moveSpeed === 0) return -1;
return a.moveSpeed - b.moveSpeed;
}
} else {
const f = orderBy === 'name' ? 'moveSpeed' : 'name';
if (a[orderBy] === b[orderBy]) {
if (f === 'name') {
return this.sort(a.name.toLowerCase(), b.name.toLowerCase());
} else {
if (a[f] === 0) return 1;
if (b[f] === 0) return -1;
return a[f] - b[f];
}
} else {
let sort;
if (orderBy === 'name') {
sort = this.sort(a.name.toLowerCase(), b.name.toLowerCase());
} else if (a.moveSpeed === 0) {
sort = 1;
} else if (b.moveSpeed === 0) {
sort = -1;
} else {
sort = a.moveSpeed - b.moveSpeed;
}
return sort * (order !== 'asc' ? -1 : 1);
}
}
});
return (
<>
<Paper className="section">
<AppBar position="static">
<Toolbar>
<Typography variant="h5" className="title-text">Mounts</Typography>
<Tabs
value={Number(!displayGrid)}
indicatorColor="secondary"
onChange={(e, value) => setDisplayGrid(Boolean(!value))}
>
<Tooltip title="Grid View">
<Tab icon={<AppsIcon />} aria-label="grid" />
</Tooltip>
<Tooltip title="List View">
<Tab icon={<ListIcon />} aria-label="list" />
</Tooltip>
</Tabs>
</Toolbar>
</AppBar>
<div className="mount-filters">
<TextField
label="Search"
className="mount-search"
value={search}
onChange={this.setSearch}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<SearchIcon />
</InputAdornment>
),
endAdornment: (
<InputAdornment position="end">
<Tooltip title="Clear">
<CancelIcon className="clear-input" onClick={() => this.setSearch({ target: { value: '' } })} />
</Tooltip>
</InputAdornment>
),
}}
/>
<SelectField
id="mount-type"
label="Mount Type"
value={mountType}
options={{ 0: 'All', ...types }}
onChange={this.setType}
renderValue={(v) => (v === 0) ? 'All' : types[v]}
/>
<SelectField
id="mount-speed"
label="Base Speed"
value={speed}
options={this.speedTiers}
onChange={this.setSpeed}
controlClassName="small"
renderValue={(v) => this.speedTiers.get(v)}
/>
<FormControlLabel
control={
<Checkbox
checked={onlyObtainable}
onChange={(e, checked) => setOnlyObtainable(checked)}
color="primary"
/>
}
label="Obtainable Only"
/>
<div className="filter-field">
<InputLabel shrink style={{ marginBottom: 4 }}>Obtain By</InputLabel>
<ButtonGroup size="small">
{Object.values(mountObtainTypes).map(obtainBy => (
<Tooltip title={obtainBy.name} key={`obt-${obtainBy.id}`}>
<Button
variant={obtainTypes.includes(obtainBy.id) ? 'contained' : 'outlined'}
className={cn({ selected: obtainTypes.includes(obtainBy.id) })}
onClick={() => this.handleObtainChange(obtainBy.id)}
>
<span className={cn('dropdown-icon', obtainBy.icon)} />
</Button>
</Tooltip>
))}
</ButtonGroup>
</div>
</div>
</Paper>
{mobile &&
<AdContainer type="feed" />}
{displayGrid
? <div className="section">
<div className="mount-grid">
{mounts.map(([mountId, mountList]) => {
const [mount] = mountList;
return (
<Zoom in unmountOnExit key={mount.id}>
<Paper className="mount">
<Link to={`/mounts/${mountId}`}>
<div className="portrait">
<img
src={Portrait[pascalCase(mount.name)] || NoPortrait}
alt={mount.name}
/>
{mount.obtainIds.length > 0 &&
<div className="obtainables">
{mount.obtainIds.sort(sortNumber).map(obtainId => (
<Tooltip
title={mountObtainTypes[obtainId].name}
key={`${pascalCase(mountId)}-${obtainId}`}>
<span className={cn('dropdown-icon', mountObtainTypes[obtainId].icon)} />
</Tooltip>
))}
</div>}
<Typography className="name">{mount.name}</Typography>
<Typography className="speed" variant="caption">{mount.moveSpeed} m/s</Typography>
</div>
</Link>
</Paper>
</Zoom>
);
})}
</div>
{mounts.length === 0 &&
<Paper>
{!objectHasProperties(mountData)
? <CircularProgress color="primary" className="no-results" />
: <Typography className="no-results">
No mounts meet the criteria.
</Typography>
}
</Paper>}
</div>
: <Paper className="section mount-table">
<Table size="small">
<TableHead>
<TableRow>
<TableCell />
<TableCell>
<TableSortLabel
active={orderBy === 'name'}
direction={order}
onClick={this.handleSort('name')}
>
Name
</TableSortLabel>
</TableCell>
<TableCell>
<TableSortLabel
active={orderBy === 'moveSpeed'}
direction={order}
onClick={this.handleSort('moveSpeed')}
>
Speed
</TableSortLabel>
</TableCell>
<TableCell>Skills</TableCell>
<TableCell>Obtain By</TableCell>
</TableRow>
</TableHead>
<TableBody>
{mounts.map(([mountId, mountList]) => {
const [mount] = mountList;
return (
<TableRow key={mountId} onClick={() => this.props.history.push(`/mounts/${mountId}`)}>
<TableCell className="mount-icon">
<Tooltip
title={<img
src={Portrait[pascalCase(mount.name)] || NoPortrait}
alt={mount.name}
className="portrait-tooltip"
/>}
placement="right"
>
<img src={`/images/icon/${mount.icon}.png`} alt={mount.name} />
</Tooltip>
</TableCell>
<TableCell>
{mount.name}
</TableCell>
<TableCell>
{mount.moveSpeed} m/s
</TableCell>
<TableCell>
<div className="mount-skills">
{mount.skillIds.map(skillId => (
<SkillIcon key={`${mount.id}-${skillId}`} id={skillId} className="size-sm" />
))}
</div>
</TableCell>
<TableCell>
{mount.obtainIds.sort(sortNumber).map(obtainId => (
<Tooltip
title={mountObtainTypes[obtainId].name}
key={`${pascalCase(mountId)}-${obtainId}`}>
<span className={cn('dropdown-icon', mountObtainTypes[obtainId].icon)} />
</Tooltip>
))}
</TableCell>
</TableRow>
);
})}
{!objectHasProperties(mountData) &&
<TableRow className="no-results">
<TableCell colSpan="5" align="center">
{mountData.length === 0
? <CircularProgress color="primary" />
: 'No mounts meet the criteria.'
}
</TableCell>
</TableRow>}
</TableBody>
</Table>
</Paper>
}
<MountViewer
id={mount}
onClose={() => this.props.history.push('/mounts')}
/>
<AdContainer type="horizontal" />
</>
);
}
Example #11
Source File: SyntaxEditor.js From SyntaxMeets with MIT License | 4 votes |
SyntaxEditor = (props) => {
const [theme, setTheme] = useState("monokai");
const [popup, setPopup] = useState([false, ""]);
const [filePopup, setFilePopup] = useState(false);
const [fileHandleError, setFileHandleError] = useState("");
const [fullscreen,setFullscreen] = useState(false); // maintain state of screen in syntax Editor
const [modalIsOpen,setModalIsOpen] = useState(false)
const [shareURL,setshareURL] = useState("")
const [isLoading,setIsLoading]=useState(false)
// This will resend a message to update the code of the newly joined user
useEffect(() => {
let UpdatedCode = props.code;
if (props.previousUser.id === props.id) {
props.socket.emit("message", UpdatedCode);
}
// if the user was connected then over reloading the page this block is called
else if(sessionStorage.getItem('isconnected'))
{
//it used to save the code in sessionStorage when only one user is using there in a room
props.setCode(sessionStorage.getItem('code'));
}
}, [props.previousUser]);
const classes = useStyles();
useEffect(() => {
props.socket.on("message", (newValue) => {
props.setCode(newValue);
});
}, []);
const handleChange = (newValue) => {
props.setCode(newValue);
sessionStorage.setItem('code',newValue);
props.socket.emit("message", newValue);
};
const copyCode = (value) => {
copy(value);
setPopup([true, "Code Copied Sucessfully"]);
};
const fetchSharedCodeLink=async (content) =>{
var response = await fetch("https://dpaste.com/api/v2/", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: "content=" + encodeURIComponent(content)
});
return response.text();
}
const shareCode = (value) => {
setModalIsOpen(true)
setIsLoading(true)
fetchSharedCodeLink(value).then(url => {setIsLoading(false);setshareURL(url) });
}
const handleCodeRun = () => {
props.executeCode(langId[props.currLang], props.code, props.codeInput);
};
const handleCodeDownload = () => {
// download code here...
const element = document.createElement("a");
const file = new Blob([props.code], {
type: "text/plain;charset=utf-8",
});
element.href = URL.createObjectURL(file);
element.download = `syntaxmeets-code.${getExtensionByLangCode(
props.currLang
)}`;
document.body.appendChild(element);
element.click();
};
const IONavbar = (props) => {
return (
<AppBar position="static" style={{ backgroundColor: "#000A29" }}>
<Typography
variant="h6"
style={{
fontFamily: "poppins",
color: "white",
marginRight: "auto",
marginTop: "auto",
marginBottom: "auto",
marginLeft: "auto",
fontWeight: "400",
padding: "3px 2px",
}}
>
{props.type}
</Typography>
</AppBar>
);
};
const uploadFile = () => {
document.querySelector("#upload").click();
};
const checkValidFileExtension = (file) => {
const validExtensions = Object.keys(langExtensionDict);
var name = file.name;
var valid = false;
if (name.length > 0) {
for (var i = 0; i < validExtensions.length; ++i) {
var ext = validExtensions[i];
if (
name.substr(name.length - ext.length, ext.length).toLowerCase() ==
ext.toLowerCase()
) {
valid = true;
break;
}
}
}
return valid;
};
const handleFileChange = () => {
var file = document.querySelector("#upload").files[0];
if (file) {
var reader = new FileReader();
reader.onload = function (e) {
if (file.size > 10000) {
setFilePopup(true);
setFileHandleError("Error: File size greater than 10KB!");
return;
}
if (!checkValidFileExtension(file)) {
setFilePopup(true);
setFileHandleError("Error: Not a Valid File Extension!");
return;
}
handleChange(e.target.result);
const fileNameArr = file.name.split(".");
const ext = `.${fileNameArr[fileNameArr.length - 1]}`;
props.setLanguage(langExtensionDict[ext]);
};
reader.onerror = function (e) {
console.error("An error ocurred reading the file", e);
};
reader.readAsText(file, "UTF-8");
}
};
// handle fullscreen mode
const handleFullscreen = (props) =>{
fullscreen ? setFullscreen(false) : setFullscreen(true);
props.toggleFocusMode();
}
return (
<Fragment>
<Dialog fullWidth={true} maxWidth={"sm"} open={props.isCompiling}>
<DialogTitle style={{ align: "center" }}>Compiling ...</DialogTitle>
<div className={localClasses.loader}>
<div>
<span style={{ paddingLeft: "190px" }}>
<ShareIcon style={{ fontSize: "125px" }} />
</span>
<span className={localClasses.arrow}>></span>
</div>
</div>
</Dialog>
<Dialog maxWidth={"sm"} open={props.isError}>
<DialogTitle>Oops Error Occured</DialogTitle>
<span style={{ marginLeft: "15px" }}>{props.codeError}</span>
<DialogActions>
<Button
onClick={() => props.setIsError(false)}
variant="contained"
size="large"
color="primary"
>
Close
</Button>
</DialogActions>
</Dialog>
<Snackbar
open={popup[0]}
autoHideDuration={2000}
onClose={() => {
setPopup([false, ""]);
}}
>
<Alert
onClose={() => {
setPopup([false, ""]);
}}
severity="success"
variant="filled"
>
{popup[1]}
</Alert>
</Snackbar>
<Snackbar
open={filePopup}
autoHideDuration={2000}
onClose={() => {
setFilePopup(false);
}}
>
<Alert
onClose={() => {
setFilePopup(false);
}}
severity="error"
variant="filled"
>
{fileHandleError}
</Alert>
</Snackbar>
<AppBar position="static" style={{ backgroundColor: "#000A29" }}>
<div className={`${localClasses.Editor__navbar} row`}>
<Typography
variant="h5"
style={{
fontFamily: "poppins",
color: "white",
marginRight: "auto",
marginTop: "auto",
marginBottom: "auto",
marginLeft: "30px",
fontWeight: "800",
}}
>
Syntax<span style={{ color: "#FFD500" }}>Editor</span>
</Typography>
<Toolbar>
<FormControl
size="small"
variant="outlined"
className={classes.formControl}
>
<InputLabel
id="mode-label"
style={{ fontFamily: "poppins", color: "#FFD500" }}
>
Language
</InputLabel>
<Select
name="mode"
labelId="mode-label"
id="select-mode"
value={props.currLang}
onChange={(e) => {
props.setLanguage(e.target.value);
}}
label="Language"
style={{ fontFamily: "poppins", color: "#ffffff" }}
>
{LangOptions.map((language) => (
<MenuItem value={language} key={language}>
<span className={localClasses.Menu__options}>
{language}
</span>
</MenuItem>
))}
</Select>
</FormControl>
<FormControl
size="small"
variant="outlined"
className={classes.formControl}
>
<InputLabel
id="theme-label"
style={{ fontFamily: "poppins", color: "#FFD500" }}
>
Theme
</InputLabel>
<Select
name="Theme"
labelId="theme-label"
id="select-theme"
onChange={(e) => setTheme(e.target.value)}
value={theme}
label="Theme"
style={{ fontFamily: "poppins", color: "#ffffff" }}
>
{themes.map((lang) => (
<MenuItem key={lang} value={lang}>
<span className={localClasses.Menu__options}> {lang} </span>
</MenuItem>
))}
</Select>
</FormControl>
<FormControl
size="small"
variant="outlined"
className={classes.formControl}
>
<InputLabel
id="font-label"
style={{ fontFamily: "poppins", color: "#FFD500" }}
>
Font Size
</InputLabel>
<Select
name="Theme"
labelId="font-label"
id="select-font"
onChange={(e) => props.setFontSize(e.target.value)}
value={props.fontSize}
label="Font Size"
style={{ fontFamily: "poppins", color: "#ffffff" }}
>
{[10, 12, 14, 16, 18, 20, 24, 28, 32, 40].map((size) => (
<MenuItem key={size} value={size}>
<span className={localClasses.Menu__options}> {size} </span>
</MenuItem>
))}
</Select>
</FormControl>
</Toolbar>
</div>
</AppBar>
<Dialog fullWidth={true} maxWidth={"xs"} open={modalIsOpen}>
<CloseIcon style={{fontSize: "2em", position: "absolute", right: "5px", top: "5px"}} onClick={()=>{
setModalIsOpen(false)
setshareURL("")
}}/>
<DialogTitle style={{ textAlign: "center", marginTop: "10px" }}>
Share Your Code
</DialogTitle>
<DialogContent>
<div style={{display: "flex", alignItems: "center", margin: "20px"}}>
{isLoading ?
<BeatLoader color='red' loading={true} css={override} size={50} /> :
<>
<Typography style={{ padding: "5px 10px", background: "#eee", borderRadius: "3px" }}>{shareURL}</Typography>
<Tooltip title="Copy Url" arrow TransitionComponent={Zoom}>
<Button
variant="contained"
color="primary"
onClick={() => {
copy(shareURL)
setPopup([true, "Url Copied !!!"])
}}
style={{
fontFamily: "poppins",
marginLeft: "auto",
fontWeight: "600",
color: "white",
}}
>
<FileCopyIcon />
</Button>
</Tooltip>
</>
}
</div>
</DialogContent>
</Dialog>
<AceEditor
mode={langMode[props.currLang]}
theme={theme}
height="550px"
width={"auto"}
value={props.code}
onChange={handleChange}
fontSize={props.fontSize}
showPrintMargin
showGutter
highlightActiveLine
name="CODEEDITOR"
setOptions={{
useWorker: false,
enableLiveAutocompletion: props.autoCompletion,
}}
/>
<AppBar
position="static"
style={{ backgroundColor: "#000A29", marginBottom: "10px" }}
>
<Toolbar>
<FormControlLabel
control={
<Switch
color="primary"
checked={props.autoCompletion}
onChange={() => {
props.setAutoCompletion(!props.autoCompletion);
}}
name="EnableAutoCompletion"
/>
}
label={
<Typography>
<span style={{ color: "white" }}>Auto-complete</span>
</Typography>
}
/>
<input
type="file"
id="upload"
onChange={() => handleFileChange()}
hidden
accept=".c, .cpp, .java, .js, .ts, .clj, .cljs, .cs, .cbl, .cob, .cpy, .erl, .hrl, .go, .py, .f90, .f95, .f03, .txt, .groovy, .gvy, .gy, .gsh, .kt, .kts, .ktm, .php, .r, .rb, .sql, .swift"
/>
<ButtonGroup
style={{ marginLeft: "auto" }}
variant="contained"
color="primary"
>
<Tooltip title="Upload Code" arrow TransitionComponent={Zoom}>
<Button
variant="contained"
color="primary"
onClick={() => uploadFile()}
style={{
fontFamily: "poppins",
marginLeft: "auto",
fontWeight: "600",
color: "white",
}}
>
<CloudUploadIcon />
</Button>
</Tooltip>
<Tooltip title="Share Code" arrow TransitionComponent={Zoom}>
<Button
variant="contained"
color="primary"
onClick={() => shareCode(props.code)}
style={{
fontFamily: "poppins",
marginLeft: "auto",
fontWeight: "600",
color: "white",
}}
>
<ShareIcon />
</Button>
</Tooltip>
<Tooltip title="Copy Code" arrow TransitionComponent={Zoom}>
<Button
variant="contained"
color="primary"
onClick={() => copyCode(props.code)}
style={{
fontFamily: "poppins",
marginLeft: "auto",
fontWeight: "600",
color: "white",
}}
>
<FileCopyIcon />
</Button>
</Tooltip>
<Tooltip title="Download Code" arrow TransitionComponent={Zoom}>
<Button
variant="contained"
color="primary"
style={{
fontFamily: "poppins",
marginLeft: "auto",
fontWeight: "600",
color: "white",
}}
onClick={handleCodeDownload}
>
<CloudDownloadRounded style={{ fontSize: 24 }} />
</Button>
</Tooltip>
<Tooltip title={fullscreen ? "Exit Full Screen" : "Full Screen"} arrow TransitionComponent={Zoom}>
<Button
variant="contained"
color="primary"
style={{
fontFamily: "poppins",
marginLeft: "auto",
fontWeight: "600",
color: "white",
}}
onClick={() => handleFullscreen(props)}
>
{fullscreen
?<FullscreenExitRounded style={{ fontSize: 24 }}/>
:<FullscreenRounded style={{ fontSize: 24 }}/>
}
</Button>
</Tooltip>
</ButtonGroup>
<Button
variant="contained"
color="primary"
onClick={handleCodeRun}
startIcon={<PlayArrowIcon style={{ fontSize: 24 }} />}
style={{
fontFamily: "poppins",
marginLeft: "10px",
fontWeight: "600",
color: "#fff",
backgroundColor: "#FFD500",
}}
>
Run
</Button>
</Toolbar>
</AppBar>
<Grid container spacing={0}>
<Grid item xs={12} sm={12} md={6}>
<IONavbar type={"Input"} />
<INPUT />
</Grid>
<Grid item xs={12} sm={12} md={6}>
<IONavbar type={"Output"} />
<OUTPUT />
</Grid>
</Grid>
</Fragment>
);
}
Example #12
Source File: PageWrapper.jsx From zubhub with GNU Affero General Public License v3.0 | 4 votes |
/**
* @function PageWrapper View
* @author Raymond Ndibe <[email protected]>
*
* @todo - describe function's signature
*/
function PageWrapper(props) {
const backToTopEl = React.useRef(null);
const classes = useStyles();
const common_classes = useCommonStyles();
const trigger = useScrollTrigger();
const [searchType, setSearchType] = useState(
getQueryParams(window.location.href).get('type') || SearchType.PROJECTS,
);
const formRef = useRef();
const token = useSelector(state => state.auth.token);
const [state, setState] = React.useState({
username: null,
anchor_el: null,
loading: false,
open_search_form: false,
});
const [options, setOptions] = useState([]);
const [query, setQuery] = useState('');
const [queryInput, setQueryInput] = useState('');
const throttledFetchOptions = useMemo(
() =>
throttle(async (query, searchType) => {
if (query.length === 0) {
setOptions([]);
return;
}
const api = new API();
let completions = [];
if (searchType === SearchType.TAGS) {
completions = await api.autocompleteTags({ query, token });
completions = completions.map(({ name }) => ({
title: name,
}));
} else if (searchType === SearchType.PROJECTS) {
completions = await api.autocompleteProjects({ query, token });
completions = completions.map(({ id, title, creator, images }) => ({
title,
shortInfo: creator.username,
image: images.length > 0 ? images[0].image_url : null,
link: `/projects/${id}`,
}));
} else {
completions = await api.autocompleteCreators({ query, token });
completions = completions.map(({ username, avatar }) => ({
title: username,
image: avatar,
link: `/creators/${username}`,
}));
}
setOptions(completions);
}, 2),
[],
);
useEffect(() => {
throttledFetchOptions(
query ||
(props.location.search &&
getQueryParams(window.location.href).get('q')),
searchType,
);
}, [query, searchType]);
useEffect(() => {
throttledFetchOptions.cancel();
}, []);
useEffect(() => {
handleSetState({ loading: true });
fetchHero(props)
.then(() => {
if (props.auth.token) {
return props.getAuthUser(props);
}
})
.finally(() => {
handleSetState({ loading: false });
});
}, [props.auth.token]);
React.useEffect(() => {
handleSetState(handleProfileMenuClose());
}, [trigger]);
const handleSetState = obj => {
if (obj) {
Promise.resolve(obj).then(obj => {
setState(state => ({ ...state, ...obj }));
});
}
};
const onSearchOptionClick = async (_, option) => {
if (!option || !option.title) return;
await new Promise(resolve => setTimeout(resolve, 100));
if (option.link) {
window.history.pushState({}, '', option.link);
window.location.reload();
return;
}
const queryParams = new URLSearchParams({
type: searchType,
q: option.title,
});
window.history.pushState({}, '', `/search?${queryParams}`);
window.location.reload();
};
const handleSubmit = e => {
e.preventDefault();
const queryParams = new URLSearchParams({
type: searchType,
q: query,
});
window.history.pushState({}, '', `/search?${queryParams}`);
window.location.reload();
};
const { anchor_el, loading, open_search_form } = state;
const { t } = props;
const { zubhub, hero } = props.projects;
const profileMenuOpen = Boolean(anchor_el);
return (
<>
<ToastContainer />
<CssBaseline />
<AppBar className={classes.navBarStyle}>
<Container className={classes.mainContainerStyle}>
<Toolbar className={classes.toolBarStyle}>
<Box className={classes.logoStyle}>
<Link to="/">
<img
src={zubhub?.header_logo_url ? zubhub.header_logo_url : logo}
alt="logo"
/>
</Link>
<Box
className={clsx(
classes.languageSelectBoxStyle,
common_classes.displayInlineFlex,
common_classes.alignCenter,
common_classes.addOnSmallScreen,
)}
>
<TranslateIcon />
<Select
className={classes.languageSelectStyle}
value=""
onChange={e => handleChangeLanguage({ e, props })}
>
{Object.keys(languageMap).map((ln, index) => (
<MenuItem key={index} value={ln}>
{languageMap[ln]}
</MenuItem>
))}
</Select>
</Box>
<Box
className={clsx(
classes.languageSelectBoxStyle,
common_classes.displayInlineFlex,
common_classes.alignCenter,
common_classes.removeOnSmallScreen,
)}
>
<TranslateIcon />
<Select
className={classes.languageSelectStyle}
value={props.i18n.language}
onChange={e => handleChangeLanguage({ e, props })}
>
{Object.keys(languageMap).map((ln, index) => (
<MenuItem key={index} value={ln}>
{languageMap[ln]}
</MenuItem>
))}
</Select>
</Box>
<form
action="/search"
className={clsx(classes.searchFormStyle, classes.removeOn894)}
role="search"
onSubmit={handleSubmit}
ref={formRef}
>
<FormControl variant="outlined">
<InputLabel
htmlFor="q"
className={classes.searchFormLabelStyle}
>
{t('pageWrapper.inputs.search.label')}
</InputLabel>
<FormGroup row>
<FormControl variant="outlined">
<InputSelect
searchType={searchType}
onSearchTypeChange={setSearchType}
name="type"
>
<MenuItem value={SearchType.PROJECTS}>
Projects
</MenuItem>
<MenuItem value={SearchType.CREATORS}>
Creators
</MenuItem>
<MenuItem value={SearchType.TAGS}>Tags</MenuItem>
</InputSelect>
</FormControl>
<Autocomplete
options={options}
defaultValue={{
title:
props.location.search &&
getQueryParams(window.location.href).get('q'),
}}
renderOption={(option, { inputValue }) => (
<Option
option={option}
inputValue={inputValue}
onOptionClick={onSearchOptionClick}
/>
)}
onChange={onSearchOptionClick}
>
{params => (
<TextField
name="q"
id="q"
type="search"
variant="outlined"
{...params}
InputProps={{
...params.InputProps,
className: clsx(
classes.searchFormInputStyle,
'search-form-input',
),
endAdornment: (
<InputAdornment position="end">
<IconButton
type="submit"
className={classes.searchFormSubmitStyle}
aria-label={t(
'pageWrapper.inputs.search.label',
)}
>
<SearchIcon />
</IconButton>
</InputAdornment>
),
pattern: '(.|s)*S(.|s)*',
defaultValue: {
title:
props.location.search &&
getQueryParams(window.location.href).get('q'),
},
}}
onChange={e => setQuery(e.target.value)}
placeholder={`${t(
'pageWrapper.inputs.search.label',
)}...`}
/>
)}
</Autocomplete>
</FormGroup>
</FormControl>
</form>
</Box>
<div className={classes.navActionStyle}>
{!props.auth.token ? (
<>
<IconButton
className={clsx(
classes.toggleSearchFormStyle,
classes.addOn894,
)}
id="toggle-search"
aria-label="toggle search form"
onClick={() =>
handleSetState(handleToggleSearchForm(state))
}
>
<SearchIcon />
</IconButton>
<Link
className={clsx(
classes.textDecorationNone,
common_classes.removeOnSmallScreen,
)}
to="/login"
>
<CustomButton
variant="outlined"
size="large"
secondaryButtonStyle
customButtonStyle
>
{t('pageWrapper.navbar.login')}
</CustomButton>
</Link>
<Link
className={clsx(
classes.textDecorationNone,
common_classes.removeOnSmallScreen,
)}
to="/signup"
>
<CustomButton
variant="contained"
size="large"
primaryButtonStyle
customButtonStyle
className={common_classes.marginLeft1em}
>
{t('pageWrapper.navbar.signup')}
</CustomButton>
</Link>
<MenuRoundedIcon
className={common_classes.addOnSmallScreen}
aria-label={t('pageWrapper.navbar.menu')}
aria-controls="menu"
aria-haspopup="true"
onClick={e => handleSetState(handleProfileMenuOpen(e))}
/>
<Menu
className={common_classes.addOnSmallScreen}
disableScrollLock={true}
id="menu"
anchorEl={anchor_el}
anchorOrigin={{
vertical: 'top',
horizontal: 'right',
}}
keepMounted
transformOrigin={{
vertical: 'top',
horizontal: 'right',
}}
open={profileMenuOpen}
onClose={e => handleSetState(handleProfileMenuClose(e))}
>
<MenuItem>
<Link className={classes.textDecorationNone} to="/login">
<Typography
variant="subtitle2"
color="textPrimary"
component="span"
>
{t('pageWrapper.navbar.login')}
</Typography>
</Link>
</MenuItem>
<MenuItem>
<Link className={classes.textDecorationNone} to="/signup">
<Typography
variant="subtitle2"
color="textPrimary"
component="span"
>
{t('pageWrapper.navbar.signup')}
</Typography>
</Link>
</MenuItem>
</Menu>
</>
) : (
<>
<Link
className={clsx(
classes.textDecorationNone,
common_classes.marginRight1em,
common_classes.removeOnSmallScreen,
)}
to="/projects/create"
>
<CustomButton
variant="contained"
primaryButtonStyle
customButtonStyle
size="small"
>
{t('pageWrapper.navbar.createProject')}
</CustomButton>
</Link>
<IconButton
className={clsx(
classes.toggleSearchFormStyle,
classes.addOn894,
)}
id="toggle-search"
aria-label="toggle search form"
onClick={() =>
handleSetState(handleToggleSearchForm(state))
}
>
<SearchIcon />
</IconButton>
<NotificationButton
className={clsx(
common_classes.marginRight1em,
common_classes.removeOnSmallScreen,
)}
/>
<Avatar
className={clsx(
classes.avatarStyle,
common_classes.removeOnSmallScreen,
)}
aria-label={`${props.auth.username}' Avatar`}
aria-controls="profile_menu"
aria-haspopup="true"
onClick={e => handleSetState(handleProfileMenuOpen(e))}
src={props.auth.avatar}
alt={props.auth.username}
/>
<Menu
className={classes.profileMenuStyle}
disableScrollLock={true}
id="profile_menu"
anchorEl={anchor_el}
anchorOrigin={{
vertical: 'top',
horizontal: 'right',
}}
keepMounted
transformOrigin={{
vertical: 'top',
horizontal: 'right',
}}
open={profileMenuOpen}
onClose={e => handleSetState(handleProfileMenuClose(e))}
>
<MenuItem>
<Tooltip title={props.auth.username} placement="top">
<Typography
variant="subtitle2"
color="textPrimary"
component="span"
className={classes.profileStyle}
>
{props.auth.username }
</Typography>
</Tooltip>
</MenuItem>
<MenuItem>
<a className={classes.textDecorationNone} href="/profile">
<Typography
variant="subtitle2"
color="textPrimary"
component="span"
>
{t('pageWrapper.navbar.profile')}
</Typography>
</a>
</MenuItem>
<MenuItem className={common_classes.addOnSmallScreen}>
<Link
className={classes.textDecorationNone}
to="/projects/create"
>
<Typography
variant="subtitle2"
color="textPrimary"
component="span"
>
{t('pageWrapper.navbar.createProject')}
</Typography>
</Link>
</MenuItem>
<MenuItem>
<Link
className={classes.textDecorationNone}
to={`/creators/${props.auth.username}/projects`}
>
<Typography
variant="subtitle2"
color="textPrimary"
component="span"
>
{t('pageWrapper.navbar.projects')}
</Typography>
</Link>
</MenuItem>
<MenuItem>
<Link
className={classes.textDecorationNone}
to={`/creators/${props.auth.username}/followers`}
>
<Typography
variant="subtitle2"
color="textPrimary"
component="span"
>
{t('pageWrapper.navbar.followers')}
</Typography>
</Link>
</MenuItem>
<MenuItem>
<Link
className={classes.textDecorationNone}
to={`/creators/${props.auth.username}/following`}
>
<Typography
variant="subtitle2"
color="textPrimary"
component="span"
>
{t('pageWrapper.navbar.following')}
</Typography>
</Link>
</MenuItem>
<MenuItem>
<Link
className={classes.textDecorationNone}
to="/projects/saved"
>
<Typography
variant="subtitle2"
color="textPrimary"
component="span"
>
{t('pageWrapper.navbar.savedProjects')}
</Typography>
</Link>
</MenuItem>
<MenuItem className={classes.logOutStyle}>
<Typography
className={common_classes.colorRed}
variant="subtitle2"
component="span"
onClick={e => logout(e, props)}
>
{t('pageWrapper.navbar.logout')}
</Typography>
</MenuItem>
</Menu>
</>
)}
</div>
</Toolbar>
{open_search_form ? (
<ClickAwayListener
onClickAway={e => handleSetState(closeSearchFormOrIgnore(e))}
>
<form
action="/search"
className={clsx(classes.smallSearchFormStyle, classes.addOn894)}
role="search"
ref={formRef}
>
<FormControl variant="outlined" style={{ minWidth: 'unset' }}>
<InputSelect
searchType={searchType}
onSearchTypeChange={setSearchType}
name="type"
>
<MenuItem value={SearchType.PROJECTS}>Projects</MenuItem>
<MenuItem value={SearchType.CREATORS}>Creators</MenuItem>
<MenuItem value={SearchType.TAGS}>Tags</MenuItem>
</InputSelect>
</FormControl>
<FormControl
variant="outlined"
style={{ flex: '1 1 auto', maxWidth: '350px' }}
>
<InputLabel
htmlFor="q"
className={classes.searchFormLabelStyle}
>
{t('pageWrapper.inputs.search.label')}
</InputLabel>
<Autocomplete
options={options}
defaultValue={
props.location.search &&
getQueryParams(window.location.href).get('q')
}
renderOption={(option, { inputValue }) => (
<Option
option={option}
inputValue={inputValue}
onOptionClick={onSearchOptionClick}
/>
)}
onChange={onSearchOptionClick}
>
{params => (
<TextField
name="q"
id="q"
type="search"
variant="outlined"
{...params}
InputProps={{
...params.InputProps,
className: clsx(
classes.smallSearchFormInputStyle,
'search-form-input',
),
endAdornment: (
<InputAdornment position="end">
<IconButton
type="submit"
className={classes.searchFormSubmitStyle}
aria-label={t(
'pageWrapper.inputs.search.label',
)}
>
<SearchIcon />
</IconButton>
</InputAdornment>
),
pattern: '(.|s)*S(.|s)*',
}}
placeholder={`${t(
'pageWrapper.inputs.search.label',
)}...`}
onChange={e => setQuery(e.target.value)}
/>
)}
</Autocomplete>
</FormControl>
</form>
</ClickAwayListener>
) : null}
</Container>
</AppBar>
<Toolbar ref={backToTopEl} />
{loading ? <LoadingPage /> : props.children}
<footer className={clsx('footer-distributed', classes.footerStyle)}>
<Box>
<a href="https://unstructured.studio">
<img
src={
zubhub?.footer_logo_url
? zubhub.footer_logo_url
: unstructuredLogo
}
className={classes.footerLogoStyle}
alt="unstructured-studio-logo"
/>
</a>
<div>
<Box
className={clsx(
classes.languageSelectBoxStyle,
common_classes.displayInlineFlex,
common_classes.alignCenter,
common_classes.addOnSmallScreen,
)}
>
<TranslateIcon />
<Select
className={classes.languageSelectStyle}
value=""
onChange={e => handleChangeLanguage({ e, props })}
>
{Object.keys(languageMap).map((ln, index) => (
<MenuItem key={index} value={ln}>
{languageMap[ln]}
</MenuItem>
))}
</Select>
</Box>
<Box
className={clsx(
classes.languageSelectBoxStyle,
common_classes.displayInlineFlex,
common_classes.alignCenter,
common_classes.removeOnSmallScreen,
)}
>
<TranslateIcon />
<Select
className={classes.languageSelectStyle}
value={props.i18n.language}
onChange={e => handleChangeLanguage({ e, props })}
>
{Object.keys(languageMap).map((ln, index) => (
<MenuItem key={index} value={ln}>
{languageMap[ln]}
</MenuItem>
))}
</Select>
</Box>
</div>
</Box>
<section className={classes.footerSectionStyle}>
<Box className={classes.footerBoxStyle}>
<Typography
variant="subtitle2"
color="textPrimary"
className={classes.footerTitleStyle}
>
{t('pageWrapper.footer.privacy')}
</Typography>
<Link
to={`/privacy_policy`}
className={common_classes.textDecorationNone}
>
<Typography
variant="subtitle2"
color="textPrimary"
className={classes.footerLinkStyle}
>
{t('pageWrapper.footer.guidelines')}
</Typography>
</Link>
<Link
to={`/terms_of_use`}
className={common_classes.textDecorationNone}
>
<Typography
variant="subtitle2"
color="textPrimary"
className={classes.footerLinkStyle}
>
{t('pageWrapper.footer.termsOfUse')}
</Typography>
</Link>
</Box>
<Box className={classes.footerBoxStyle}>
<Typography
variant="subtitle2"
color="textPrimary"
className={classes.footerTitleStyle}
>
{t('pageWrapper.footer.about')}
</Typography>
<Link to="/about" className={common_classes.textDecorationNone}>
<Typography
variant="subtitle2"
color="textPrimary"
className={classes.footerLinkStyle}
>
{t('pageWrapper.footer.zubhub')}
</Typography>
</Link>
</Box>
<Box className={classes.footerBoxStyle}>
<Typography
variant="subtitle2"
color="textPrimary"
className={classes.footerTitleStyle}
>
{t('pageWrapper.footer.help')}
</Typography>
<a
target="__blank"
rel="noreferrer"
href={
hero.tinkering_resource_url
? hero.tinkering_resource_url
: 'https://kriti.unstructured.studio/'
}
className={common_classes.textDecorationNone}
>
<Typography
variant="subtitle2"
color="textPrimary"
className={classes.footerLinkStyle}
>
{t('pageWrapper.footer.resources')}
</Typography>
</a>
<Link
to={`/faqs`}
className={clsx(
common_classes.textDecorationNone,
common_classes.displayNone,
)}
>
<Typography
variant="subtitle2"
color="textPrimary"
className={classes.footerLinkStyle}
>
{t('pageWrapper.footer.faqs')}
</Typography>
</Link>
<a
href="mailto:[email protected]"
className={common_classes.textDecorationNone}
>
<Typography
variant="subtitle2"
color="textPrimary"
className={classes.footerLinkStyle}
>
{t('pageWrapper.footer.contactUs')}
</Typography>
</a>
</Box>
</section>
<Zoom in={useScrollTrigger}>
<div
onClick={e => handleScrollTopClick(e, backToTopEl)}
role="presentation"
className={classes.scrollTopButtonStyle}
>
<Fab color="secondary" size="small" aria-label="scroll back to top">
<KeyboardArrowUpIcon />
</Fab>
</div>
</Zoom>
</footer>
</>
);
}
Example #13
Source File: GameListElement.js From dipact with GNU General Public License v3.0 | 4 votes |
render() {
const { classes } = this.props;
let itemKey = 0;
let buttons = [];
if (
this.state.game.Properties.Open &&
this.state.game.Properties.ActiveBans &&
this.state.game.Properties.ActiveBans.length > 0
) {
buttons.push(
<Typography key="banned-notice" style={noticeClass}>
You can't join because you banned or are banned by a player.
</Typography>
);
}
if (
!this.state.game.Properties.Closed &&
this.state.game.Properties.FailedRequirements
) {
buttons.push(
<Typography
variant="subtitle2"
key="requirement-notice"
style={noticeClass}
>
You can't join this game because{" "}
{this.state.game.Properties.FailedRequirements.map((req) => {
return this.failureExplanations()[req];
}).join(" ")}
</Typography>
);
}
if (!this.state.dead) {
buttons.push(
<Button
variant="outlined"
style={{
marginRight: "16px",
minWidth: "100px",
marginBottom: "4px",
}}
color="primary"
onClick={this.viewGame}
key={itemKey++}
>
View
</Button>
);
if (this.state.member) {
buttons.push(
<Button
variant="outlined"
style={{
marginRight: "16px",
minWidth: "100px",
marginBottom: "4px",
}}
color="primary"
onClick={this.renameGame}
key={itemKey++}
>
Rename
</Button>
);
}
}
let replaceablePlayers = 0;
if (this.state.game.Properties.Members !== null) {
replaceablePlayers = this.state.game.Properties.Members.filter(member =>
member.Replaceable == true
).length;
} else {
replaceablePlayers = 0;
}
if (!this.state.game.Properties.Closed || replaceablePlayers > 0) {
buttons.push(
<Button
variant="outlined"
style={{
marginRight: "16px",
minWidth: "100px",
marginBottom: "4px",
}}
color="primary"
onClick={this.shareNative}
key={itemKey++}
>
Invite
</Button>
);
}
let hasInviteDialog = false;
this.state.game.Links.forEach((link) => {
if (link.Rel === "join") {
if (
this.state.game.Properties.PhaseLengthMinutes < 60 * 12 ||
(this.state.game.Properties.NonMovementPhaseLengthMinutes !== 0 &&
this.state.game.Properties.NonMovementPhaseLengthMinutes < 60 * 12)
) {
buttons.unshift(
<Typography key="deadline-warning" style={warningClass}>
WARNING: This game has short deadlines (less than 12 hours). If it
starts while you're unavailable, you might miss parts of the game
greatly impacting your reliability score.
</Typography>
);
}
if (
!this.state.game.Properties.Private &&
this.state.game.Properties.MinReliability === 0 &&
Globals.userStats.Properties.Reliability >= 10
) {
buttons.unshift(
<Typography key="reliability-warning" style={warningClass}>
WARNING: We advise you to join a different game, because this game
might have (some) absent players. You have high reliability so can
join a better game.
</Typography>
);
}
buttons.push(
<Button
key={itemKey++}
variant="outlined"
color="primary"
style={{ marginRight: "16px", minWidth: "100px" }}
onClick={(_) => {
this.joinGame(link);
}}
>
Join
</Button>
);
} else if (link.Rel === "edit-newest-phase-deadline-at") {
buttons.push(
//TODO: Add confirmdialog.js before we accidentally move a turn forwards.. (how?)
<React.Fragment>
<Divider style={{marginBottom: "4px"}} />
<Button
key={itemKey++}
variant="contained"
color="primary"
style={{
marginRight: "16px",
minWidth: "100px",
marginBottom: "4px",
}}
onClick={(_) => {
this.nextturn(link);
}}
>
End Current Phase
</Button>
<Button
key={itemKey++}
variant="contained"
color="primary"
style={{
marginRight: "16px",
minWidth: "100px",
marginBottom: "4px",
}}
onClick={(_) => {
this.reschedule(link);
}}
>
Change deadline
</Button>
</React.Fragment>
);
} else if (link.Rel === "leave") {
buttons.push(
<Button
key={itemKey++}
variant="outlined"
color="primary"
style={{
marginRight: "16px",
minWidth: "100px",
marginBottom: "4px",
}}
onClick={(_) => {
this.leaveGame(link);
}}
>
Leave
</Button>
);
} else if (link.Rel === "delete-game") {
buttons.push(
//TODO: add confirmdialog.js before we accidentally DELETE THE WHOLE (ONGOING) GAME (how)?
<Button
key={itemKey++}
variant="outlined"
color="primary"
style={{
marginRight: "16px",
minWidth: "100px",
marginBottom: "4px",
}}
onClick={(_) => {
this.deleteGame(link);
}}
>
Delete
</Button>
);
} else if (
link.Rel === "invite-user" ||
link.Rel.indexOf("uninvite-") === 0
) {
hasInviteDialog = true;
}
});
if (hasInviteDialog) {
buttons.push(
<Button
key={itemKey++}
variant="contained"
color="primary"
style={{
marginRight: "16px",
minWidth: "100px",
marginBottom: "4px",
}}
onClick={(_) => {
this.manageInvitations();
}}
>
Assign players
</Button>
);
}
const buttonDiv = (
<div
key={itemKey++}
style={{
dispay: "flex",
justifyContent: "space-evenly",
marginBottom: "8px",
}}
>
{buttons}
</div>
);
let summary = (
<div
style={{
display: "flex",
flexDirection: "column",
width: "100%",
marginTop: "8px",
}}
>
{((_) => {
if (this.state.game.Properties.Started && replaceablePlayers == 0) {
return (
<React.Fragment>
{/* IF STARTED */}
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
}}
>
{this.state.member && this.state.member.UnreadMessages > 0 ? (
<Badge
key={itemKey++}
badgeContent={this.state.member.UnreadMessages}
color="primary"
style={{
maxWidth: "calc(100% - 70px)",
}}
>
<Typography
textroverflow="ellipsis"
noWrap
style={{
color: "rgba(40, 26, 26, 1)",
}}
>
{helpers.gameDesc(this.state.game)}
</Typography>
</Badge>
) : (
<Typography
key={itemKey++}
textroverflow="ellipsis"
noWrap={true}
style={{
minWidth: "60px",
color: "rgba(40, 26, 26, 1)",
}}
>
{helpers.gameDesc(this.state.game)}
</Typography>
)}
<div
id="Timer"
key={itemKey++}
style={{
alignSelf: "center",
display: "flex",
alignItems: "center",
color: "#281A1A",
}}
>
{this.state.member &&
this.state.game.Properties.Started &&
!this.state.game.Properties.Finished ? (
this.state.member.NewestPhaseState.OnProbation ? (
<SvgIcon>
<path
d="M2.98188996,2.24133335 L21.3666663,20.6261097 L20.0261097,21.9666663 L19.0573333,20.998 L19,21 L5,21 C3.95,21 3.0822314,20.1799587 3.00551277,19.1486946 L3,19 L3,5 L3.00233335,4.942 L1.64133335,3.58188996 L2.98188996,2.24133335 Z M12,1 C13.235,1 14.2895,1.7581 14.75196,2.828465 L14.82,3 L19,3 C20.05,3 20.9177686,3.82004132 20.9944872,4.85130541 L21,5 L21,17.963 L16.037,13 L17,13 L17,11 L14.037,11 L12.037,9 L17,9 L17,7 L10.037,7 L6.037,3 L9.18,3 C9.579,1.898 10.5917,1.0848 11.80656,1.006235 L12,1 Z M13.0593333,15 L7,15 L7,17 L15.0593333,17 L13.0593333,15 Z M11.0593333,13 L9.06033335,11 L7,11 L7,13 L11.0593333,13 Z M12,3 C11.45,3 11,3.45 11,4 C11,4.55 11.45,5 12,5 C12.55,5 13,4.55 13,4 C13,3.45 12.55,3 12,3 Z"
id="Shape"
fill="#b71c1c"
fillRule="nonzero"
></path>
</SvgIcon>
) : this.state.member.NewestPhaseState.ReadyToResolve ? (
<SvgIcon>
<path
d="M9,0 C10.3,0 11.4,0.84 11.82,2 L11.82,2 L16,2 C17.1045695,2 18,2.8954305 18,4 L18,4 L18,18 C18,19.1045695 17.1045695,20 16,20 L16,20 L2,20 C0.8954305,20 0,19.1045695 0,18 L0,18 L0,4 C0,2.8954305 0.8954305,2 2,2 L2,2 L6.18,2 C6.6,0.84 7.7,0 9,0 Z M13.4347826,7 L7.70608696,12.7391304 L4.56521739,9.60869565 L3,11.173913 L7.70608696,15.8695652 L15,8.56521739 L13.4347826,7 Z M9,2 C8.44771525,2 8,2.44771525 8,3 C8,3.55228475 8.44771525,4 9,4 C9.55228475,4 10,3.55228475 10,3 C10,2.44771525 9.55228475,2 9,2 Z"
fill="#281A1A"
id="Combined-Shape"
></path>
</SvgIcon>
) : (
<StartedAtIcon />
)
) : (
""
)}
<Typography
variant="body2"
style={{
paddingLeft: "2px",
color: "rgba(40, 26, 26, 1)",
}}
>
{this.state.game.Properties.Finished
? helpers.minutesToDuration(
-this.state.game.Properties.FinishedAgo /
1000000000 /
60,
true
)
: helpers.minutesToDuration(
this.state.game.Properties.NewestPhaseMeta[0]
.NextDeadlineIn /
1000000000 /
60,
true
)}
</Typography>
</div>
</div>
<div key={itemKey++} style={secondRowSummaryClass}>
<Typography
textroverflow="ellipsis"
noWrap={true}
display="inline"
variant="caption"
id="variant"
style={secondRowSummaryColorClass}
>
{this.state.game.Properties.Variant}{" "}
{helpers.phaseLengthDisplay(this.state.game.Properties)}
</Typography>
<div style={summaryIconsAndPhaseClass}>
<div style={summaryIconsClass}>{this.getIcons()}</div>
<Typography
variant="caption"
style={secondRowSummaryColorClass}
>
{this.state.game.Properties.NewestPhaseMeta[0].Season}{" "}
{this.state.game.Properties.NewestPhaseMeta[0].Year},{" "}
{this.state.game.Properties.NewestPhaseMeta[0].Type}
</Typography>
</div>
</div>
{!this.state.member || this.state.game.Properties.Mustered ? (
""
) : (this.state.game.Properties.Members || []).find((m) => {
return m.User.Id === Globals.user.Id;
}).NewestPhaseState.ReadyToResolve ? (
<Typography
className={this.props.classes.sixteenBySixteenClass}
>
Confirmed ready <ConfirmedReadyIcon />
</Typography>
) : (
<Button
variant="outlined"
style={{
marginRight: "16px",
minWidth: "100px",
marginBottom: "4px",
}}
color="primary"
onClick={(ev) => {
ev.stopPropagation();
helpers
.safeFetch(
helpers.createRequest(
"/Game/" +
this.state.game.Properties.ID +
"/Phase/" +
this.state.game.Properties.NewestPhaseMeta[0]
.PhaseOrdinal +
"/PhaseState",
{
headers: {
"Content-Type": "application/json",
},
method: "PUT",
body: JSON.stringify({
ReadyToResolve: true,
}),
}
)
)
.then(this.reloadGame);
}}
key={itemKey++}
>
Confirm ready
</Button>
)}
</React.Fragment>
);
} else {
return (
<React.Fragment>
{/* IF STARTED */}
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
}}
>
<Typography
key={itemKey++}
textroverflow="ellipsis"
noWrap={true}
style={{}}
>
{helpers.gameDesc(this.state.game)}
</Typography>
<div
id="Join"
key={itemKey++}
style={{
alignSelf: "center",
display: "flex",
alignItems: "center",
}}
>
<NumMembersIcon style={replaceablePlayers == 0 ? {color: "primary"} : {color: "red"} } />
<Typography variant="body2" style={replaceablePlayers == 0 ? { paddingLeft: "2px", } : { paddingLeft: "2px", color: "red"}}>
{replaceablePlayers == 0 ? this.state.game.Properties.NMembers : this.state.game.Properties.NMembers - replaceablePlayers}/
{this.variant.Properties.Nations.length}{" "}
</Typography>
</div>
</div>
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
}}
>
<Typography
textroverflow="ellipsis"
noWrap={true}
display="inline"
variant="caption"
style={{
color: "rgba(40, 26, 26, 0.7)",
}}
>
{this.state.game.Properties.Variant}{" "}
{helpers.phaseLengthDisplay(this.state.game.Properties)}
</Typography>
<div> {this.getIcons()}</div>
</div>
</React.Fragment>
);
}
})()}
<div></div>
</div>
);
let gameView = (
<Zoom in={this.state.viewOpen} mountOnEnter unmountOnExit>
<div
style={{
position: "fixed",
zIndex: 1300,
right: 0,
bottom: 0,
top: 0,
left: 0,
background: "#ffffff",
}}
>
<Game
onChangeReady={this.reloadGame}
onJoinGame={this.reloadGame}
onLeaveGame={(_) => {
if (this.state.game.Properties.Members.length > 1) {
this.reloadGame();
} else {
this.setState({ dead: true });
}
}}
unreadMessagesUpdate={this.reloadGame}
gamePromise={(reload) => {
if (reload) {
return helpers
.safeFetch(
helpers.createRequest(
this.state.game.Links.find((l) => {
return l.Rel === "self";
}).URL
)
)
.then((resp) => resp.json());
} else {
return new Promise((res, rej) => {
res(this.state.game);
});
}
}}
close={this.closeGame}
/>
</div>
</Zoom>
);
if (this.props.summaryOnly) {
return (
<React.Fragment>
<div style={{ width: "100%" }} onClick={this.viewGame}>
{summary}
</div>
{this.state.viewOpen ? gameView : ""}
</React.Fragment>
);
}
return (
<React.Fragment>
<Accordion
key="game-details"
onChange={(ev, exp) => {
this.setState({ expanded: exp });
}}
square
style={{
border: "none",
boxShadow: "none",
padding: "0px",
margin: "0px",
}}
>
<AccordionSummary
classes={{
root: classes.accordionSummaryRoot,
content: classes.accordionSummaryContent,
}}
expandIcon={<ExpandIcon />}
>
{summary}
</AccordionSummary>
<AccordionDetails className={classes.accordionDetails}>
{this.state.expanded ? (
<div>
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
flexWrap: "wrap",
maxWidth: "960px",
width: "100%",
marginBottom: "16px",
}}
>
<div
style={{
maxWidth: "460px",
}}
>
{buttonDiv}
{this.state.dead ? (
<Typography style={{ color: "red" }}>Deleted</Typography>
) : (
""
)}
<GameMetadata
game={this.state.game}
withKickButtons={true}
reloadGame={this.reloadGame}
/>
</div>
</div>
<Divider />
</div>
) : (
""
)}
</AccordionDetails>
</Accordion>
{this.state.viewOpen ? gameView : ""}
<NationPreferencesDialog
parentCB={(c) => {
this.nationPreferencesDialog = c;
}}
onSelected={null}
/>
{this.state.member ? (
<RenameGameDialog
onRename={this.reloadGame}
game={this.state.game}
parentCB={(c) => {
this.renameGameDialog = c;
}}
/>
) : (
""
)}
{this.state.game.Properties.GameMaster &&
this.state.game.Properties.GameMaster.Id === Globals.user.Id ? (
<React.Fragment>
<RescheduleDialog
parentCB={(c) => {
this.rescheduleDialog = c;
}}
onSubmit={this.onRescheduleSubmit}
/>
<ManageInvitationsDialog
game={this.state.game}
parentCB={(c) => {
this.manageInvitationsDialog = c;
}}
reloadGame={this.reloadGame}
/>
</React.Fragment>
) : (
""
)}
</React.Fragment>
);
}