Use Paper elevation prop via css? - reactjs

This is probably a bigger design question, but in my material ui app, I have tried to keep all styling done in CSS (using makeStyles), rather than do some styling inside the jsx (as per the material ui docs) and some in CSS.
So far all my styling has worked in css only, but I have hi a sticking point with elevation on the Paper component. I thought it would be a simple case of adding elevation: '3' to my useStyles object (cv__paper), but it only works as below:
//works as expeted
<Paper className={classes.cv__paper} elevation={3}>
<img
className={classes.image}
src={image}
alt=""
></img>
</Paper
//won't style with elevation
<Paper className={classes.cv__paper}>
<img
className={classes.image}
src={image}
alt=""
></img>
</Paper
...
cv__paper: {
elevation: '3'
}
full code
just to confirm, I have checked that the css is being applied (changed the background to blue)
import { makeStyles } from '#material-ui/core/styles';
const useStyles = makeStyles((theme) => ({
root: {
padding: '25px',
maxWidth: '60%'
},
content: {
height: '100%',
width: '100%',
justifyContent: 'center',
textAlign: 'center'
},
image: {
maxWidth: '100%',
maxHeight: '100%'
},
download__icon: {
fontSize: '100px'
},
cv__paper: {
elevation: 3
}
}));
export default useStyles;
const Cv = () => {
const classes = useStyles();
return (
<Container className={classes.root}>
<Box className={classes.content}>
<Paper className={classes.cv__paper} elevation={3}>
<img
className={classes.image}
src={image}
alt=""
></img>
</Paper>
<Link variant="IconButton" href={CvFile} download="mreaybeaton.pdf">
<GetAppIcon className={classes.download__icon}></GetAppIcon>
</Link>
</Box>
</Container>
);
};
Any ideas?

As the docs mention the elevation is a property that gives to Paper shadow depth.
So if you want to add to your Paper elevation style, you must add boxShadow in your className.
Check the below snippet:
import { makeStyles } from '#material-ui/core/styles';
const useStyles = makeStyles((theme) => ({
root: {
padding: '25px',
maxWidth: '60%'
},
content: {
height: '100%',
width: '100%',
justifyContent: 'center',
textAlign: 'center'
},
image: {
maxWidth: '100%',
maxHeight: '100%'
},
download__icon: {
fontSize: '100px'
},
cv__paper: {
boxShadow: "0px 3px 3px -2px rgb(0 0 0 / 20%), 0px 3px 4px 0px rgb(0 0 0 / 14%), 0px 1px 8px 0px rgb(0 0 0 / 12%)"
}
}));
export default useStyles;
const Cv = () => {
const classes = useStyles();
return (
<Container className={classes.root}>
<Box className={classes.content}>
<Paper className={classes.cv__paper} elevation={3}>
<img
className={classes.image}
src={image}
alt=""
></img>
</Paper>
<Link variant="IconButton" href={CvFile} download="mreaybeaton.pdf">
<GetAppIcon className={classes.download__icon}></GetAppIcon>
</Link>
</Box>
</Container>
);
};

Related

Centre the Typography

