How to make responsive React bootstrap cards that are vertically aligned? - javascript

I have a card component:
<Card className="m-5 border-0 shadow" style={styles.card}>
<Row>
<Col>
<Card.Img src={props.image} style={styles.cardImage}/>
</Col>
<Col>
<Card.Body>
<Card.Title as="h1">
{props.title}
</Card.Title>
<Card.Text as="h4" style={styles.cardText}>
{props.description}
</Card.Text>
</Card.Body>
{
props.link &&
<Button style={styles.button} href={props.url}>Read More</Button>
}
</Col>
</Row>
</Card>
The card is wrapped in a fluid <Container> and <CardGroup> component from react-bootstrap:
<Container fluid className="text-center">
<CardGroup className="m-5 d-block">
<Card />
</CardGroup>
</Container>
On desktop device it looks like this:
But it looks like this on mobile device:
Here are the styles:
const styles = {
card: {
backgroundColor: '#B7E0F2',
borderRadius: 55,
padding: '3rem'
},
cardImage: {
height: '100%',
objectFit: 'cover',
borderRadius: 55
}
};
Does anyone know how to fix this? Thanks.

Try this. For the <Row> component class with className row in css file assign property as follows:
.row {
display: flex,
flex-wrap:wrap
}

Try this one
<Card.Columns>
<Card >
<Card.Body>
<Card.Title style={{textAlign:"center"}}>title</Card.Title>
<Card.Text style={{textAlign:"left"}}>
description
</Card.Text>
</Card.Body>
<Card.Footer>
<Card.Text style={{textAlign:"right"}}>Link</Card.Text>
</Card.Footer>
</Card>
</Card.Columns>
For more details check out this Link

Related

How fetch data from parent element to child component?

