Adding text over image in ReactJS by relative height and width - reactjs

I am trying the following code using HTML and CSS:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
.container {
position: relative;
text-align: center;
color: white;
}
.top-asad {
color: blue;
position: absolute;
top: 10%;
left: 50%;
transform: translate(-50%, -50%);
}
</style>
</head>
<body>
<h2>Image Text</h2>
<p>How to place text over an image:</p>
<div class="container">
<img src="http://www.pngall.com/wp-content/uploads/2016/05/Trollface.png" alt="Snow" style="width:100%;">
<div class="top-asad">Top Left</div>
</div>
</body>
</html>
I am trying to convert the above code to ReactJS using the following:
import React from "react"
import CardMedia from '#material-ui/core/CardMedia';
import { withStyles } from '#material-ui/core/styles';
import CardActionArea from '#material-ui/core/CardActionArea';
import { Card, CardContent } from "#material-ui/core";
const styles = theme => ({
card: {
display: 'flex',
},
details: {
display: 'flex',
flexDirection: 'column',
},
content: {
flex: '1 0 auto',
},
cover: {
width: 151,
},
controls: {
display: 'flex',
alignItems: 'center',
paddingLeft: theme.spacing.unit,
paddingBottom: theme.spacing.unit,
},
container: {
position: 'relative',
textAlign: 'center',
color: 'white',
},
topasad: {
color: 'blue',
position: 'absolute',
top: '10%',
left: '50%',
},
media: {
display: 'flex',
height: 100,
objectFit: 'contain',
alignItems: 'left',
},
})
function Header(props) {
const { classes } = props;
return (
<Card className={classes.card}>
<div className={classes.con}>
<CardContent className={classes.content}>
<CardMedia
component="img"
className={classes.media}
image="http://www.pngall.com/wp-content/uploads/2016/05/Trollface.png"
/>
</CardContent>
</div>
</Card>
)
}
// export default Header
export default withStyles(styles)(Header);
But I have been unable to place the text on top center of image as I have done using basic HTML and CSS. Can someone please help, please note that I am using relative position while placing text in my working HTML and CSS codes?
Edit:
I am doing this as a learning exercise. I am seeking an answer using ReactJS and MaterialUI

How about just add a div into your header that wraps the <CardMedia>, sets some styles, and includes the text you want to center?
function Header(props) {
const { classes } = props;
return (
<Card className={classes.card}>
<div className={classes.con}>
<CardContent className={classes.content}>
<div style={{position: 'relative'}} >
<CardMedia
component="img"
className={classes.media}
image="https://www.w3schools.com/css/img_lights.jpg"
/>
<div style={{
position: 'absolute',
color: 'white',
top: 8,
left: '50%',
transform: 'translateX(-50%)'
}} >Your text</div>
</div>
</CardContent>
</div>
</Card>
);
}
https://stackblitz.com/edit/react-b7esqk
Result:
Of course "Your text" could be whatever you want, including a prop on <Header> or the children of the header component.

Related

React how to set image as background of navbar

i'm using create-react-app and have a navbar that I would like to add a background image to. I have tried a couple different things like add the backgroundImage styling and adding an image tag but have not been able to make it work. The picture I am using is a .jpg and was downloaded from a stock image site. I added the image to my project by dragging it in and adding it to an images folder.
The current path from my header (what I called my navbar) file to my image is ../../images/pexels-kai-pilger-1341279.jpg
Here is my header file:
import React from 'react';
import { makeStyles } from '#material-ui/core';
import { ReactComponent as MenuLogo } from '../../images/menu-logo.svg';
const useStyles = makeStyles(theme => {
return ({
header: {
backgroundColor: '#d9d9d9',
boxShadow: '0rem 0rem 0rem 0.05rem #666666',
padding: '0rem 1rem 0rem 1rem',
position: 'relative',
width: '100vw',
height: 70,
zIndex: '100',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
backgroundImage: "url('SpaceLogo')"
},
headerActive: {
left: 352,
backgroundColor: '#d9d9d9',
boxShadow: '0rem 0rem 0rem 0.05rem #666666',
padding: '0rem 1rem 0rem 1rem',
position: 'relative',
width: '81.7%',
height: 70,
zIndex: '100',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center'
},
menuLogo: {
backgroundColor: '#d9d9d9',
border: 'none',
'&:hover': {
cursor: 'pointer'
}
},
});
});
function Header(props) {
const { toggleMenu, isMenuOpen } = props;
const classes = useStyles(props);
return (
<div className={ isMenuOpen ? classes.headerActive : classes.header } >
<button
className={classes.menuLogo}
onClick={() => toggleMenu()}>
<MenuLogo />
</button>
</div>
);
}
export default (Header);
I believe that is the only file that is needed for this question, but I can update if I need to add more info.
If I could get some help on how to get this set up, that would be great.
Bonus question: Is there a way for me to choose what part of the picture is visible in the navbar? For example, the image is a large square but my navbar is a thin rectangle. I would like to use the middle of the image as the background as opposed to the top.
header: {
backgroundColor: '#d9d9d9',
boxShadow: '0rem 0rem 0rem 0.05rem #666666',
padding: '0rem 1rem 0rem 1rem',
position: 'relative',
width: '100vw',
height: 70,
zIndex: '100',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
backgroundImage: `url(${SpaceLogo})`
},
This should be work