I tried to centre the typography using both textAlign and align but that did not work. Can someone help me with this ? The resulting page is below the code
import React, {useState} from 'react'
import logo from '../../images/logo.svg'
import { Typography } from '#mui/material'
import AccountCircleIcon from "#mui/icons-material/AccountCircle"
const NavBar = () => {
const StyledToolbar = styled(Toolbar)({
display: "flex",
alignItems: "center",
justifyContent: "space-between"
});
const Logo = styled("img")({
width: "12rem",
height: "auto",
});
const StyledAppBar = styled(AppBar)({
position: "sticky",
backgroundColor: "#EDEDED",
});
return (
<StyledAppBar>
<StyledToolbar>
<Logo src={logo} alt="quizy" />
<Typography variant="h5" color="black" align='center'>
Question
</Typography>
<AccountCircleIcon
style={{ color: "black" }}
/>
</StyledToolbar>
</StyledAppBar>
);
}
Page Result
It actually is centered according to its width. To center with 3 children elements you could assign Logo, Typography and Icon following CSS properties:
flex-grow: 1
flex-basis: 0
This will probably move the AccountCircleIcon a bit to the left but you can assign it margin-left: auto. You will also have to remove your assigned width of Logo. For example:
import React, {useState} from 'react'
import logo from '../../images/logo.svg'
import { Typography } from '#mui/material'
import AccountCircleIcon from "#mui/icons-material/AccountCircle"
const NavBar = () => {
const StyledToolbar = styled(Toolbar)({
display: "flex",
alignItems: "center",
justifyContent: "space-between"
});
const Logo = styled("img")({
width: "12rem",
height: "auto"
});
const StyledAppBar = styled(AppBar)({
position: "sticky",
backgroundColor: "#EDEDED",
});
return (
<StyledAppBar>
<StyledToolbar>
<div style={{ flexGrow: 1, flexBasis: 0 }}>
<Logo src={logo} alt="quizy" />
</div>
<Typography style={{ flexGrow: 1, flexBasis: 0 }} variant="h5" color="black" align='center'>
Question
</Typography>
<div style={{ flexGrow: 1, flexBasis: 0, textAlign: "right" }}>
<AccountCircleIcon
style={{ marginLeft: 'auto', color: "black" }}
/>
</div>
</StyledToolbar>
</StyledAppBar>
);
}

React - Material UI Grid and useStyles prop issues

First time really playing around with materialUI. I've made a grid of cards and sorted out most of the styling within the same component, so I wanted to move all the useStyles styling to a styling file.
After figuring out how to do so, on reload I could see that no backgroundColor styling across any of the components were rendering, but everything else was.
backgroundColor rendered fine when it was in the same file, and weirdly, it renders once (the other backgroundColours not removed render fine, I mean) if I remove one instance of the color and readd it...but on reload, they're all gone again.
Appreciate some help on this please!
GridStyles.js
import { makeStyles } from '#material-ui/core/styles'
const useStyles = makeStyles({
root: {
flexGrow: 1,
marginLeft: '15rem',
marginRight: '15rem',
wordBreak: 'break-all',
whiteSpace: 'unset'
},
containerCard: {
border: 'solid 3px black',
marginRight: '2rem',
marginLeft: '2rem',
marginTop: '3rem',
marginBottom: '5rem',
borderRadius: '8px',
borderLeftStyle: 'dashed',
borderRightStyle: 'dashed',
},
topCard: {
backgroundColor: '#53E9B2',
border: 'none',
boxShadow: 'none',
paddingBottom: '7rem',
position: 'relative'
},
topCardText: {
position: 'absolute',
bottom: 0,
padding: 0,
marginLeft: '2rem'
},
middleCard: {
border: 'solid 2px black',
borderLeftStyle: 'dashed',
borderRightStyle: 'dashed',
backgroundColor: '#53E9B2',
marginRight: '2rem',
marginLeft: '2rem',
marginTop: '1em',
marginBottom: '3rem',
borderRadius: '8px'
},
middleCardText: {
whiteSpace: 'pre-wrap',
color: 'white'
},
bottomCard: {
backgroundColor: '#53E9B2',
border: 'none',
boxShadow: 'none',
paddingBottom: '1rem'
},
bottomCardText: {
color: 'white',
padding: 0,
marginLeft: '2rem'
}
})
export default useStyles
Grid.js
import React from 'react'
import useStyles from './GridStyles'
import {
Grid,
Card,
CardHeader
} from '#material-ui/core/'
const CardGrid = (props) => {
const classes = useStyles(props);
return (
<div className={classes.root}>
<Grid
container
spacing={0}
direction='row'
justifyContent='flex-start'
alignItems='flex-start'
>
{props.cardData.map(elem => (
<Grid
item
xs={4}
sm={4}
md={4}
xl={4}
key={props.cardData.indexOf(elem)}
>
<Card className={classes.containerCard}>
<Card className={classes.topCard}>
<CardHeader className={classes.topCardText} title={elem.name} />
</Card>
<Card className={classes.middleCard}>
<CardHeader
className={classes.middleCardText}
title={`Company Name:\n${elem.company.name}`}
/>
<CardHeader
className={classes.middleCardText}
title={`Company Catchphrase:\n${elem.company.catchPhrase}`}
/>
<CardHeader
className={classes.middleCardText}
title={`Company Bs:\n${elem.company.bs}`}
/>
</Card>
<Card className={classes.bottomCard}>
<CardHeader
className={classes.bottomCardText}
title={`Phone: ${elem.phone}`}
/>
<CardHeader
className={classes.bottomCardText}
title={`Email: ${elem.email}`}
/>
<CardHeader
className={classes.bottomCardText}
title={`Website: ${elem.website}`}
/>
</Card>
</Card>
</Grid>
))}
</Grid>
</div>
)
}
export default CardGrid
Next JS not properly loading Material UI styles until refresh
The accepted answer on this link fixed my problem. Converted the GridStyles page into one const with the styles and nothing else, arrow function with that calls this file with the makeStyles() function reference and it worked.

