How do I center TabPanel in React material UI? - javascript

I am trying to create a list of articles with switching to a list of other entities in React + material UI. But I faced some problems, namely, I can't center Card, which displays an article in the way, that will correspond to centered Tabs. So, I get something like this:
Can anyone help me to make it to look symmetric?
I want the Card to be centered in the same way, the Tabs are.
TabsMenu.js, which itself is displayed:
import React from "react";
import {makeStyles} from "#material-ui/core/styles";
import Paper from "#material-ui/core/Paper";
import Tabs from "#material-ui/core/Tabs";
import Tab from "#material-ui/core/Tab";
import Box from "#material-ui/core/Box";
import Typography from "#material-ui/core/Typography";
import * as PropTypes from "prop-types";
import ArticlesList from "./ArticlesList";
function TabPanel(props) {
const {children, value, index, ...other} = props;
return (
<div
role="tabpanel"
hidden={value !== index}
id={`simple-tab-${index}`}
aria-labelledby={`simple-tab-${index}`}
{...other}
>
{value === index && (
<Box p={3}>
<Typography>{children}</Typography>
</Box>
)}
</div>
);
}
TabPanel.propTypes = {
children: PropTypes.node,
index: PropTypes.any.isRequired,
value: PropTypes.any.isRequired,
};
const useStyles = makeStyles({
root: {
flexGrow: 1,
},
tabpanel: {
marginLeft: "auto"
}
});
function a11yProps(index) {
return {
id: `simple-tab-${index}`,
'aria-controls': `simple-tabpanel-${index}`,
};
}
export default function CenteredTabs(props) {
const classes = useStyles();
const [value, setValue] = React.useState(0);
const handleChange = (event, newValue) => {
setValue(newValue);
}
return (
<Paper className={classes.root}>
<article>
<Tabs
value={value}
onChange={handleChange}
indicatorColor="primary"
textColor="primary"
centered
>
<Tab label="Articles" {...a11yProps(0)}/>
<Tab label="News" {...a11yProps(1)}/>
<Tab label="Authors" {...a11yProps(2)}/>
</Tabs>
<TabPanel value={value} index={0} className={classes.tabpanel}>
<ArticlesList articles={[{
imageSrc: "https://frontendmasters.com/static-assets/learn/og-learning-path-react.jpg",
authorImageSrc: "https://lh5.googleusercontent.com/--OlyHl449xI/AAAAAAAAAAI/AAAAAAAAAAA/ACevoQNk7ZZElQ_vKIQT_6d4HZw_wN3Qxg/mo/photo.jpg?sz=64",
authorName: "Denis Ivanenko",
dateTime: "2017-02-14",
imageAlt: "Article Image",
title: "Test title",
subtitle: "Test subtitle"
}]}/>
</TabPanel>
<TabPanel value={value} index={1} className={classes.tabpanel}>
Item Two
</TabPanel>
<TabPanel value={value} index={2} className={classes.tabpanel}>
Item Three
</TabPanel>
</article>
</Paper>
);
}
ArticlesList.js, which is used in TabsMenu.js
import React from 'react';
import {makeStyles} from '#material-ui/core/styles';
import List from '#material-ui/core/List';
import ArticleCard from "./ArticleCard";
import Box from "#material-ui/core/Box";
import Grid from '#material-ui/core/Grid';
const useStyles = makeStyles((theme) => ({
root: {
width: '100%',
maxWidth: 360,
backgroundColor: theme.palette.background.paper,
},
}));
export default function ArticlesList(props) {
const classes = useStyles();
return (
<React.Fragment>
<div className={classes.root}>
<Grid container
spacing={0}
direction="column"
alignItems="center"
justify="center"
style={{minHeight: '100vh'}}>
<Grid item xs={12}>
<Box width={"150%"}>
<List component="nav" aria-label="secondary mailbox folders">
<ArticleCard title={"Introducing \"Dead Simple Python\"\n"}
text={"Ever spent three hours trying to find that bit of knowledge that everyone seemed to have but you?\n" +
"\n" +
"As a self-trained Python developer, I've sometimes found myself stuck in that knowledge crater, between tutorials far simpler than real life, and articles more advanced than I could comprehend. Even the documentation felt like a firehose of information, making it nearly impossible to find the one basic thing I needed to know.\n" +
"\n" +
"In this series, I'll be exploring a few of these topics, in a way that hopefully makes them dead simple!\n" +
"\n" +
"Intended Audience\n" +
"While programmers at all experience levels may find this series useful, I'm specifically targeting Python novices. I am assuming, however, that you have a very basic understanding of programming. The coding topics especially will be more focused on the Python way of doing things, not on the underlying generic concept.\n" +
"\n" +
"With that said, if you're an intermediate-level Python developer, you may still find it helpful to follow along with the series. Although I've been working with Python for nearly eight years, some of these topics didn't really \"click\" for me until recent years. These are the explanations I wish I'd had!\n" +
"\n" +
"What You Won't Find Here\n" +
"All of the topics I'm discussing here go much, much deeper. However, I don't want to muddy the waters, so I'll be omitting a considerable amount of detail. Once you're comfortable with a topic, and have done it a few times yourself, I recommend going back and reading through the official Python documentation on the topic.\n" +
"\n" +
"A Note on Python Versions\n" +
"The official end-of-life for Python 2 is rapidly approaching, so you should learn and begin using Python 3 as soon as possible! This entire series is geared towards Python 3, with a bias towards 3.6 and 3.7, except as otherwise noted.\n" +
"\n" +
"Edits\n" +
"The articles in this series are frequently being reviewed by my fellow Python experts, and by the Dev community at large. I will expand and revise accordingly. Always check the edit timestamp at the top of the article.\n" +
"\n" +
"Roadmap\n" +
"The current series plan is below. Please note, I may rearrange, add, or remove planned sections."}
imageSrc={"https://insights.dice.com/wp-content/uploads/2017/09/shutterstock_315465929.jpg"}
authorImageSrc={"https://lh5.googleusercontent.com/--OlyHl449xI/AAAAAAAAAAI/AAAAAAAAAAA/ACevoQNk7ZZElQ_vKIQT_6d4HZw_wN3Qxg/mo/photo.jpg?sz=64"}
authorName={"Denis Ivanenko"}/>
</List>
</Box>
</Grid>
</Grid>
</div>
</React.Fragment>
);
}
ArticleCard.js
import React from "react";
import {red} from '#material-ui/core/colors';
import makeStyles from "#material-ui/core/styles/makeStyles";
import Card from "#material-ui/core/Card";
import CardHeader from "#material-ui/core/CardHeader";
import Avatar from "#material-ui/core/Avatar";
import IconButton from "#material-ui/core/IconButton";
import CardMedia from "#material-ui/core/CardMedia";
import CardContent from "#material-ui/core/CardContent";
import Typography from "#material-ui/core/Typography";
import CardActions from "#material-ui/core/CardActions";
import clsx from "clsx";
import FavoriteIcon from '#material-ui/icons/Favorite';
import ShareIcon from '#material-ui/icons/Share';
import Button from "#material-ui/core/Button";
const useStyles = makeStyles((theme) => ({
root: {
width:"155%",
gridColumn: "2/span 7"
},
media: {
height: 0,
paddingTop: '56.25%',
},
expand: {
transform: 'rotate(0deg)',
marginLeft: 'auto',
transition: theme.transitions.create('transform', {
duration: theme.transitions.duration.shortest,
}),
},
avatar: {
backgroundColor: red[500],
},
}));
export default function ArticleCard(props) {
const classes = useStyles();
const [expanded] = React.useState(false);
const title = props.title;
const date = props.dateTime;
const imageSrc = props.imageSrc;
const imageAlt = props.imageAlt;
const previewText = props.text.substring(0,158)+"...";
return (
<Card className={classes.root}>
<CardHeader
avatar={
<Avatar aria-label="recipe" className={classes.avatar}>
<img src={props.authorImageSrc} alt={props.authorName}/>
</Avatar>
}
title={title}
subheader={date}
/>
<CardMedia
className={classes.media}
image={imageSrc}
title={imageAlt}
/>
<CardContent>
<Typography variant="body2" color="textSecondary" component="p">
{previewText}
</Typography>
</CardContent>
<CardActions disableSpacing>
<IconButton aria-label="add to favorites">
<FavoriteIcon/>
</IconButton>
<IconButton aria-label="share">
<ShareIcon/>
</IconButton>
<Button
className={clsx(classes.expand, {
[classes.expandOpen]: expanded,
})}
aria-expanded={expanded}
aria-label="show more"
href={"/article"}
>
Read More
</Button>
</CardActions>
</Card>
);
}