How to add a label to a border in mui?

I would like to have a list wrapped in a border which looks and behaves the same as a textfield border:
Example textfield and list which should have both same border.
In the image, the border around the list looks similar than the one around the textfield but most notably, the label is missing. How can I add the label and how would I set up the focus listeners to get the same hover and selection behaviour?
The typescript code for the list:
<List dense sx={{ borderRadius: 1, border: 1, borderColor: 'grey.600'}}>
<ListItem secondaryAction={<IconButton edge="end" aria-label="delete"><DeleteIcon /></IconButton>}>
<ListItemText primary="primary" secondary="group id"/>
</ListItem>
</List>
I am also open for alternative approaches. Thanks for the help.
Here is my answer using React and Mui (only for icon).
It relies on flex.
We have a main container that only draws its left, bottom and right borders.
Then we have a header container in charge of drawing the top border in two parts (before and after) and a section with an icon and title.
You can either pass an icon and a title, just a title, just an icon, or nothing at all.
borderedSection.js:
import React from "react";
import SvgIcon from "#mui/material/SvgIcon";
import styles from "./borderedSection.module.scss";
function BorderedSection({ icon, title, children }) {
return (
<div className={styles.mainContainer}>
<div className={styles.header}>
<div className={styles.headerBorderBefore}></div>
{(icon || title) && (
<div className={styles.headerTitle}>
{icon && <SvgIcon component={icon} />}
{title && <span className={styles.title}>{title}</span>}
</div>
)}
<div className={styles.headerBorderAfter}></div>
</div>
<div className={styles.childrenContainer}>{children}</div>
</div>
);
}
export default BorderedSection;
borderedSection.module.scss:
$border-color: #b2b2b2;
.mainContainer {
display: flex;
flex-direction: column;
max-width: 100%;
border-left: 1px solid $border-color;
border-bottom: 1px solid $border-color;
border-right: 1px solid $border-color;
border-radius: 5px;
margin: 1em;
.childrenContainer {
padding: 1em;
}
.header {
display: flex;
flex-direction: row;
width: 100% !important;
.headerBorderBefore {
border-top: 1px solid $border-color;
width: 1em;
border-top-left-radius: 5px;
}
.headerTitle {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-items: center;
gap: 0.25em;
width: fit-content;
height: 2em;
margin: -1em 0.5em 0em 0.5em;
overflow: hidden;
text-overflow: ellipsis;
font-size: 1em;
font-weight: 600;
}
.headerBorderAfter {
border-top: 1px solid $border-color;
width: 1em;
flex-grow: 2;
border-top-right-radius: 5px;
}
}
}
usage:
import React from "react";
import BorderedSection from "./borderedSection";
import InfoIcon from "#mui/icons-material/Info";
function Example() {
return (
<div style={{ padding: "2em" }}>
<BorderedSection icon={InfoIcon} title="Icon and title">
<div>a first child with quite a long text</div>
<div>a second child</div>
</BorderedSection>
<BorderedSection title="Title only">
<div>a first child with quite a long text</div>
<div>a second child</div>
</BorderedSection>
<BorderedSection icon={InfoIcon} >
<div>Icon only</div>
<div>a second child with quite a long text</div>
</BorderedSection>
<BorderedSection >
<div>No icon and no title</div>
<div>a second child with quite a long text</div>
</BorderedSection>
</div>
);
}
Here is how it looks:
I hope it helps
I now managed to hack a solution which looks the same. I do still hope though that there is a clean way to do this: result.
<FormLabel style={{marginLeft: "0.71em", marginTop: "-0.71em", paddingLeft: "0.44em", zIndex: 2, width: "4.2em", backgroundColor: "#383838", position: "absolute", fontSize: "0.75em"}}>Damage</FormLabel>
<List dense sx={{ borderRadius: 1, border: 1, borderColor: 'grey.600', "&:hover": { borderColor: 'grey.200' }}}>
<ListItem secondaryAction={<IconButton edge="end" aria-label="delete"><DeleteIcon /></IconButton>}>
<ListItemText primary="primary" secondary="group id"/>
</ListItem>
</List>
I needed the same thing. As I was poking around I noticed that MUI accomplished this by using the fieldset tag. I created a quick and dirty component (OutlinedBox) to get this effect:
import React from "react";
import {Box, FormLabel} from "#mui/material";
const OutlinedBox = (props) => {
const {
label,
children
} = props;
return (
<Box>
<FormLabel
sx={{
marginLeft: "0.71em",
marginTop: "-0.71em",
paddingLeft: "0.44em",
paddingRight: '0.44em',
zIndex: 2,
backgroundColor: (theme) => theme.palette.background.default,
position: "absolute",
fontSize: "0.75em",
width: 'auto',
}}>{label}</FormLabel>
<Box
sx={{
position: 'relative',
borderRadius: theme => theme.shape.borderRadius + 'px',
fontSize: '0.875rem',
}}
>
<Box
sx={{
padding: (theme) => theme.spacing(1),
display: 'flex',
gap: (theme) => theme.spacing(1),
flexWrap: 'wrap',
overflow: 'auto'
}}
>
{children}
</Box>
<fieldset aria-hidden={"true"} style={{
textAlign: 'left',
position: 'absolute',
bottom: 0,
right: 0,
top: '-5px',
left: 0,
margin: 0,
padding: '0 8px',
pointerEvents: 'none',
borderRadius: 'inherit',
borderStyle: 'solid',
borderWidth: '1px',
overflow: 'hidden',
minWidth: '0%',
borderColor: 'rgba(255, 255, 255, 0.23)',
}}
>
<legend style={{
float: 'unset',
overflow: 'hidden',
display: 'block',
width: 'auto',
padding: 0,
height: '11px',
fontSize: '0.75em',
visibility: 'hidden',
maxWidth: '100%',
'-webkit-transition': 'max-width 100ms cubic-bezier(0.0, 0, 0.2, 1) 50ms',
transition: 'max-width 100ms cubic-bezier(0.0, 0, 0.2, 1) 50ms',
whiteSpace: 'nowrap',
}}><span>{label}</span></legend>
</fieldset>
</Box>
</Box>
);
}
export { OutlinedBox };
// Example usage: <OutlinedBox label="Test">Some content here</OutlinedBox>
I figured I'd post it here in case anyone needs the same thing and comes across this question. All the styling stuff was copied from the styles MUI was using. There may be a better way to read some of this off of the theme, so if anyone decides to use this you may want to tweak it some.