Video loader overrides the div element

The video loader overrides the fixed bottom element, thus makes it quite unpleasant. I'am streaming the videos online and player used for it is React HLS player. What would be the best solution to prevent the overriding of loader. Following is the code reference
React HLS Player
<ReactHlsPlayer
url={video_url}
autoplay={false}
controls={true}
width="100%"
height="auto"
config={{
file: {
forceHLS: true,
}
}}
/>
Bottom Navbar Code
const useStyles = makeStyles({
root: {
width: "100%",
bottom: "0px",
position: "sticky"
},
gridList: {
flexWrap: "nowrap",
position: "fixed",
bottom: "0px",
background: "white",
border: "1px solid grey",
width: "100%"
}
});
<GridList className={classes.gridList}>
{itemList.map((tile, index) => {
return (
<GridListTile
key={tile.icon}
style={{ height: "70px", width: "25%" }}
>
<ListItem button key={tile.text}
onClick={(tile.text == "DirectLine") ? directLineFunc : ''}
>
<NavLink
exact
to={tile.link}
key={tile.key}
activeClassName="main-nav-active"
style={{ textAlign: "center" }}
isActive={(match, location) => {
match && setNewActiveLink(index)
return match;
}}
>
<ListItemText
disableTypography
primary={
<Typography
style={{
fontSize: "10px",
fontWeight: "bold",
fontFamily: "Nunito"
}}
>
{tile.text}
</Typography>
}
/>
</NavLink>
</ListItem>
</GridListTile>
);
})}
</GridList>
See the image below
And this the codesandbox link: https://codesandbox.io/s/react-material-forked-dtx6w
Finally I was able to sort out by adding 'zIndex:999' to gridList of BottomNavbar with the following changes in useStyles as:
const useStyles = makeStyles({
root: {
width: "100%",
bottom: "0px",
position: "sticky"
},
gridList: {
flexWrap: "nowrap",
position: "fixed",
bottom: "0px",
background: "white",
border: "1px solid grey",
width: "100%",
zIndex: 999 {/* <-- Here I added this and issue solved */}
}
});
I added a style={{marginBottom: "100px"}} property in the <ReactHlsPlayer /> and it seems to fix your problem

How to correctly align an image inside a React Material ui Grid?

