jy95
jy95

Reputation: 783

React Material UI - Responsive CardMedia

Currently, I am trying to build a gallery using React Material UI (with Card, ...). I have some issues to make the gallery responsive, as I might have different cover sizes :

enter image description here

Here is the code I used :

My card implementation :

import React from "react";
import { makeStyles } from '@material-ui/core/styles';

import Card from "@material-ui/core/Card";
import CardMedia from "@material-ui/core/CardMedia";
import CardActionArea from '@material-ui/core/CardActionArea';

const useStyles = makeStyles((theme) => ({
    gameRoot: {
        position: "relative",
        height: "100%"
    },
    gameCover: {
        zIndex: 1
    }
}));

function CardEntry(props) {
    const {game} = props;
    const classes = useStyles(props);

    function watchGame() {
       // some redirecting stuff not needed for this POC
    }

    return (
        <Card className={classes.gameRoot}>

                <CardActionArea onClick={watchGame}>
                    <CardMedia
                        component="img"
                        className={classes.gameCover}
                        image={game.imagePath}
                        title={game.title}
                    />
                </CardActionArea>
            
        </Card>
    );

}

export default CardEntry;

Which is called by the HOC Gallery I have :

import React from "react";

import { makeStyles } from '@material-ui/core/styles';

import Grid from "@material-ui/core/Grid";
import CardEntry from "./CardEntry";

// To dynamically change the number of items depending of browser
const useStyles = makeStyles((theme) => ({
    // inspired by the settings https://www.youtube.com/gaming uses ;)
    gameEntry: {
        // 2 items on [0, sm]
        [theme.breakpoints.only('xs')]: {
            "flex-basis": "calc((100% / 2) - 1%)"
        },
        // 4 items on [sm, md[
        [theme.breakpoints.only('sm')]: {
            "flex-basis": "calc((100% / 4) - 1%)"
        },
        // 8 items on [md, infinity]
        [theme.breakpoints.up('md')]: {
            "flex-basis": "calc((100% / 8) - 1%)"
        },
    }
}));

// The gallery component
function GamesGallery(props) {
    const classes = useStyles(props);

    const currentGames = [/*See comment below*/]

    return (
        <Grid
            container
            spacing={1}
            style={
                {
                    rowGap: "15px"
                }
            }
        >
            {
                currentGames
                    .map(game => 
                            <Grid 
                                key={game.playlistId ?? game.videoId} 
                                item 
                                className={classes.gameEntry}
                            >
                                <CardEntry game={game}/>
                            </Grid>
                    )
            }
        </Grid>
    );
}

For testing, here is some data (with corner cases) I could have in currentGames variable :

[
   {
      "title": "Astérix & Obélix XXL",
      "imagePath": "https://jy95.github.io/yt_gaming_library/covers/PLRfhDHeBTBJ7hPe8RxhK3FTXoqdFNL0BG/cover.webp",
      "playlistId": "PLRfhDHeBTBJ7hPe8RxhK3FTXoqdFNL0BG"
   },
   {
      "title": "Astérix & Obélix XXL 2",
      "imagePath": "https://jy95.github.io/yt_gaming_library/covers/PLRfhDHeBTBJ6FTJ2LSrdL4MaFM1Pl5nfo/cover.webp",
      "playlistId": "PLRfhDHeBTBJ6FTJ2LSrdL4MaFM1Pl5nfo"
   },
   {
      "title": "Astérix & Obélix XXL 2 : Mission Ouifix",
      "imagePath": "https://jy95.github.io/yt_gaming_library/covers/PLRfhDHeBTBJ6lDdIcNMFKsCzWtItCEcBq/cover.webp",
      "playlistId": "PLRfhDHeBTBJ6lDdIcNMFKsCzWtItCEcBq"
   },
   {
      "title": "Beyond Good & Evil",
      "imagePath": "https://jy95.github.io/yt_gaming_library/covers/PLRfhDHeBTBJ7GRN3EnqBEvfki5uAKiw5Z/cover.webp",
      "playlistId": "PLRfhDHeBTBJ7GRN3EnqBEvfki5uAKiw5Z"
   },
   {
      "title": "Bully",
      "imagePath": "https://jy95.github.io/yt_gaming_library/covers/PLRfhDHeBTBJ4l1G59ZVCUuTuZ-btLpPnm/cover.webp",
      "playlistId": "PLRfhDHeBTBJ4l1G59ZVCUuTuZ-btLpPnm"
   },
   {
      "title": "Chicken Invaders 5 - Cluck of the dark side",
      "imagePath": "https://jy95.github.io/yt_gaming_library/covers/PLRfhDHeBTBJ5x3Al4O71diHmivHNIRn2B/cover.webp",
      "playlistId": "PLRfhDHeBTBJ5x3Al4O71diHmivHNIRn2B"
   },
   {
      "title": "Guns Gore & Cannoli",
      "imagePath": "https://jy95.github.io/yt_gaming_library/covers/PLRfhDHeBTBJ6oiHK7lfTbOQlMWVHecx2I/cover.webp",
      "playlistId": "PLRfhDHeBTBJ6oiHK7lfTbOQlMWVHecx2I"
   },
   {
      "title": "Guns Gore & Cannoli 2",
      "imagePath": "https://jy95.github.io/yt_gaming_library/covers/PLRfhDHeBTBJ4ivg1J2leFzeuABXobVFNO/cover.webp",
      "playlistId": "PLRfhDHeBTBJ4ivg1J2leFzeuABXobVFNO"
   }
]

Thanks in advance,

Upvotes: 2

Views: 3225

Answers (1)

alisasani
alisasani

Reputation: 2968

Well, if I understand your main purpose correctly, modifying MuiCardActionArea-root and CardMedia-root will solve your problem. Please also check these two links about overriding styles and cardActionArea api in material-ui. https://material-ui.com/customization/components/ https://material-ui.com/api/card-action-area/

Here is the corrected code that will solve your problem:

`CaedEntry.js`

import React from "react";
import { makeStyles } from '@material-ui/core/styles';

import Card from "@material-ui/core/Card";
import CardMedia from "@material-ui/core/CardMedia";
import CardActionArea from '@material-ui/core/CardActionArea';

const useStyles = makeStyles((theme) => ({
    gameRoot: {
        position: "relative",
        height: "100%"
    },
    gameCover: {
        zIndex: 1,
        height: "inherit"
    },
    MuiCardActionArea:{
        height: "inherit",
        zIndex: 1
    }
}));

function CardEntry(props) {
    const {game} = props;
    const classes = useStyles(props);

    function watchGame() {
       // some redirecting stuff not needed for this POC
    }

    return (
        <Card className={classes.gameRoot}>

                <CardActionArea classes={{root: classes.MuiCardActionArea}} onClick={watchGame}>
                    <CardMedia
                        component="img"
                        classes={{root: classes.gameCover}}
                        image={game.imagePath}
                        title={game.title}
                    />
                </CardActionArea>
            
        </Card>
    );

}

export default CardEntry;

enter image description here

Upvotes: 1

Related Questions