I want to add card using react-bootstrap in a project. I used Grid and CardDeck option from react-bootstrap. But all cards comes in a column (like this). But I want this cards comes with side by side, not in row.(I want my output like this image).
Here the code for card section
import Card from 'react-bootstrap/Card';
const Course = (props) => {
const {title, price,details,img} = props;
return (
<div>
<div className="col-md-4 col-12 mt-5 mx-auto">
<Card>
<Card.Img variant="top" src={img} />
<Card.Body>
<Card.Title>{title}</Card.Title>
<Card.Title>{price}</Card.Title>
<Card.Text>
{
details
}
</Card.Text>
</Card.Body>
</Card>
</div>
</div>
);
};
export default Course;
Where I pass the value
import React from "react";
import fakeData from "../FakedData/FakeData";
import Course from "../Course/Course";
import CardDeck from 'react-bootstrap/CardDeck';
const Home = () => {
return (
<div>
<div className="container">
<div className="row">
<CardDeck>
{fakeData.map((data) => {
return (
<Course
key={data.id}
title={data.title}
price={data.price}
details={data.details}
img={data.img}
/>
);
})}
</CardDeck>
</div>
</div>
</div>
);
};
export default Home;
I don't try this, it's the old way with modulo, should work, but not responsive
const Home = () => {
const numInRow = 4;
return (
<div>
<div className="container">
<div class="d-flex justify-content-center"> // <---- div first row
{fakeData.map((data, idx) => { //<--- note the idx
return (
<Course
key={data.id}
title={data.title}
price={data.price}
details={data.details}
img={data.img}
/>
{idx % numInRow === 0 && </div><div class="d-flex justify-content-center">} // <--- use modulo to close row and open a new one
);
})}
</div> //<-- div last row
</div>
</div>
);
};
Related
Please help me to solve my problem.
When I use
h-screen
to every element in Output, it makes scrolls on a single page which I don't need. My footer is not on the bottom of visible page, it's under Outler. How to make an Outlet not to shift my footer outside the visible page?
this is my main.jsx
import ReactDOM from 'react-dom/client';
import { createBrowserRouter, Outlet, RouterProvider } from 'react-router-dom';
import Index from './pages/Index';
import './index.css';
import ErrorPage from './pages/ErrorPage';
import Personnel from './pages/Personnel';
import NewNavbar from './components/NewNavbar';
import Footer from './components/Footer';
import Contacts from './pages/Contacts';
import About from './pages/About';
const AppLayout = () => {
return (
<div className=' flex justify-between flex-col bg-gradient-to-r from-zinc-900 via-zinc-700 to-zinc-900'>
<NewNavbar />
<Outlet />
<Footer />
</div>
);
};
const router = createBrowserRouter([
{
element: <AppLayout />,
path: '/',
errorElement: <ErrorPage />,
children: [
{
index: true,
element: <Index />,
},
{
path: '/personnel',
element: <Personnel />,
},
{
path: '/contacts',
element: <Contacts />,
},
{
path: '/about',
element: <About />,
},
],
},
]);
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<RouterProvider router={router} />
</React.StrictMode>
);
Index, About and Contacts are similar
import React from 'react';
const Index = () => {
return (
<main className='bg-red-500 '>This is main page
</main>
);
};
export default Index;
As I said before Personnel.jsx works as I expected, but not sure that is right.
import React from 'react';
import Administration from '../components/Administration';
import Teachers from '../components/Teachers';
const Personnel = () => {
return (
<div className='flex w-full flex-col'>
<div className='w-full px-[8%] lg:mx-auto lg:max-w-7xl text-white '>
<Administration />
<Teachers />
</div>
</div>
);
};
export default Personnel;
Each of these two elements has:
<div className='flex min-h-screen flex-col justify-center'>
h-screen will set an element with height: 100vh, meaning it will take the span of the entire viewport.
If I understand your problem correctly, you should set your AppLayout component with min-h-screen, so all the components inside it (NewNavbar, Outlet and Footer) will take at least the height of the viewport:
const AppLayout = () => {
return (
<div
className='min-h-screen flex justify-between flex-col bg-gradient-to-r from-zinc-900 via-zinc-700 to-zinc-900'
>
<NewNavbar />
<Outlet />
<Footer />
</div>
);
};
in checkOut js im unable to access the data inside the items arrey but i can access the length how is it possible i added 3 items i can see the items.lenth but when try to use items.map its not working showing error:
TypeError: Cannot read properties of undefined (reading 'image')
store.ts
import { configureStore } from "#reduxjs/toolkit";
import basketReducer from "./basketSlice";
//this is redux like a global store to store users items data
//when users put the items in the shopping cart
export const store = configureStore({
reducer: {
basket: basketReducer,
},
});
busketSlice.ts
import { createSlice } from "#reduxjs/toolkit";
interface BasketItem {
id: string;
title: string;
image: string;
description: string;
price: number;
category: string;
}
const initialState = {
items: [] as BasketItem[],
};
export const basketSlice = createSlice({
name: "basket",
initialState,
reducers: {
addToBasket: (state, action) => {
state.items = state.items.concat(action.payload);
},
removeFromBasket: (state, action) => {
const index = state.items.findIndex((basketItem: any) => basketItem.id === action.payload.id)
let newBasket = [...state.items];
if (index >= 0){
//if item exists in the basket remove it ...
newBasket.splice(index, 1);
} else {
console.warn(`cant remove (id: ${action.payload.id}) because its not in busket`)
}
state.items = newBasket;
},
},
});
export const { addToBasket, removeFromBasket } = basketSlice.actions;
// Selectors - This is how we pull information from the Global store slice
export const selectItems = (state: any) => state.basket.items;
export const selectTotal = (state: any) => state.busket.items.reduce((total:any, item:any) => total + item.price, 0);
const basketReducer = basketSlice.reducer;
export default basketReducer;
Cards.tsx
import Image from 'next/image';
import React, { useEffect, useState } from 'react';
import { StarIcon } from '#heroicons/react/solid';
// import Currency from 'react-currency-formatter';
import { useDispatch } from 'react-redux';
import { addToBasket } from "../basketSlice"
export default function Cards({id,title,image,description,price,category}: any) {
const dispatch = useDispatch()
const addItemsToBusket = () => {
const product = {
id,title,image,description,price,category
}
dispatch(addToBasket(product))//sending the product as an action to the redux store
}
const [rating, set] = useState(5);
const [hasPrime, setH] = useState(Math.random() < 1)
useEffect(() => {
set(Math.floor(Math.random() * 5) + 1 );
}, [])
useEffect(() => {
setH(Math.random() < 0.5 );
}, [])
return (
<div className="relative z-30 flex flex-col p-10 m-5 bg-white ">
<p className='absolute text-xs italic right-2 top-2'>{category}</p>
<Image className='mx-auto' src={image} height={200} width={200} alt=""/>
<h4 className='my-3'>{title}</h4>
<div className='flex'>
{Array(rating).fill(rating).map((_, i) => (
<StarIcon key={i} className='h-6 text-yellow-500'/>
))}
</div>
<p className='my-2 text-xs line-clamp-2 '>{description}</p>
<div>
{/* <Currency quantity={props.price} currency="INR"/> */}
<p className='mb-5'>₹{price}</p>
</div>
{hasPrime && (
<div className='flex items-center -mt-5 space-x-2'>
<img
className='w-12'
src="https://links.papareact.com/fdw" alt="" />
<p className='text-xs text-gray-500'>Free Next-Day Delivary</p>
</div>
)}
<button onClick={addItemsToBusket} className='mt-auto button'>Add to Busket</button>
</div>
)
}
ProductsFeed.tsx
import React from 'react'
import Cards from './Cards'
export default function({ products }: any) {
return (
<div className="grid grid-flow-row-dense mx-auto md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 md:-mt-40 lg:-mt-52">
{products.slice(0,4).map((product: any) => (
<Cards
key={product.id}
id={product.id}
title={product.title}
price={product.price * 60}
description={product.description}
category={product.category}
image={product.image}
/>
))}
<img className="md:col-span-full" src="https://links.papareact.com/dyz" alt="" />
<div className='md:col-span-2'>
{products.slice(4,5).map((product: any) => (
<Cards
key={product.id}
id={product.id}
title={product.title}
price={product.price * 60}
description={product.description}
category={product.category}
image={product.image}
/>
))}
</div>
{products.slice(5, products.length).map((product: any) => (
<Cards
key={product.id}
id={product.id}
title={product.title}
price={product.price * 60}
description={product.description}
category={product.category}
image={product.image}
/>
))}
</div>
)
}
checkout.tsx
import React from 'react'
import Nav from '../components/Nav'
import { signIn, signOut, useSession } from "next-auth/react"
import { useSelector } from 'react-redux';
import { selectItems } from '../basketSlice';
import CheckOutProduct from '../components/CheckOutProduct';
export default function CheckOut() {
const { data: session } = useSession()
const items = useSelector(selectItems);
console.warn(items)
return (
<div className='h-screen bg-gray-100'>
<Nav />
<main>
{!session? (
<div>
<div className='flex items-center justify-start p-10 m-10 space-x-4 overflow-hidden bg-white md:space-x-10'>
<img src="/checkout.svg" className='h-[7rem] w-[7rem] sm:w-[15rem] sm:h-[15rem]' alt=""/>
<div className=''>
<h1 className='font-bold md:text-[2rem] mb-1'>Your Amazon Cart is empty</h1>
<p className='text-[#007185] hover:text-red-600 cursor-pointer hover:underline hover'>Shop today's deals</p>
<button
className='px-10 py-2 mt-4 button'
onClick={() => signIn()}>Sign in to your account</button>
</div>
</div>
<div className=' h-[5rem] bg-white mx-10' />
</div>
): (
<div>
<div className='flex items-center justify-start p-10 m-10 space-x-4 overflow-hidden bg-white md:space-x-10'>
<img src="/checkout.svg" className='h-[7rem] w-[7rem] sm:w-[15rem] sm:h-[15rem]' alt=""/>
<div className=''>
<h1 className='font-bold md:text-[2rem] mb-1'>
{items.length === 0? "Your Amazon Cart is empty": "Shoping Basket"}
</h1>
<p className='text-[#007185] hover:text-red-600 cursor-pointer hover:underline hover'>Shop today's deals</p>
</div>
</div>
<div className='mx-10 bg-white '>
{items.length !== 0 && `You have ${items.length} items in your busket.`}
{items.map(({item, i}: any) => {
<CheckOutProduct
key={i}
image={item.image}
price={item.price}/>
})}
</div>
</div>
)}
</main>
</div>
)
}
checkOutProduct.tsx
import Image from 'next/image'
import React from 'react'
export default function CheckOutProduct({ id,title,image,description,price,category }: any) {
return (
<div className='grid grid-cols-5'>
<Image src={image} height={200} width={200} alt=""/>
<p>{price}</p>
</div>
)
}
Try to add like below because concat will not change object reference since updated values will not show in component.
addToBasket: (state, action) => {
state.items = [...state.items, ...action.payload];
}
I'm using tailwind with react. The problem is that my paragraph text is quite long. I have applied overflow-hidden to the div. But it is still flowing outside div. But it is not visible. But it is ruining my UI. As the pic is also getting stretched out due to the text overflowing. How do I stop the text from overflowing. So I only get the text that is visible inside div. I am using subString(0,50). It will fix the issue, if I use a smaller number. But I want to know is there any other way to fix it. So that the text does not go outside the div and occupies full space of div only. I tried many other properties to fix this issue. But no success so far.
I have uploaded a gif of my problem on imgur
Code
import React, { useEffect, useState } from "react";
import { BsBoxArrowUpRight, BsPencilSquare, BsTrash } from "react-icons/bs";
import { getActors } from "../api/actor";
let currentPageNo = 0;
let limit = 20;
export default function Actors() {
const [actors, setActors] = useState([]);
const [reachedToEnd, setReachedToEnd] = useState(false);
const fetchActors = async (pageNo) => {
const { profiles, error } = await getActors(pageNo, limit);
if (!profiles.length) {
currentPageNo = pageNo - 1;
return setReachedToEnd(true);
}
setActors([...profiles]);
};
const handleOnNextClick = () => {
if (reachedToEnd) return;
currentPageNo += 1;
fetchActors(currentPageNo);
};
const handleOnPrevClick = () => {
if (currentPageNo <= 0) return;
currentPageNo -= 1;
fetchActors(currentPageNo);
};
useEffect(() => {
fetchActors(currentPageNo);
}, []);
return (
<div className="p-5">
<div className="grid grid-cols-4 gap-5">
{actors.map((actor) => {
return <ActorProfile profile={actor} key={actor.id} />;
})}
</div>
<div className="flex justify-end items-center space-x-3 mt-5">
<button
type="button"
className="text-primary dark:text-white hover:underline"
onClick={handleOnPrevClick}
>
Prev
</button>
<button
type="button"
className="text-primary dark:text-white hover:underline"
onClick={handleOnNextClick}
>
Next
</button>
</div>
</div>
);
}
const ActorProfile = ({ profile }) => {
if (!profile) return null;
const [showOptions, setShowOptions] = useState(false);
const handleOnMouseEnter = () => {
setShowOptions(true);
};
const handleOnMouseLeave = () => {
setShowOptions(false);
};
let acceptedNameLength = 15;
const getName = (name) => {
if (name.length <= acceptedNameLength) return name;
return name.substring(0, acceptedNameLength) + "...";
};
const { name, avatar, about = "" } = profile;
return (
<div className="bg-white dark:bg-secondary shadow dark:shadow rounded h-20 overflow-hidden">
<div
onMouseEnter={handleOnMouseEnter}
onMouseLeave={handleOnMouseLeave}
className="flex cursor-pointer relative"
>
<img
src={avatar}
alt={name}
className="w-20 aspect-square object-cover"
/>
<div className="px-2 flex-1">
<h1 className="text-xl text-primary dark:text-white whitespace-nowrap">
{getName(name)}
</h1>
<p className="text-primary dark:text-white opacity-75">
{about.substring(0, 30)}
</p>
</div>
<Options visible={showOptions} />
</div>
</div>
);
};
const Options = ({ visible, onEditClick, onDeleteClick }) => {
if (!visible) return null;
return (
<div className="absolute inset-0 bg-primary bg-opacity-25 backdrop-blur-sm flex justify-center items-center space-x-5">
{" "}
<button
onClick={onDeleteClick}
type="button"
className="text-primary bg-white p-2 rounded-full hover:opacity-80 transition"
>
<BsTrash />
</button>
<button
onClick={onEditClick}
type="button"
className="text-primary p-2 rounded-full bg-white hover:opacity-80 transition"
>
<BsPencilSquare />
</button>
</div>
);
};
This is my first time I am asking question here. If I make any mistake, sorry from now on. I've been trying to build infinite scroll bar with 3 columns. But when the next data is fetched, the images act really weird. I've tried almost everything like "fixed, flex-nowrap", etc.. with tailwind. But none of them worked. I also made research almost for 3 hours and couldn't find any helpful resources. I'd be glad if you could help me!
video: https://streamable.com/ouk16y
import React, { useState, useEffect } from "react";
import InfiniteScroll from "react-infinite-scroll-component";
//components
//icons
import { AiOutlineHeart, AiOutlinePlus } from "react-icons/ai";
//styling
const Gallery = () => {
const apiKey = "apiKey";
const [pictures, setPictures] = useState([]);
const [page, setPage] = useState(1);
//fetching the api data
useEffect(() => {
fetch(
`https://api.unsplash.com/search/photos?page=${page}&query=office&client_id=${apiKey}`
)
.then((resp) => {
return resp.json();
})
.then((data) => {
const pictureData = [...new Set(data.results)];
setPictures((prev) => [...prev, ...pictureData]);
});
}, [page]);
return (
<InfiniteScroll
dataLength={pictures.length}
next={() => setPage((prev) => prev + 1)}
hasMore={true}
scrollThreshold={0.3}
>
<div className="columns-1 lg:columns-3 col-auto lg:w-5/6 mx-auto gap-8 space-y-4">
{pictures.map((picture) => (
<div className="" key={picture.id}>
<div className="flex p-2 lg:hidden ">
<img
className="rounded-full w-10 h-10"
src={picture.user.profile_image.medium}
alt={`${picture.name} profile`}
/>
<span className="pt-2 pl-2">{picture.user.name}</span>
</div>
<img className="resize-none" src={picture.urls.regular} />
{/* //icons for small devices// */}
<div className="flex mt-2 pl-2 mb-8 lg:hidden">
<AiOutlineHeart className="w-8 h-8 text-gray-600" />
<AiOutlinePlus className="w-8 h-8 ml-2 text-gray-600 " />
<button className="w-40 border ml-auto mr-4">Download</button>
</div>
</div>
))}
</div>
</InfiniteScroll>
);
};
export default Gallery;
'''
I have /pages/profile.js which calls the LovedOne element, passing values from props.
Debugging shows that these values are valid when passed
import React from "react";
import LovedOne from "../components/loved_one";
export const Profile = ({ loved_ones }) => {
const [session, loading] = useSession();
if (loading) return <div>loading...</div>;
if (!session) return <div>no session</div>;
return (
<Layout>
{session && (
<>
<img src={session.user.image} className="avatar" />
<h1>{session.user.name}</h1>
</>
)}
{loved_ones.map((loved_one, index) => (
<LovedOne
key={index}
firstname={loved_one.firstname}
surname={loved_one.surname}
email={loved_one.email}
/>
))}
<style jsx>{`
.avatar {
width: 220px;
border-radius: 10px;
}
`}</style>
</Layout>
);
};
However in /components/loved_one.js my props is undefined
import React, { useState, useRef } from "react";
export const LovedOne = ({ props }) => {
const [setActive, setActiveState] = useState("");
const [setHeight, setHeightState] = useState("0px");
const content = useRef();
function toggleAccordion() {
setActiveState(setActive === "" ? "active" : "");
setHeightState(
setActive === "active" ? "0px" : `${content.current.scrollHeight}px`
);
}
return (
<div>
<div className="row">
<button
className={`collection-item ${setActive}`}
onClick={toggleAccordion}
>
<i className="fas fa-plus teal-text"></i>
</button>
<div className="col s2">
{props.firstname} {props.surname}
</div>
<div className="col s2">{props.email}</div>
</div>
<div ref={content} style={{ maxHeight: `${setHeight}` }}>
<span>some stuff</span>
</div>
</div>
);
};
export default LovedOne;
I've tried passing single variables, and passing the entire loved_ones object. I get the same problem.
Any help much appreciated!
Have you tried passing props instead of {props} ?
lose brackets, try this way:
export const LovedOne = (props) => {