Button doesn't disappear immediately; need to move mouse during animation using clip-path

I am setting the clipPath property from circle(0%) to circle(100%) using GSAP timeline.
let t1 = useRef();
useEffect(() => {
t1.current = gsap.timeline({
defaults: { duration: 0.5, ease: "Back.easeOut.config(2)" },
});
t1.current.paused(true); //to ensure animation doesn't play immediately
t1.current.to(".overlay", { clipPath: "circle(100%)" });
});
const handleClick = () => {
t1.current.play(); //start the animation
};
const handleClose = () => {
t1.current.reverse(0.2); //reverse the animation from 0.2 seconds
};
Complete React Component code:
import React, { useEffect, useRef } from "react";
import { gsap } from "gsap";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { faWindowClose } from "#fortawesome/free-solid-svg-icons";
export default function GSAPFullScreen() {
let t1 = useRef();
useEffect(() => {
t1.current = gsap.timeline({
defaults: { duration: 0.5, ease: "Back.easeOut.config(2)" },
});
t1.current.paused(true); //to ensure animation doesn't play immediately
t1.current.to(".overlay", { clipPath: "circle(100%)" });
}, []);
const handleClick = () => {
t1.current.play(); //start the animation
};
const handleClose = () => {
t1.current.reverse(0.2); //reverse the animation from 0.2 seconds
};
return (
<>
<div
className="overlay"
style={{
clipPath: "circle(0%)",
width: "100%",
height: "100%",
position: "fixed",
overflowY: "scroll",
overflowX: "hidden",
backgroundColor: "purple",
}}
>
<FontAwesomeIcon
icon={faWindowClose}
size="2x"
style={{
position: "absolute",
top: "2rem",
right: "2rem",
color: "white",
cursor: "pointer",
}}
onClick={handleClose}
/>
<div className="container md" style={{ color: "white" }}>
<br />
<div style={{ fontWeight: "bold" }}>This is an amazing Question</div>
<div>What is your question? Can you guess?</div>
<div>Option 1</div>
<div>Option 2</div>
<div>Option 3</div>
<div>Option 4</div>
</div>
</div>
<div className="container" style={{ height: "100vh" }}>
<div className="flex">
<button className="lg p-1 btn" onClick={() => handleClick()}>
Launch Animation
</button>
</div>
</div>
</>
);
}
Relevant CSS:
.container {
max-width: 1100px; /* Ensures heading is in center beyond 1100px*/
margin: 0 auto; /* Ensures to keep the 1100px container in middle of the screen;
until 1100px it will be on the side and this property will not have any affect*/
overflow: auto; /* This removes the space on the top of the heading which was created because of margin: 10px 0 on h1*/
padding: 0 40px;
}
.btn {
display: inline-block;
padding: 10px 30px;
cursor: pointer;
background: var(--primary-color);
color: #fff;
border: none;
border-radius: 5px;
}
.md {
font-size: 2rem;
}
.lg {
font-size: 3rem;
}
.flex {
display: flex;
justify-content: center; /* aligns along the main axis*/
align-items: center;
height: 100%;
}
.p-1 {
padding: 1rem; /*1 rem is usually 16px depending the size at root*/
}
.btn:hover:enabled{
transform: scale(0.98); /*reduces the size of button a bit*/
}
When the button has the pseudo class :hover a transform will be applied to the element, which means that it the stacking context is changed (see also Stacking without the z-index property).
To fix this you can add z-index: 1 to the overlay class or remove the transform from the :hover class (Not ideal).