I was working on a footer for my project.
I am using material UI grid for the footer so I wanted to add the logo at the bottom but I don't understand why it is having right padding (I guess it is padding, not sure).
ScreenShot ->
It's something like this. (Have blurred the logo for privacy reasons)
Code Footer.js React Compoennt ->
import React from "react";
import CssBaseline from "#material-ui/core/CssBaseline";
import Typography from "#material-ui/core/Typography";
import { makeStyles } from "#material-ui/core/styles";
import Container from "#material-ui/core/Container";
import Link from "#material-ui/core/Link";
import Grid from "#material-ui/core/Grid";
import Box from "#material-ui/core/Box";
import logoWhite from "../logos/logoWhite.png";
function Copyright() {
return (
<Typography variant="body2" color="textSecondary">
{"Copyright © "}
<Link color="inherit" href="https://material-ui.com/">
Your Website
</Link>{" "}
{new Date().getFullYear()}
{"."}
</Typography>
);
}
const useStyles = makeStyles((theme) => ({
root: {
display: "flex",
flexDirection: "column",
minHeight: "100vh",
},
main: {
marginTop: theme.spacing(8),
marginBottom: theme.spacing(2),
},
footer: {
padding: theme.spacing(3, 2),
marginTop: "auto",
backgroundColor: "#312D2D",
color: "white",
height: 167,
},
footerGrid: {
width: "20%",
marginLeft: 40,
marginTop: 35,
pading:0,
border: "2px solid red"
},
footerLogo: {
minWidth: "50%",
maxWidth: "60%",
width: "auto",
margin: "0 auto",
backgroundColor: "pink"
},
footerGridLogo: {
width: "fit-content",
pading:0,
borderRight: "1px solid white",
margin:0,
border: "4px solid green"
}
}));
export default function Footer() {
const classes = useStyles();
return (
<div className={classes.root}>
<CssBaseline />
<footer className={classes.footer}>
<Grid spacing={0} className={classes.footerGrid}>
<Grid item className={classes.footerGridLogo}>
<img
src={logoWhite}
alt="brandlogo"
className=""
className={classes.footerLogo}
/>
</Grid>
</Grid>
</footer>
</div>
);
}
Wanted it to look something like this ->
add this inline styling inside the Grid item tag style={{display:'flex',justifyContent:'center',alignItems:'center'}}

Creating Tweet Display Box in ReactJS