Hello Im new in fetching and I have a problem, because I dont know how pass data from one component to child component. In the Fetch.js i have carousel and when I click on actual slide I want to display data in / learn and only ID what i clicked in carousel :(
I dont know exacly how to approach it and hope for help
Fetch.js
import {
Col,
Container,
Row,
Card,
Button,
Form,
Carousel,
} from "react-bootstrap";
import axios from "axios";
import { Link } from "react-router-dom";
export default function Fetch() {
const [posts, setPosts] = useState([]);
const [formData, setFormData] = useState({
USERNAME: "",
LINK_THUMBNAIL: "",
LINK_TITLE: "",
});
useEffect(() => {
fetchData();
}, [posts]);
const fetchData = async () => {
const { data } = await axios.get(
"https://api.test.dokume.net/public.php/object/465?include_data=true",
{
headers: {
"X-DOKUME-API-KEY":
"aJorRrbtlcNfONLWdg2tg0Wz1vEFeOjDhrxygQFUb9mdJSOexoUm6vjSmOt27hvq",
"X-DOKUME-PROFILEID": "21152",
},
}
);
setPosts(data.MESSAGE);
};
const postData = async (e) => {
e.preventDefault();
console.log("form submited");
const { data } = await axios.post(
"https://api.test.dokume.net/public.php/object/465?include_data=true",
formData,
{
headers: {
"X-DOKUME-API-KEY":
"aJorRrbtlcNfONLWdg2tg0Wz1vEFeOjDhrxygQFUb9mdJSOexoUm6vjSmOt27hvq",
"X-DOKUME-PROFILEID": "21152",
},
}
);
console.log("form success");
setFormData({
USERNAME: "",
LINK_THUMBNAIL: "",
LINK_TITLE: "",
});
};
const handleChange = (e) => {
setFormData({ ...formData, [e.target.name]: e.target.value });
};
if (posts.length === 0) {
return <div>Loading data...</div>;
}
return (
<Container
fluid
className="fetch pt-5 bg-light "
style={{ height: "100vh", overflow: "hidden" }}
>
<Row
className="row justify-content-center pt-5 "
style={{
alignItems: "center",
justifyContent: "center",
textAlign: "center",
fontSize: "4vw",
lineHeight: "90%",
fontWeight: "bold",
}}
>
<Col md sm lg className="pt-5">
<h1>Trusted by 25M+</h1>
<Carousel
controls={false}
indicators={false}
style={{
color: "blue",
}}
>
<Carousel.Item>
<h3>Small Business</h3>
</Carousel.Item>
<Carousel.Item>
<h3>Influencers</h3>
</Carousel.Item>
<Carousel.Item>
<h3>Tech Industy</h3>
</Carousel.Item>
</Carousel>
</Col>
</Row>
<Row style={{ justifyContent: "center" }}>
<Col
className="bg-secondary rounded mb-5"
md={3}
sm
lg
xl
style={{
marginLeft: "3rem",
maxHeight: "300px",
marginTop: "3rem",
marginRight: "3rem",
}}
>
<Form onSubmit={postData}>
<Form.Group controlId="formFile" className="mb-3">
<Form.Label>Attach Img URL</Form.Label>
<Form.Control
type="url"
name="LINK_THUMBNAIL"
onChange={handleChange}
value={formData.LINK_THUMBNAIL}
/>
</Form.Group>
<Form.Group className="mb-3" controlId="formBasicEmail">
<Form.Label>Title</Form.Label>
<Form.Control
onChange={handleChange}
type="text"
name="LINK_TITLE"
placeholder="Enter title"
value={formData.LINK_TITLE}
/>
</Form.Group>
<Form.Group className="mb-3" controlId="formBasicPassword">
<Form.Label>Username</Form.Label>
<Form.Control
onChange={handleChange}
type="text"
name="USERNAME"
placeholder="Username"
value={formData.USERNAME}
/>
</Form.Group>
<Button variant="primary" type="submit">
Submit
</Button>
</Form>
</Col>
<Col md={8} sm lg xl className=" mt-5">
<Carousel indicators={false} fade={true} style={{ height: "500px" }}>
{posts.map((item) => (
<Carousel.Item key={item.ID} className="bg-secondary rounded ">
<img
className="d-block rounded pt-5"
src={item.LINK_THUMBNAIL}
alt="First slide"
style={{
height: "300px",
width: "auto",
objectFit: "contain",
padding: "10px",
}}
/>
<Carousel.Caption
key={item.ID}
className="text-dark "
style={{ paddingLeft: "5rem" }}
>
<h3 className="pt-5 ">{item.LINK_TITLE}</h3>
<h3 className="pt-5 ">{item.USERNAME}</h3>
<h3 className="pt-5 ">
<a href={item.LINK_THUMBNAIL}> Link:</a>
</h3>
</Carousel.Caption>
</Carousel.Item>
))}
</Carousel>
</Col>
</Row>
</Container>
);
}
/learn - Learning.js
import React from "react";
import { Container, Row, Col, Card, Button } from "react-bootstrap";
const Learning = () => {
return (
<Container className="bg-secondary pt-5" style={{ height: "100vh" }}>
<Row className="pt-5" style={{ textAlign: "center" }}>
<Col className="pt-5">
<h1>Learn Component</h1>
<p> Tutaj wsadzisz caly fetch w kartach</p>
</Col>
</Row>
<Row
style={{
textAlign: "center",
alignItems: "center",
justifyContent: "center",
}}
>
<Col>
<Card style={{ width: "18rem" }}>
<Card.Img variant="top" />
<Card.Body>
<Card.Title>
<h3>PROFILE_PICTURE:</h3> Click
</Card.Title>
<Card.Text>
<h3>LINK_URL</h3> Click
</Card.Text>
<Card.Text>
<h3>USERNAME</h3> Click
</Card.Text>
<Card.Text>
<h3>STASH_NAME</h3>
Click
</Card.Text>
<Card.Text>
<h3>LINK_THUMBNAIL</h3>
Click
</Card.Text>
<Button variant="primary">Go somewhere</Button>
</Card.Body>
</Card>
</Col>
</Row>
</Container>
);
};
export default Learning;

Make elements on same line

I'm making a blog app using React, Material UI and Tailwindcss.
I made a grid of posts, but every postcard has a different height.
The question is: how to make all cards have the same height and all children in the same line?
Like This:
My Code:
Posts.jsx:
function Posts({ posts }) {
return (
<div className="mt-10">
<Container maxWidth="lg">
<Grid
container
rowSpacing={8}
columnSpacing={8}
direction="row"
justifyContent="center"
>
{posts.map((post, index) => (
<Grid key={index} item xs={12} sm={12} md={6} lg={4}>
<Card>
<CardActionArea>
<div className="flex flex-col ">
<CardHeader
avatar={
<Avatar>{post?.username?.substring(0, 1)}</Avatar>
}
title={post?.username}
subheader={"date"}
subheaderTypographyProps={{
color: "primary.dark",
}}
color="primary.main"
/>
<CardMedia
component="img"
height="194"
image={post?.photoURL}
/>
<CardContent>
<Typography variant="h6" color="primary.main">
{post.description}
</Typography>
</CardContent>
<Divider variant="middle" className="bg-[#fcfcfc]" />
<CardActions>
<IconButton>
<MdFavorite className="text-red-500" />
</IconButton>
</CardActions>
</div>
</CardActionArea>
</Card>
</Grid>
))}
</Grid>
</Container>
</div>
);
}
export default Posts;
You could try targeting the root <img> element directly by using the sx property. <CardMedia> would be updated like this:
...
<CardMedia
component="img"
height="194"
image={post?.photoURL}
sx={ {
['&.MuiCardMedia-root.MuiCardMedia-media.MuiCardMedia-img']: {
maxHeight: '194px'
}
} }
/>
...
As for making all children in the same line, you could:
set a maxHeight on the <CardHeader> and <CardContent> components, and
if you do not have control over the character length of the text in the header and content, use overflow: 'hidden', and textOverflow: 'ellipsis' to prevent long text strings from vertically expanding the <CardHeader> and <CardContent> components.
Try adding a fixed height on your tag. Also if the size of the images vary for each card it might cause a difference in the height of the whole card. If it doesn't work, try changing the height on your image to height: '194' to height: '194px'. Maybe this is what is causing an error.

Handling onClick for a particular element in react

I am trying to make a card grid where the user can expand the card to view its details. The issue I am facing with the react hooks is that the function is getting called for all cards instead of the particular card I am clicking the button. As a result, all the cards are getting expanded.
Here's my code for reference.
Any help is highly appreciated. Thank you!
function Album(props) {
return (
<div>
<Card className={classes.card}>
<Card.Text >
<p className={classes.heading}>
{props.blogTitle}
</p>
</Card.Text>
<Card.Body>
<Card.Img
src={props.imgsrc}
alt="Card image"
className={classes.cardMedia}
/>
{props.cardOpen &&
<AnimatePresence>
<motion.div
initial={{opacity:0}}
animate={{opacity:1, transition:0.3}}
>
<p className={classes.desc} gutterbottom>
{props.blogDescription}
</p>
<div href={props.blogLink}
style={{color:"gray", fontSize:17, fontFamily:"calibri", fontSmooth: "auto", cursor:"pointer", display:"flex", justifyContent:"center"}}>
<LocalLibraryIcon style={{marginRight:7}}/>Read blog
</div>
</motion.div>
</AnimatePresence>
}
{(props.cardOpen) ?
<div onClick={props.isOpen} style={{float:"right", cursor:"pointer"}}>
<ExpandLessIcon style={{fontSize:40, marginTop:10, color:" #909090"}}/>
</div> : (
<div onClick={props.isOpen} style={{float:"right", cursor:"pointer"}}>
<ExpandMoreIcon style={{fontSize:40, marginTop:10, color:" #909090"}}/>
</div>
)}
</Card.Body>
</Card>
</div>
);
}
export default function ProjectItems() {
const [cardOpen, setCardOpen]= useState(false);
return (
<React.Fragment>
<CssBaseline />
<main>
<div className={classes.heroContent}>
<Container maxWidth="md">
<Typography
variant="h2"
align="center"
color="textPrimary"
className={classes.root}
gutterBottom
>
Blogs
</Typography>
</Container>
</div>
<Container maxWidth="md">
<Grid container spacing={4}>
{blogData.map(post => (
<Grid item xs={12} sm={6} md={4} key={post.id}>
<div>
<Album
blogId={post.id}
blogTitle={post.title}
blogDescription={post.summary}
imgsrc={post.image_link}
blogLink={post.article_link}
isOpen={()=>{
setCardOpen(!cardOpen);
}}
cardOpen={cardOpen}
/>
</div>
</Grid>
))}
</Grid>
</Container>
</main>
</React.Fragment>
);
}

How to fix button to be interacted with, in carousel?

When I try to import a layer/button onto one of these cards it does not allow it to be clicked or interacted with. I believe the problem is with the carousel. What is a way I can fix this? The "CenterLayer" is supposed to act as a button and is the one I am having problems with. When I put this code the layer appears on the card as a footer but it's not allowed to be clicked. Is there anyone that can help me with this, please?
import React from "react";
import {
Card,
CardHeader,
CardBody,
CardFooter,
Box,
Image,
Heading,
Carousel,
Grommet,
Calendar,
Text,
} from "grommet";
import {CenterLayer} from "./EventsButton";
import { MainFooter } from "../Footer/Footer";
const Card0 = () => (
<Card pad="large" background="dark-1" gap="medium">
<CardHeader>
<Box height="small" width="small">
<Image src="./images/Photo.jpg" />
</Box>
</CardHeader>
<CardBody>The Stranahan High School Graduation</CardBody>
<Box direction="row" round gap="xlarge">
<CardFooter>
3/25/2021
</CardFooter>
<CardFooter>
<CenterLayer />
</CardFooter>
</Box>
</Card>
);
const Card1 = () => (
<Card pad="large" background="dark-1" gap="medium">
<CardHeader>
<Box height="small" width="small">
<Image src="./images/Photo.jpg" />
</Box>
</CardHeader>
<CardBody>Card1 The Stranahan High School Graduation</CardBody>
<CardFooter>Footer</CardFooter>
</Card>
);
const Card2 = () => (
<Card pad="large" background="dark-1" gap="medium">
<CardHeader>
<Box height="small" width="small">
<Image src="./images/Photo.jpg" />{" "}
</Box>
</CardHeader>
<CardBody>Card2 The Stranahan High School Graduation</CardBody>
<CardFooter>Footer</CardFooter>
</Card>
);
const Events = () => (
<Grommet>
<Heading textAlign="center" size="large" alignSelf="center" level="2" margin={{ left: "xlarge",
top: "large",}}>Upcoming Events</Heading>
<Carousel>
<Box direction="row" pad="large" round gap="small">
<Card0 />
<Card1 />
<Card2 />
</Box>
<Box direction="row" pad="large" round gap="small">
<Card1 />
<Card0 />
<Card2 />
</Box>
<Box direction="row" pad="large" round gap="small">
<Card2 />
<Card1 />
<Card0 />
</Box>
<Box direction="row" pad="large" round gap="small">
<Card1 />
<Card0 />
<Card2 />
</Box>
</Carousel>
<Heading textAlign="center" size="large" alignSelf="center" level="2" margin={{ left: "xlarge",
top: "large",}}>Past Events</Heading>
<Carousel>
<Box direction="row" pad="large" round gap="small">
<Card0 />
<Card1 />
<Card2 />
</Box>
<Box direction="row" pad="large" round gap="small">
<Card1 />
<Card0 />
<Card2 />
</Box>
<Box direction="row" pad="large" round gap="small">
<Card2 />
<Card1 />
<Card0 />
</Box>
<Box direction="row" pad="large" round gap="small">
<Card1 />
<Card0 />
<Card2 />
</Box>
</Carousel>
<Box direction="row" pad="xlarge" round gap="xlarge">
<Box height="medium" width="medium" margin={{left: "xlarge"}}>
<Calendar fill daysOfWeek />
</Box>
<Box margin={{left: "xlarge", top:"large"}}>
<Card background={'orange'} >
<CardBody height="medium" width="medium" margin={{right: "medium", bottom: "medium", left: "medium", top: "medium"}}>
<Text>At SEEF we take every opportunity to help the Stranahan community. We hope that our impact will lead others to do the same.</Text>
</CardBody>
</Card>
</Box>
</Box>
< MainFooter />
</Grommet>
);
export default Events
import React from 'react';
import { Add } from 'grommet-icons';
import { Box, Button, Grommet, Heading, Layer, Select, Text } from 'grommet';
import { grommet } from 'grommet/themes';
export const CenterLayer = () => {
const [open, setOpen] = React.useState();
const onOpen = () => setOpen(true);
const onClose = () => setOpen(undefined);
return (
<Grommet theme={grommet} >
<Box fill align="center" justify="center">
<Button
icon={<Add />}
label={
<Text>
<strong>More Information</strong>
</Text>
}
onClick={onOpen}
plain
/>
</Box>
{open && (
<Layer position="center" onClickOutside={onClose} onEsc={onClose}>
<Box pad="medium" gap="small" width="medium">
<Heading level={3} margin="none">
The Stranahan High School Graduation
</Heading>
<Text>This event will be taken place at City Hall in Fort Lauderdale</Text>
<Text>This event will be taken place on 3/25/2021 at 3:00PM</Text>
<Box
as="footer"
gap="small"
direction="row"
align="center"
justify="end"
pad={{ top: 'medium', bottom: 'small' }}
>
<Button
label={
<Text color="white">
<strong>Close</strong>
</Text>
}
onClick={onClose}
primary
color="status-critical"
/>
</Box>
</Box>
</Layer>
)}
</Grommet>
);
};
CenterLayer.storyName = 'Center';
CenterLayer.parameters = {
chromatic: { disable: true },
};
export default {
title: 'EventsButton',
};
Carousel is an interactive element, i.e. it has its own focus and navigation behavior, and for UX & accessibility reasons you shouldn't place nested interactive elements inside of each other, hence I'd try to avoid a button inside of a card, inside of a Carousel.
That being said, the button you've placed in the card is placed 'behind' the Carousel, so moving up its z-index would solve the problem.
Add this style to a Card and it should do trick
<Card style={{ zIndex: "100" }} ... >
I chose 100 as a random number, feel free to make it smaller according to your app behavior.

Call a Function on Tab click based on key?

These are my tabs and tables and I want to call different functions based on tabKey when you click on the tab.
<Paper className={classes.root} style = {{paddingTop:50}}>
<Grid>
<TabSelector
displayType="button"
showTab={"Org Details"}
showCount={false}
highlightTab={true}
onClick={() => this.getTabs.bind(this)}
>
<Tab name="Org Details" tabKey="gridOrgDetails">
<p>
<Grid>
<Paper className={classes.root} style={{ paddingTop: 50 }}>
<a href="#gridOrgDetails" id="gridOrgDetails" />
<Paper style={{ backgroundColor: "#759FEB" }}>
<Typography> ORG Details </Typography>
</Paper>
<EnhancedTable
checkBoxEnabled={false}
Data={{ rows: this.getOrg(), headCells: orgDeatils }}
rowsPerPage={5}
orderBy="Call_Date_vod__c"
order="desc"
/>
</Paper>
</Grid>
</p>
</Tab>
<Tab
name="License Details"
tabKey="gridLicenseDetails"
onClick={() => this.getLicenseDetails()}
>
<p>
<Grid>
<Paper className={classes.root} style={{ paddingTop: 50 }}>
<a href="#gridLicenseDetails" id="gridLicenseDetails" />
<Paper style={{ backgroundColor: "#759FEB" }}>
<Typography> License Details </Typography>
</Paper>
<EnhancedTable
checkBoxEnabled={false}
Data={{ rows: this.getOrg(), headCells: licenseDetails }}
rowsPerPage={5}
orderBy="Call_Date_vod__c"
order="desc"
/>
</Paper>
</Grid>
</p>
</Tab>
</TabSelector>;
This is my function where I am switching keys but this seems to be not working.
Can anyone please help me?
getTabs(f){
console.log(f.tabKey)
switch(f.tabKey) {
case "gridOrgDetails":
return this.getOrgDetails();
break;
case "gridLicenseDetails":
return this.getLicenseDetails();
break;
}
}
Here's a basic representation of what you're trying to achieve jsFiddle
link
const User = (props) => <div onClick = {props.onClick}>I am user
{props.user}</div>
class App extends React.Component {
constructor(props) {
super(props)
}
getTabs(f){
switch(f) {
case "gridOrgDetails":
console.log("gridOrgDetails")
break;
case "gridLicenseDetails":
console.log("gridLicenseDetails")
break;
}
}
render() {
return (
<div>
<div >
<User user="a" onClick={this.getTabs.bind(this,"gridOrgDetails")} />
<User user="b" onClick={this.getTabs.bind(this, "gridLicenseDetails")}/>
</div>
</div>
)
}
}
ReactDOM.render(<App />, document.querySelector("#app"))

Categories