How to keep react modal open when the popup window is clicked?

I'm very new to React js. After a series of youtube videos, I am working on a project.
My project searches for recipes with some keywords. I am trying to add a filter to filter out some recipes with a react modal. I know I can create a popup with React modal but not sure if this is the best way to have a popup.
Here's a screenshot of my filter popup:
The problem I'm having now is when I clicked on the input bar, the window closed.
Here's the modal component:
class Filter extends Component {
render() {
return ReactDOM.createPortal(
<div className="background"
style={{
position: 'absolute',
top: '0',
bottom: '0',
left: '0',
right: '0',
display: 'grid',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'rgba(0,0,0,0.3)',
}}
onClick={this.props.onClose}
>
<div
style={{
padding: 20,
background: '#fff',
borderRadius: '2px',
display: 'inline-block',
minHeight: '300px',
margin: '1rem',
position: 'relative',
minWidth: '300px',
boxShadow: '0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23)',
justifySelf: 'center',
}}
>
<form className="filter-form">
<div>
<p>Max Calories: </p>
<input type="text" value={this.state.input} onChange={this.props.handler}></input>
</div>
</form>
<hr />
<button onClick={this.props.onClose}>Save</button>
</div>
</div>,
document.getElementById('filter-popup')
)
}
}
Please let me know if other code is needed.

Adjusting toolbar height for material-table

The blue marked area takes up a lot of space. How can I adjust the height of the Toolbar?
Can you show by example?
Or how can I create a css file and import it into the toolbar. I need to change the height, I couldn't change whatever I did. please can you help with this?
There is almost no method I have not tried.
In short, I want to adjust the height of the Mtabletoolbar field marked in blue.
<MaterialTable
Toolbar: props => (
<div style={{ backgroundColor: 'blue', }}>
<MTableToolbar {...props} classes={{ customizeToolbar: "15px" }} />
</div>
),
/>
`
const styles = {
customizeToolbar: {
minHeight: "100px"
}
}
`
I have been trying for 2 days, please can you help with the subject?
I need to change the style structure below. especially I have to change the min-height
.MuiToolbar-regular {
min-height: 64px;
}
`
.MuiToolbar-root {
display: flex;
position: relative;
align-items: center;
}
.MuiToolbar-regular {
min-height: 56px;
}
#media (min-width:0px) and (orientation: landscape) {
.MuiToolbar-regular {
min-height: 48px;
}
}
#media (min-width:600px) {
.MuiToolbar-regular {
min-height: 64px;
}
}
.MuiToolbar-dense {
min-height: 48px;
}
`
Simply adjust the style of the element where blue appears,
and make the child vertical center as below:
<div
style={{
backgroundColor: "lightblue",
height: "200px",
display: "flex",
alignItems: "center"
}}
>
<MTableToolbar {...props} />
</div>

Resources