I am using the following code to generate a Tweet input box which takes in text/video/image/emoji. And they can be in different combinations.
I am not sure how to generate a tweet display box which shows the final display containing text/image/emoji ? I understand I might need to put the different inputs in an array or some sort but what after that. My current code for display side is performing nothing and I am not sure where to go from here.
I am looking for display box to be of following form after a Submit Button:
Code components/EmojiPicker.js has:
import React, {useState} from 'react'
import ReactDOM from "react-dom";
import { Picker } from "emoji-mart";
import Button from "#material-ui/core/Button";
const EmojiPicker = ({ onSelect }) => {
const [show, setShow] = useState(false);
return (
<>
<Button
onClick={() => setShow(oldState => !oldState)}
style={{ width: "30px", height: "30px", borderRadius: "4px", border: "3px solid", display: "flex", alignItems: "center", justifyContent: "center",
background: "transparent"}}>
ej
</Button>
{ReactDOM.createPortal(
show && <Picker onSelect={onSelect} />,
document.body
)}
</>
);
};
export default EmojiPicker
Code components/FileInput.js has:
import React, {useRef} from 'react'
const FileInput = ({ onChange, children }) => {
const fileRef = useRef();
const onPickFile = event => {
onChange([...event.target.files]);
};
return (
<div
style={{
width: "35px",
height: "35px",
borderRadius: "3px"
}}
onClick={() => fileRef.current.click()}
>
{children}
<input
multiple
ref={fileRef}
onChange={onPickFile}
type="file"
style={{ visibility: "hidden" }}
/>
</div>
);
};
export default FileInput
Code components/tweetboxImgInp.js as:
import React, {useState, useEffect} from 'react'
const ImgIcon = () => (
<svg focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M0 0h24v24H0z" fill="none" />
<path d="M14 13l4 5H6l4-4 1.79 1.78L14 13zm-6.01-2.99A2 2 0 0 0 8 6a2 2 0 0 0-.01 4.01zM22 5v14a3 3 0 0 1-3 2.99H5c-1.64 0-3-1.36-3-3V5c0-1.64 1.36-3 3-3h14c1.65 0 3 1.36 3 3zm-2.01 0a1 1 0 0 0-1-1H5a1 1 0 0 0-1 1v14a1 1 0 0 0 1 1h7v-.01h7a1 1 0 0 0 1-1V5z" />
</svg>
);
export const Img = ({ file, onRemove, index }) => {
const [fileUrl, setFileUrl] = useState(null);
useEffect(() => {
if (file) {
setFileUrl(URL.createObjectURL(file));
}
}, [file]);
return fileUrl ? (
<div style={{ position: "relative", maxWidth: "230px", maxHeight: "95px" }}>
<img
style={{
display: "block",
maxWidth: "230px",
maxHeight: "95px",
width: "auto",
height: "auto"
}}
alt="pic"
src={fileUrl}
/>
<div
onClick={() => onRemove(index)}
style={{
position: "absolute",
right: 0,
top: 0,
width: "20px",
height: "20px",
borderRadius: "50%",
background: "black",
color: "white",
display: "flex",
alignItems: "center",
justifyContent: "center"
}}
>
x
</div>
</div>
) : null;
};
export default ImgIcon
And App.js has:
import React, { useRef, useState } from "react";
import ImgIcon, {Img} from './components/tweetboxImgInp'
import EmojiPicker from './components/EmojiPicker'
import FileInput from './components/FileInput'
import "emoji-mart/css/emoji-mart.css";
import "./styles.css";
function App() {
const [text, setText] = useState("");
const [pics, setPics] = useState([]);
const textAreaRef = useRef();
const insertAtPos = value => {
const { current: taRef } = textAreaRef;
let startPos = taRef.selectionStart;
let endPos = taRef.selectionEnd;
taRef.value =
taRef.value.substring(0, startPos) +
value.native +
taRef.value.substring(endPos, taRef.value.length);
};
return (
<div style={{display: "flex", flexDirection: "column", border: "3px solid", borderRadius: "5px", width: "600px", minHeight: "200px", padding: "20px"}} >
<div style={{ display: "flex", flexDirection: "column", flex: 1, border: "1px solid", borderRadius: "5px", margin: "0px"}}>
<textarea
ref={textAreaRef}
value={text}
style={{ flex: 1, border: "none", minHeight: "150px" }}
onChange={e => setText(e.target.value)}
/>
<div style={{ display: "flex", flexDirection: "row", flexWrap: "wrap", background: "fbfbfb"}} >
{pics.map((picFile, index) => (
<Img key={index} index={index} file={picFile} onRemove={rmIndx =>
setPics(pics.filter((pic, index) => index !== rmIndx))}/>))}
</div>
</div>
<div style={{ display: "flex", flexDirection: "row", alignItems: "center", marginTop: "20px" }}>
<div style={{ marginRight: "20px" }}>
<FileInput onChange={pics => setPics(pics)}>
{/* <ImgIcon /> */}
Tes
</FileInput>
</div>
<EmojiPicker onSelect={insertAtPos} />
</div>
</div>
);
}
export default App
Edit: I am good with the display box accepting only 1 media file, text and few emoji. It will surprise me if I am the only one in 2019 looking to do it for fun.
Working Example
Click the codesandbox button to view the demo
The tweet display component is pretty straightforward. Its a flexbox column with two parts. First part of the column contains the tweet. The second part of the column contains the list of images/media elements. Emoji is part of the text component.
Tweet Display Component
const Tweet = ({ tweet: { text, images } }) => (
<div
style={{
margin: "20px",
border: "1px solid grey",
width: "600px",
padding: "20px",
borderRadius: "3px"
}}
>
<div>{text}</div>
{images.length > 0 && (
<div
style={{
display: "flex",
flexDirection: "row",
flexWrap: "wrap",
background: "fbfbfb",
padding: "30px 0"
}}
>
{images.map((img, i) => (
<Img key={i} file={img} index={i} isSingle={images.length === 1} />
))}
</div>
)}
</div>
);
For more info checkout this css-tricks article to get more info on css flex layout

Resources