I am trying to design a simple report with the format as shown in the following Figma file using React and Material UI. However, I am encountering a challenge when designing the slanting edges of the divs as shown on the report. Plus the purple border. This is what I have done so far, but it is far from being perfect:
const leftDiv = {
content: "",
position: "absolute",
top: "50%",
right: 0,
width: "100%",
height: "50%",
backgroundColor: 'rgb(255, 255, 255)',
clipPath: "polygon(0 0, 0% 0%, 100% 100%, 0% 100%)"
}
const rightDiv = {
position: "absolute",
bottom: 0,
right: 0,
display: 'inline-block',
width: 0,
height: 0,
borderStyle: 'solid',
borderWidth: '0 0 500px 100vw',
borderColor: 'transparent transparent #FFFFFF transparent',
}
const contentDiv = {
backgroundColor: 'rgb(255, 255, 255)',
width: "100%",
height: "100%",
clipPath: "polygon(100% 0, 100% 0%, 100% 100%, 0% 100%)"
}
const Coverpage = () => {
return (
<Container>
<Grid>
<Paper>
<Box sx={{ position: 'relative', width: '100%' }}>
<CardMedia
component='img'
alt="cover page image"
image='https://unsplash.com/photos/vbxyFxlgpjM'
/>
<Box style={leftDiv}></Box>
<Box style={rightDiv}>
<Box style={contentDiv}>
<Box sx={{ width: '100%', height: '100%', display: 'flex', flexDirection: 'column', justifyContent: 'flex-end', alignItems: 'flex-end', textAlign: 'right', pr: 8 }}>
<Typography sx={{ fontSize: '24px', mb: 2 }}>Lorem ipsum</Typography>
<Typography sx={{ fontSize: '48px', fontWeight: 'bold', textTransform: 'uppercase', color: '#000133' }}>Lorem ipsum</Typography>
<Typography sx={{ fontSize: '64px', fontWeight: 'bold', textTransform: 'uppercase', color: 'blue' }}>Lorem ipsum</Typography>
</Box>
</Box>
</Box>
</Box>
</Paper>
</Grid>
</Container>
);
}
export default Coverpage;
I found using clipPath as the easiest, even though I would prefer using triangles to design the slanting edges since later, I am planning to use react-pdf-renderer which I am not sure if it supports clipPath in its CSS styling.
I will appreciate a pointer to the right direction.
Dan touched on the purple border. About the slanted div you can use this trick:
.slanted{
height: 0;
width: 0;
border-top: solid 100px transparent;
border-right: solid 50vw blue;
border-left: solid 50vw blue;
border-bottom: solid 100px blue;
}
You're making a div with no height or width. The borders meet along a diagonal line and so you can have a triangle effect.
You can use an additional div for the text
Edit: making the borders responsive
To make the border trick dynamic you can use some JS:
function App() {
const footerRef = React.useRef()
useEffect(() => {
window.addEventListener('resize', setBorders)
return () => {
window.removeEventListener('resize', setBorders)
}
}, [])
useEffect(() => {
if (!footerRef.current) return
setBorders()
}, [footerRef])
const setBorders = () => {
let containerWidth = document.querySelector('.container').clientWidth
let footerStyle = footerRef.current.style
footerStyle.borderRightWidth = containerWidth/2+'px'
footerStyle.borderLeftWidth = containerWidth/2+'px'
}
return (
<div className='App'>
<div className='container'>
<div className='footer' ref={footerRef}>
</div>
</div>
</div>
);
}
export default App
We are adding a 'resize' eventListener to the window that will trigger the setBorders() function. In this function we select the container element and set the width of the footer borders to be half of it.
To make sure the function also fires on initial load I added a useEffect which will fire when the footer is created and its Ref is set. You can also use a callback ref instead.
The css, I assumed the footer will be static height:
.container{
height: 200px;
width: 100%;
background: red;
}
.footer{
position: relative;
height: 0;
width: 0;
top: calc(100% - 100px);
/*border-top width + border-bottom width = 100px*/
border-top: 50px solid transparent;
border-bottom: 50px solid green;
border-right: solid blue;
border-left: solid blue;
}
If you don't mind making the container position: relative; you can then just do:
.footer{
position: absolute;
bottom: 0;
}
You just need to use a simple CSS transform on the element.
transform: skew(-15deg, -15deg);
Related
I resized an ant design carousel and would like to move the image to appear on the center of my screen.
This is how the image currently appears
This is what I have tried:
const contentStyle = {
height: '160px',
width: '25%',
color: '#fff',
lineHeight: '60%',
textAlign: 'center',
background: '#364d79',
justifyContent: 'center',
alignItems: 'center',
};
const imageStyle = {
flex: 1,
width: '100%',
height: '100%',
resizeMode: 'center',
}
return(
<>
<Carousel autoplay>
{
[onlineUsers].length === 0 ?
<p>There are currently no active users</p>
: onlineUsers.map(user => {
return (
<div className="img-container">
<h3 style={contentStyle}><img style={imageStyle} src={user.profile_pic} /></h3>
</div>
)
})
}
</Carousel>
You can use flex on the image container. It seems at runtime, on the container, display:inline-block is assigned. So we have to use display: flex !important for it to work.
It's also important to put a width & height:auto to image.
CSS
.container {
display: flex !important;
justify-content: center;
background-color: hotpink;
align-content: center;
}
.container > img {
width: 80px;
height: auto;
}
.carousal {
background-color: brown;
padding-bottom: 50px;
}
JS
<Carousel className="carousal">
<div className="container">
<img src={user} alt="xx" />
</div>
<div className="container">
<img src={programmer} alt="xx" />
</div>
</Carousel>
I have made a sandbox with two images, different sizes, center aligned.
Add this CSS and it should work fine
img{
margin: 0 auto;
}
I have a MUI styled component that renders a green circular badge.
const StyledGreenBadge = styled(Badge)(({ theme }) => ({
'& .MuiBadge-badge': {
backgroundColor: '#44b700',
color: '#44b700',
width: '15px',
height: '15px',
borderRadius: '100%',
boxShadow: `0 0 0 2px ${theme.palette.background.paper}`,
'&::after': {
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
borderRadius: '50%',
animation: 'ripple 1.2s infinite ease-in-out',
border: '1px solid currentColor',
content: '""',
},
},
'#keyframes ripple': {
'0%': {
transform: 'scale(.8)',
opacity: 1,
},
'100%': {
transform: 'scale(2.4)',
opacity: 0,
},
},
}));
Now, I want my code to be DRY, so I want to create a StyledYellowBadge.
All I have to do is somehow just change the color property of StyledGreenBadge.
Yet, I could not figure out how for 3 hours.
I have tried something like this:
color: { desiredColor === 'yellow' ? 'yellow' : #44b700'},
where desiredColor is a second argument, after
{ theme }
How can I make achieve this?
You can add custom properties to your styled MUI component by describing the type:
const StyledGreenBadge = styled(Badge)<{ badgeColor?: string }>(
Then, you can pass described property (badgeColor in this case) to your styled Badge component:
<StyledGreenBadge badgeColor="red" badgeContent={4} color="primary">
and assign it to the property you want:
backgroundColor: props.badgeColor ?? "#44b700",
Full code:
const StyledGreenBadge = styled(Badge)<{ badgeColor: string }>(
({ theme, ...props }) => {
console.log(props);
return {
"& .MuiBadge-badge": {
backgroundColor: props.badgeColor ?? "#44b700",
color: "#44b700",
width: "15px",
height: "15px",
borderRadius: "100%",
boxShadow: `0 0 0 2px ${theme.palette.background.paper}`,
"&::after": {
position: "absolute",
top: 0,
left: 0,
width: "100%",
height: "100%",
borderRadius: "50%",
animation: "ripple 1.2s infinite ease-in-out",
border: "1px solid currentColor",
content: '""'
}
},
"#keyframes ripple": {
"0%": {
transform: "scale(.8)",
opacity: 1
},
"100%": {
transform: "scale(2.4)",
opacity: 0
}
}
};
}
);
export default function SimpleBadge() {
return (
<StyledGreenBadge badgeColor="red" badgeContent={4} color="primary">
<MailIcon color="action" />
</StyledGreenBadge>
);
}
Demo
I know how to change the background and the the colour of the progress. I want to change the colour of the path of the progress before it fill in
export const CircleProgress = withStyles(() => ({
root: {
width: '262px !important',
height: '262px !important',
transform: 'rotate(220deg) !important',
color: 'blue',
},
}))(CircularProgress);
How do I change the trail color
you could add styles in such a way :
border-radius: 50%;
box-shadow: inset 0 0 1px 5px $color;
background-color: transparent;
Just play with a spread-radius.
MUI V5
react
<Box className="box-wrapper" sx={{ position: "relative", display: "inline-flex" }}>
<CircularProgress
variant="determinate"
thickness={3}
{...props}
className={"foreground"}
/>
<CircularProgress
variant="determinate"
value={100}
className={"background"}
thickness={3}
/>
<Box
sx={{
top: 0,
left: 0,
bottom: 0,
right: 0,
position: "absolute",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}>
<Typography
variant="caption"
component="div"
color="text.secondary">{`${Math.round(props.value)}%`}</Typography>
</Box>
</Box>
scss
.background {
position: absolute;
z-index: 1;
right: 0;
svg {
color: var(--color_300);
circle {
stroke-dashoffset: 0px !important;
}
}
}
.foreground {
position: relative;
z-index: 2;
svg {
color: var(--color_050);
circle {
}
}
}
const size = 120,
thickness = 9,
value = 22,
secColor = '#d1d1d1';
const progressSx = {
borderRadius: '50%',
boxShadow: `inset 0 0 0 ${thickness/44*size}px ${secColor}`,
};
<CircularProgress variant='determinate' size={size} thickness={thickness} value={value} sx={progressSx} />
function App() {
const { CircularProgress } = MaterialUI;
const size = 120,
thickness = 9,
value = 22,
secColor = '#d1d1d1';
const progressSx = {
borderRadius: '50%',
boxShadow: `inset 0 0 0 ${thickness/44*size}px ${secColor}`,
};
return (
<div className="App">
<CircularProgress variant='determinate' size={size} thickness={thickness} value={value} sx={progressSx} />
</div>
);
}
const container = document.getElementById('root');
const root = ReactDOM.createRoot(container);
root.render(<App />);
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/react#18/umd/react.production.min.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#18/umd/react-dom.production.min.js" crossorigin></script>
<script src="https://unpkg.com/#babel/standalone/babel.min.js"></script>
<script src="https://unpkg.com/#mui/material#latest/umd/material-ui.production.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel" src="./script.js"></script>
</body>
</html>
Workaround would be to use two circular progress bars on top of each other. Inspired by following example on MUI official doc: CircularProgressWithLabel
Currently, I am trying to place an overlay on top of a background image. For some reason I just can't seem to get the background color to lay on top of the image. Any suggestions would be greatly appreciated. I am using a lot of Material UI etc, so my styling is done using JS.
import React from 'react'
import Background from '../images/background.jpg'
// MUI STUFF
import Grid from '#material-ui/core/Grid'
import Container from '#material-ui/core/Container'
import Box from '#material-ui/core/Box'
import { makeStyles } from '#material-ui/core/styles'
const useStyles = makeStyles(theme => ({
background: {
backgroundImage: `url(${Background})`,
position: 'relative',
objectFit: 'cover',
width: '100%',
height: 400,
paddingTop: 70,
margin: 0
},
card: {
width: '100%'
},
overlay: {
position: 'absolute',
objectFit: 'cover',
width: '100%',
height: 400,
margin: 0,
backgroundColor: '#5BC2E7'
}
}))
const Home = () => {
const classes = useStyles()
return (
<Box>
<div className={classes.overlay}>
<Box className={classes.background}>
<Container>
Wyncode is so great and stuff. Track your jobs and stuff here.
</Container>
</Box>
</div>
<Box>
<Container>More stuff will go here</Container>
</Box>
</Box>
)
}
export default Home
try this css:
background: {
backgroundImage: `url(${Background})`,
position: 'relative',
objectFit: 'cover',
width: '100%',
height: 400,
paddingTop: 70,
margin: 0
},
overlay: {
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
margin: 0,
backgroundColor: '#5BC2E7'
}
With this html:
<Box>
<Box className={classes.background}>
<div className={classes.overlay}>
<Container>
Wyncode is so great and stuff. Track your jobs and stuff here.
</Container>
</div>
</Box>
<Box>
<Container>More stuff will go here</Container>
</Box>
</Box>
I’m having trouble aligning two components within another div in React. I’m using relative positioning for the parent div (snippetButtonHolder) and absolute positioning for its children (snippet and button). I want snippet to be centered in the parent and button to be under snippet and to the right, but for some reason when I use these attributes they are positioned relative to the entire page, not to the parent div. Does anyone have a suggestion as to what I should do differently?
const styles = {
module: {
marginTop: '30px',
padding: '20px',
},
snippet: {
backgroundColor: '#f2f2f2',
border: 'solid 1px #ccc',
borderRadius: '4px',
margin: '0 auto',
padding: '10px',
width: '100%',
position: 'absolute',
left: '50%',
},
snippetButtonHolder: {
width: '95%',
position: 'relative',
},
button: {
float: 'right',
marginTop: '5px',
position: 'absolute',
left: '94%',
},
};
export default class CodeSnippet extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div style={styles.module}>
<div style={styles.snippetButtonHolder}>
<div style={styles.snippet}>
<div
{'text will go here'}
</div>
{this.state.showButton ?
<button
style={styles.button}>
Press me
</button>
: null}
</div>
</div>
</div>
);
}
}
Give this a try:
const styles = {
module: {
marginTop: '30px',
padding: '20px',
},
snippet: {
backgroundColor: '#f2f2f2',
border: 'solid 1px #ccc',
borderRadius: '4px',
display: 'inline-block',
overflow: 'hidden',
padding: '10px',
},
snippetButtonHolder: {
textAlign: 'center',
width: '95%',
},
button: {
float: 'right',
marginTop: '5px',
},
};