This has got nothing to do with material-ui,
you've applied marginLeft: auto, which will not apply marginRight: auto, so it would not be center aligned
you should add marginRight: auto, as well to center it.
const useStyles = makeStyles({
root: {
flexGrow: 1,
},
tabpanel: {
marginLeft: "auto",
marginRight: "auto"
}
});

Related

Warning: Each child in a list should have a unique "key" prop. how to fix this?

Ive been using this project with out a problem and now all of a sudden I keep getting this error and it won't show my notes when I click on the my notes section. What do I have to do for it to go away. The backend is up and running and I can see the static data but it wont show on the app
import { makeStyles } from '#mui/styles'
import React from 'react'
import { Drawer } from '#mui/material'
import { Typography } from '#mui/material'
import List from '#mui/material/List'
import ListItem from '#mui/material/ListItem'
import ListItemIcon from '#mui/material/ListItemIcon'
import ListItemText from '#mui/material/ListItemText'
import { AddCircleOutlineOutlined, SubjectOutlined } from '#mui/icons-material'
import { useHistory, useLocation } from 'react-router-dom'
import AppBar from '#mui/material/AppBar'
import Toolbar from '#mui/material/Toolbar'
import { format } from 'date-fns'
import { red } from '#mui/material/colors'
const drawerWidth = 240 // 500 - subtract this number from
const useStyles = makeStyles((theme) => {
return{
page: {
background: '#E5E4E2',
width: '100%',
padding: theme.spacing(3)
},
drawer: {
width: drawerWidth
},
drawerPaper: {
width: drawerWidth
},
root: {
display: 'flex' //places the drawer side by side with the page content
},
active: {
background: '#E5E4E2'
},
// title:{
// padding: theme.spacing(13),
// alignItems: 'center'
// },
}})
export default function Layout({ children }) {
const classes = useStyles()
const history = useHistory()
const location = useLocation()
const menuItems = [
{
text: 'My Projects',
icon: <SubjectOutlined color="secondary" />,
path: '/'
},
{
text: 'Create Project',
icon: <AddCircleOutlineOutlined color="secondary" />,
path: '/create'
}
]
return (
<div className={classes.root}>
{/* side drawer */}
<Drawer
className={classes.drawer}
variant='permanent' //Lets MUI know we want it on the page permanently
anchor="left" // position of drawer
classes={{ paper: classes.drawerPaper}}
>
<div>
<Typography variant="h5" sx={{textAlign: 'center'}}>
Projects
</Typography>
</div>
{/* List / Links */}
<List>
{menuItems.map(item => (
<div className={location.pathname == item.path ? classes.active : null}>
<ListItem key={item.text} button onClick={() => history.push(item.path)}>
<ListItemIcon>{item.icon}</ListItemIcon>
<ListItemText primary={item.text} />
</ListItem>
</div>
))}
</List>
</Drawer>
<div className={classes.page}>
<div className={classes.toolbar}></div>
{children}
</div>
</div>
)
}
enter image description here
Updated
I'm sorry, of course, you should just move key to the parent div. I didn't notice it. Chris who answered in the comments is right and my answer was not needed. I rewrote the answer.
To have an unique key use index in map or like you did item.text if text is unique for each element in map.
menuItems.map((item,index) =>
The idea is that map has to contain unique key for each element.
In result we have:
<div key={item.text} className={location.pathname == item.path ? classes.active : null}>
or
<div key={index} className={location.pathname == item.path ? classes.active : null}>
And you need to remove key from the List.
Hope this helps! Regards,

React Manage Multiple Audios on Same Page and play one at a time using function based components

I am making a new react app which have multiple music cards on same page. I want to change the state of previous card before updating the state of new card. In short I want to pause previous audio before playing new one.
import React, { useState , useEffect , useRef} from "react";
import Card from '#mui/material/Card';
import CardContent from '#mui/material/CardContent';
import CardMedia from '#mui/material/CardMedia';
import Typography from '#mui/material/Typography';
import { CardActionArea } from '#mui/material';
import PlayArrowIcon from '#mui/icons-material/PlayArrow';
import IconButton from '#mui/material/IconButton';
import PauseICon from "#mui/icons-material/Pause";
import { logDOM } from "#testing-library/react";
export default function ActionAreaCard(props) {
const audioRef = useRef(new Audio("http://myinstants.org/games/22ecaa5e-f90f-4e81-96b1-b240751439fa.mp3"));
const [clicked, setClicked] = useState(false);
useEffect(() => {
audioRef.current.addEventListener('ended', () => setClicked(false));
if (clicked) {
audioRef.current.play();
} else {
audioRef.current.pause();
}
},[clicked]);
return (
<Card sx={{ maxWidth: 256 }} >
<CardMedia
component="img"
height="140"
image="https://picsum.photos/400/200"
alt="green iguana"
/>
<CardContent style={{ display: 'flex', flexDirection: 'column' }}>
<Typography gutterBottom variant="h5" component="div" style={{ textAlign: 'center', overflow: 'hidden', whiteSpace: 'nowrap', textOverflow: 'ellipsis' }}>
lorem Spem kjb j kl lk n lkn lk nlk n kln lkn kln kln kl nlk n vdr rtgvrt rtwbtr rtbvrt vbwrt vwretvw
</Typography>
{/* <PlayArrowIcon sx={{ height: 38, width: 38}}/> */}
<IconButton onClick={() => setClicked(!clicked)}>
{
clicked ? <PauseICon sx={{ height: 38, width: 38 }} /> : <PlayArrowIcon sx={{ height: 38, width: 38 }} />
}
</IconButton>
</CardContent>
</Card>
);
}
The above one is my playing card component.
The above GIF is the working app. In which when I play the second Audio it starts it before stopping the old when. MY background is from android development in which we have only one object of media player and we can manage this using that object. But here i found no solution may be we can do it by accessing the other component state in an other component or may be using a hook etc.
Make a common state in parent storing active playing:
const [activePlaying,setActivePlaying]=useState(null);
Make a handler for it:
const activePlayerhandler=useCallback((id)=>{
setActivePlaying(id);
},[id]);
Pass this handler as a prop:
...
{players.map((player,index)=>(
< ActionAreaCard onPlay={()=>activePlayerhandler(index)} playing={activePlaying===index}/>
))
...
now you just need to call this prop on play button click.

ReactJS: Images are sometimes not appearing on button click

I am a React noob. I am using Material UI and Material UI icons and React to create a title with a forward and back button, so the user can scroll through the pictures on display. When I press the forward button, the picture in "index 2" shows nothing. When I press the back button, the picture in "index 0" is blank (weird, right?). This seems like a super weird bug in my mind. Is there something I am missing here? It is making no sense to me.
Here is my code (as you can see I'm still editing things, so I still have the default text from when I grabbed this from Material UI).
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import clsx from 'clsx';
import Card from '#material-ui/core/Card';
import CardHeader from '#material-ui/core/CardHeader';
import CardMedia from '#material-ui/core/CardMedia';
import CardContent from '#material-ui/core/CardContent';
import CardActions from '#material-ui/core/CardActions';
import Collapse from '#material-ui/core/Collapse';
import Avatar from '#material-ui/core/Avatar';
import IconButton from '#material-ui/core/IconButton';
import Typography from '#material-ui/core/Typography';
import { red } from '#material-ui/core/colors';
import FavoriteIcon from '#material-ui/icons/Favorite';
import ShareIcon from '#material-ui/icons/Share';
import ExpandMoreIcon from '#material-ui/icons/ExpandMore';
import MoreVertIcon from '#material-ui/icons/MoreVert';
import ArrowForwardIosIcon from '#material-ui/icons/ArrowForwardIos';
import ArrowBackIosIcon from '#material-ui/icons/ArrowBackIos';
import image2019_0201 from '../images/2019_0201.jpeg';
import image2019_0202 from '../images/2019_0202.jpeg';
import image2019_0203 from '../images/2019_0203.jpeg';
const images = [
image2019_0201,
image2019_0202,
image2019_0203,
];
const imageText = [
"February 15, 2019",
"text2",
"text3"
]
const useStyles = makeStyles((theme) => ({
root: {
maxWidth: 345,
},
media: {
height: 0,
paddingTop: '56.25%', // 16:9
},
expand: {
transform: 'rotate(0deg)',
marginLeft: 'auto',
transition: theme.transitions.create('transform', {
duration: theme.transitions.duration.shortest,
}),
},
expandOpen: {
transform: 'rotate(180deg)',
},
avatar: {
backgroundColor: red[500],
},
}));
export default function Year2019() {
const classes = useStyles();
const [expanded, setExpanded] = React.useState(false);
const [currentImageIndex, setCurrentImageIndex] = React.useState(0)
const handleExpandClick = () => {
setExpanded(!expanded);
};
const handleForwardClick = () => {
console.log("current index", currentImageIndex);
if (currentImageIndex < images.length) {
setCurrentImageIndex(currentImageIndex + 1);
}
else {
setCurrentImageIndex(0);
}
console.log("new index", currentImageIndex);
}
const handleBackClick = () => {
console.log("current index", currentImageIndex);
if (currentImageIndex == 0) {
setCurrentImageIndex(images.length);
}
else {
setCurrentImageIndex(currentImageIndex - 1);
}
console.log("new index", currentImageIndex);
}
return (
<Card className={classes.root}>
<CardHeader
title="Title"
subheader="February 15, 2019"
/>
<CardMedia
className={classes.media}
image={images[currentImageIndex]}
title="image2019_0201"
/>
<CardContent>
<Typography variant="body2" color="textSecondary" component="p">
Waiting for the shuttle.
</Typography>
</CardContent>
<CardActions disableSpacing>
<IconButton aria-label="back" onClick={handleBackClick}>
<ArrowBackIosIcon/>
</IconButton>
<IconButton aria-label="forward" onClick={handleForwardClick}>
<ArrowForwardIosIcon/>
</IconButton>
<IconButton
className={clsx(classes.expand, {
[classes.expandOpen]: expanded,
})}
onClick={handleExpandClick}
aria-expanded={expanded}
aria-label="show more"
>
<ExpandMoreIcon />
</IconButton>
</CardActions>
<Collapse in={expanded} timeout="auto" unmountOnExit>
<CardContent>
<Typography paragraph>Method:</Typography>
<Typography paragraph>
Heat 1/2 cup of the broth in a pot until simmering, add saffron and set aside for 10
minutes.
</Typography>
<Typography paragraph>
Heat oil in a (14- to 16-inch) paella pan or a large, deep skillet over medium-high
heat. Add chicken, shrimp and chorizo, and cook, stirring occasionally until lightly
browned, 6 to 8 minutes. Transfer shrimp to a large plate and set aside, leaving chicken
and chorizo in the pan. Add pimentón, bay leaves, garlic, tomatoes, onion, salt and
pepper, and cook, stirring often until thickened and fragrant, about 10 minutes. Add
saffron broth and remaining 4 1/2 cups chicken broth; bring to a boil.
</Typography>
<Typography paragraph>
Add rice and stir very gently to distribute. Top with artichokes and peppers, and cook
without stirring, until most of the liquid is absorbed, 15 to 18 minutes. Reduce heat to
medium-low, add reserved shrimp and mussels, tucking them down into the rice, and cook
again without stirring, until mussels have opened and rice is just tender, 5 to 7
minutes more. (Discard any mussels that don’t open.)
</Typography>
<Typography>
Set aside off of the heat to let rest for 10 minutes, and then serve.
</Typography>
</CardContent>
</Collapse>
</Card>
);
}
Picture of the Forward and Backward Icons
In your handler functions, the array index may go out of bound. So you should modify your handler functions like below:
const handleForwardClick = () => {
if (currentImageIndex < (images.length - 1)) {
setCurrentImageIndex(currentImageIndex + 1);
}
else {
setCurrentImageIndex(0);
}
}
const handleBackClick = () => {
if (currentImageIndex == 0) {
setCurrentImageIndex(images.length - 1);
}
else {
setCurrentImageIndex(currentImageIndex - 1);
}
}

MUI breakpoints not recognizing "theme.breakpoints.down"

Goal: Hide navMenu when breakpoint is tablet and under, so I can replace with a hamburger menu
In terminal in VS code, it says compiled successfully, but in the browser I see:
TypeError: Cannot read properties of undefined (reading 'down')
I tried instructions here: StackOverflow Question, with no luck.
Can someone point me in the right direction?
import AppBar from "#mui/material/AppBar";
import Box from "#mui/material/Box";
import Toolbar from "#mui/material/Toolbar";
import Typography from "#mui/material/Typography";
import Button from "#mui/material/Button";
import { makeStyles } from "#mui/styles";
const useStyles = makeStyles((theme) => ({
navMenu: {
[theme.breakpoints.down('md')]: {
display: "none",
},
},
}));
const Navbar = () => {
const classes = useStyles();
return (
<Box sx={{ flexGrow: 1 }}>
<AppBar position="static" style={{ backgroundColor: "#061B2E" }}>
<Toolbar>
<Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
Name
</Typography>
<Box className={classes.navMenu}>
<Button color="inherit">Item 1</Button>
<Button color="inherit">Item 2</Button>
<Button color="inherit">Item 3</Button>
<Button color="inherit">Item 4</Button>
</Box>
</Toolbar>
</AppBar>
</Box>
);
};
export default Navbar;
Great question, which version of MUI are you using? They're kind of shifting away from makeSyles in favor of styled components, but this method is still supported (we still use it exclusively on my team). You may need to change your import statement to import { makeStyles } from '#material-ui/core';

How to create a dashboard grid with material-ui for react?

I have the following react code and the thing that I want is to create a dashboard, but before I need to create a Grid for it.
I have the following code (using the material-ui grid system "https://material-ui.com/components/grid/")
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import Paper from '#material-ui/core/Paper';
import Grid from '#material-ui/core/Grid';
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
},
paper: {
padding: theme.spacing(2),
textAlign: 'center',
color: theme.palette.text.secondary,
},
}));
function App() {
const classes = useStyles();
return (
<div>
<Grid container spacing={2}>
<Grid alignItems='baseline' item xs={3}>
<Paper className={`${classes.paper}`}>xs=3</Paper>
</Grid>
<Grid item xs={9}>
<Paper className={classes.paper}>xs=6</Paper>
<Paper className={`${classes.paper} ${styles.content}`} height="100%">xs=6</Paper>
</Grid>
</Grid>
</div>
);
}
export default App;
The result I want is the one from the 1 image, however the result that I have so far is the one from the second image, I am pretty sure that something is wrong with my code, I am not react expert.
Any help here will be aprecciated

Categories

Resources