How to add images to tailwind card from API - reactjs

I am trying to edit a project from github to learn how to call data from an API. Everything works fine so far and I have managed to change the card to a nice tailwind card. However, I am struggling to add an image.
Here is the code
const CardApi = ({ api }) => {
const renderDetail = (text, field) => <p>{text}: <span className="font-semibold">{api[field] || '-'}</span></p>
return (
<div class="max-w-sm bg-white border border-gray-200 rounded-lg shadow-md dark:bg-gray-800 dark:border-gray-700">
<a href="#">
<img class="rounded-t-lg" src="/docs/images/blog/image-1.jpg" alt="" />
</a>
<div class="p-5">
<a href="#">
<h5 class="mb-2 text-2xl font-bold tracking-tight text-gray-900 dark:text-white">Noteworthy technology acquisitions 2021</h5>
</a>
<p class="mb-3 font-normal text-gray-700 dark:text-gray-400">
{renderDetail('title', 'title')}
{renderDetail('brand', 'brand')}
{renderDetail('Description', 'description')}
{renderDetail('price', 'price')}
{renderDetail('rating', 'rating')}
</p>
<a href="#" class="inline-flex items-center px-3 py-2 text-sm font-medium text-center text-white bg-blue-700 rounded-lg hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">
Read more
<svg aria-hidden="true" class="w-4 h-4 ml-2 -mr-1" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M10.293 3.293a1 1 0 011.414 0l6 6a1 1 0 010 1.414l-6 6a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-4.293-4.293a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>
</a>
</div>
</div>
)
}
export default CardApi
I tried to edit by using the api results by trying to call the "thumbnail" just like I have done with "tile" etc
"products": [{
"id": 1,
"title": "iPhone 9",
"thumbnail": "https://i.dummyjson.com/data/products/1/thumbnail.jpg",
"images": ["https://i.dummyjson.com/data/products/1/1.jpg",
"https://i.dummyjson.com/data/products/1/2.jpg
I edited by adding image to renderDetail and adding "thumbnail" to the image class on the css but it didn't work. Any help will be appreciated. Thank you
const CardApi = ({ api }) => {
const renderDetail = (image,text, field) => <p>{text}: <span className="font-semibold">{api[field] || '-'}</span></p>
<img class="rounded-t-lg" src={thumbnail}" />

Related

My Navbar hamburger menu component in NextJS isn't working

For context, I followed this navbar component guide https://dev.to/andrewespejo/how-to-design-a-simple-and-beautiful-navbar-using-nextjs-and-tailwindcss-26p1
As stated, I am creating a website, but the Hamburger menu, when clicked, won't drop down. I also used TailwindCSS to create responsiveness within the website, where the hamburger menu only shows within the mobile view of the website. I believe the ternary operator should be working, but I don't believe the onClick method is working.
import Link from 'next/link';
import { useState } from 'react';
export const Navbar = () => {
const [navbar, setNavbar] = useState(false);
const handleClick = () => {
setNavbar(!navbar);
console.log("clicked");
};
return (
<>
<nav className='flex items-center flex-wrap bg-blue-400 p-3 '>
<Link href='/'>
<a className='inline-flex items-center p-2 mr-4 '>
<svg
viewBox='0 0 24 24'
xmlns='http://www.w3.org/2000/svg'
className='fill-current text-white h-8 w-8 mr-2'
>
<path d='M12.001 4.8c-3.2 0-5.2 1.6-6 4.8 1.2-1.6 2.6-2.2 4.2-1.8.913.228 1.565.89 2.288 1.624C13.666 10.618 15.027 12 18.001 12c3.2 0 5.2-1.6 6-4.8-1.2 1.6-2.6 2.2-4.2 1.8-.913-.228-1.565-.89-2.288-1.624C16.337 6.182 14.976 4.8 12.001 4.8zm-6 7.2c-3.2 0-5.2 1.6-6 4.8 1.2-1.6 2.6-2.2 4.2-1.8.913.228 1.565.89 2.288 1.624 1.177 1.194 2.538 2.576 5.512 2.576 3.2 0 5.2-1.6 6-4.8-1.2 1.6-2.6 2.2-4.2 1.8-.913-.228-1.565-.89-2.288-1.624C10.337 13.382 8.976 12 6.001 12z' />
</svg>
<span className='text-xl text-white font-bold uppercase tracking-wide'>
Portfolio
</span>
</a>
</Link>
<button className=' inline-flex p-3 hover:bg-blue-500 rounded lg:hidden text-white ml-auto hover:text-white outline-none' onClick={handleClick}>
<svg
className='w-6 h-6'
fill='none'
stroke='currentColor'
viewBox='0 0 24 24'
xmlns='http://www.w3.org/2000/svg'
>
<path
strokeLinecap='round'
strokeLinejoin='round'
strokeWidth={2}
d='M4 6h16M4 12h16M4 18h16'
/>
</svg>
</button>
<div className={` ${
navbar ? '' : 'hidden'
} w-full lg:inline-flex lg:flex-grow lg:w-auto`}>
<div className='lg:inline-flex lg:flex-row lg:ml-auto lg:w-auto w-full lg:items-center items-start flex flex-col lg:h-auto'>
<Link href='/'>
<a className='lg:inline-flex lg:w-auto w-full px-3 py-2 rounded text-white font-bold items-center justify-center hover:bg-blue-500 hover:text-white '>
Home
</a>
</Link>
<Link href='/'>
<a className='lg:inline-flex lg:w-auto w-full px-3 py-2 rounded text-white font-bold items-center justify-center hover:bg-blue-500 hover:text-white'>
Experience
</a>
</Link>
<Link href='/about'>
<a className='lg:inline-flex lg:w-auto w-full px-3 py-2 rounded text-white font-bold items-center justify-center hover:bg-blue-500 hover:text-white'>
About
</a>
</Link>
<Link href='/'>
<a className='lg:inline-flex lg:w-auto w-full px-3 py-2 rounded text-white font-bold items-center justify-center hover:bg-blue-500 hover:text-white'>
Projects
</a>
</Link>
<Link href='/'>
<a className='lg:inline-flex lg:w-auto w-full px-3 py-2 rounded text-white font-bold items-center justify-center hover:bg-blue-500 hover:text-white'>
Contact
</a>
</Link>
</div>
</div>
</nav>
</>
);
};
`
I have tried testing the onclick function by adding test buttons but they weren't displaying on the navbar.
try giving the onclick an anonymous function.
<button className='inline-flex p-3 hover:bg-blue-500 rounded lg:hidden text-white ml-auto hover:text-white outline-none' onClick={()=>handleClick()}>

How do I dynamically change the position of an element in react (tailwind)?

I have a project on react . In it I make a card, when you hover over it, information about this card should appear next to it. Here is the code:
export const CourseCard: React.FC<CourseCardProps> = () => {
const [isShown, setIsShown] = useState(false)
const [xInfoPos, setXInfoPos] = useState("0")
const [yInfoPos, setYInfoPos] = useState("0")
const cardRef = useRef<HTMLDivElement>(null)
const infoCardRef = useRef<HTMLDivElement>(null)
const formateXCord = (x : Number | undefined) => {
return "left-[" + x + "px]"
}
const formateYCord = (y : Number | undefined ) => {
return "top-[" + y + "px]"
}
const carMouseHandler = () => {
const cardEl = cardRef.current?.getBoundingClientRect()
const infoCardEl = infoCardRef.current?.getBoundingClientRect()
setXInfoPos(formateXCord(cardEl?.right))
setYInfoPos(formateYCord(cardEl?.top))
setIsShown(true)
}
return (
<>
<div ref={cardRef} onMouseEnter={carMouseHandler} onMouseLeave={()=>setIsShown(false)} className="py-0 px-4 relative snap-center flex flex-col w-1/4">
<div className="relative rounded-t-xl rounded-b-none bg-white shrink-0">
<img className="block w-full h-auto rounded-t rounded-b-none" src={cardImage} />
<button className="absolute top-2.5 right-2.5 h-6 w-6 rounded-full bg-gray-700 text-white font-bold text-center">♡</button>
</div>
<div className="py-2.5 px-3.5 bg-white border-[1px] border-solid border-gray-300 rounded-b border-t-0 flex-1 flex flex-col">
<div className="mb-2 flex flex-wrap items-center">
<span className="text-lg leading-4 text-cyan-600 mr-2"></span>
<span className="text-sm leading-4 text-blue-400 line-through"></span>
</div>
<h3 className="text-lg leading-4 mb-2 text-black font-normal h-14 overflow-hidden">TITLE</h3>
<div className="text-sm leading-5 opacity-40 mt-auto">Teacher Name</div>
</div>
{isShown &&
<div ref={infoCardRef} className={`flex flex-col absolute ${xInfoPos} ${yInfoPos} z-20 rounded-t-md w-full py-4 px-4 bg-slate-100`} >
<div className="mb-2 text-sm leading-5 text-black flex items-center">
<img className="block rounded-full w-7 h-7 shrink-0 mr-2" src={cardImage} />
Autor
</div>
<div className="text-lg leading-5 font-light text-black mb-2">
Title
</div>
<ul className="list-none p-0 mb-2 w-full block">
<li className="top-0 left-0 bg-white w-full" >
<img className="block w-full rounded-md top-0 left-0 right-0 bottom-0 h-full object-cover" src={cardImage}></img>
</li>
</ul>
<div className="text-sm leading-5 text-black mb-2">
Description
</div>
<ul className="-mx-2 list-none p-0 flex flex-wrap">
<li className="w-1/2 mb-2.5 text-sm leading-5 text-gray-800 flex items-center">
<img className="block shrink-0 mr-2.5"></img>
file
</li>
<li className="px-2.5 w-1/2 mb-2.5 text-sm leading-5 text-gray-800 flex items-center">
<img className="block shrink-0 mr-2.5"></img>
clock
</li>
<li className="w-1/2 mb-2.5 text-sm leading-5 text-gray-800 flex items-center">
<img className="block shrink-0 mr-2.5"></img>
books
</li>
<li className="px-2.5 w-1/2 mb-2.5 text-sm leading-5 text-gray-800 flex items-center">
<img className="block shrink-0 mr-2.5"></img>
lang
</li>
</ul>
<div className="pt-2 text-base leading-5 font-light text-gray-800 border-t border-solid border-t-black">footer</div>
</div>
}
</div>
</>
);
};
But I ran into a problem , the project uses tailwind and the concatenation doesn't work with it
"left-[" + x + "px]"
I found an article describing it https://v2.tailwindcss.com/docs/just-in-time-mode
but if I write like this
"left-[400px]"
it works.
The solution suggested in this article does not work because there can be many variants of x and y.
Right now the information is blocking the card which the cursor is pointing at.
Can you tell me how to solve this problem or give me another way to solve it?
Note: Information about the card should appear depending on the location of the card itself. If the card is located at the bottom then the information appears above it, if it is at the top then the information appears below it. Otherwise, on the right or left of the card.
My answer has two part.
Part one: tailwind generate style when you use and if you want to use dynamically you mist have confidence that style exist and you can generate all dynamic style one by one like this
"left-[400px]"
And part two: you have to use your classname like below
className={`left-[${x}px]`}

Make a smoothly opening menu effect using Tailwind CSS and React JS

I want to transform the menu to have a smooth transition when it opens, but it's not working for me.
I've also tried using hidden class, but ran into the same problem.
Is there a way to make it open smoothly?
My attempt:
import React from "react";
export default function ModerSideMenu({}) {
const [menu, setMenu] = React.useState({
home: true,
});
return (
<div className="w-64 bg-blue-900 h-full p-4 text-white">
<div className="relative">
<div className="flex flex-row items-center justify-between uppercase font-semibold w-full">
<div className="ml-2 flex-row flex items-center space-x-2">
<i className="fas fa-home" />
<p className="">Home</p>
</div>
<i
className={`transform transition-all ease-out duration-300 select-none fas ${
menu.home ? "fa-angle-up" : "fa-angle-down"
} mr-2`}
onClick={() => setMenu({ ...menu, home: !menu.home })}
/>
</div>
<div
className={`ml-4 mt-2 space-y-1 text-sm transform transition-all ease-out duration-300 z-20 select-none ${
!menu.home ? "-translate-y-full" : "translate-y-0"
}`}
hidden={!menu.home}
>
<p>- Home 1</p>
<p>- Home 2</p>
</div>
</div>
<div className="relative mt-2">
<div className="flex flex-row items-center justify-between uppercase font-semibold w-full">
<div className="ml-2 flex-row flex items-center space-x-2">
<i className="fas fa-home" />
<p className="">Home 2</p>
</div>
<i className="justify-self-end fas fa-angle-down mr-2" />
</div>
<div className="ml-4 mt-2 space-y-1 text-sm">
<p>- Home 3</p>
<p>- Home 4</p>
</div>
</div>
</div>
);
}

Blog using React, GraphQL, GraphCMS, NextJS, Tailwind CSS

I am creating my components => PostCard.JSX and pulling the data from graphCMS. Everything was going good and created more files under the components folder. I took a break and I exited. But when I came back to code again, I run the app using npm run dev, it gives me this error:
error - components/PostCard.jsx (35:27) # PostCard
TypeError: Cannot read property 'name' of null
33 |
34 | <img
35 | alt={post.author.name}
I do not know why this error happened now, however, the app was working before. here is my code for the PostCard.jsx
import React from 'react';
//import Image from 'next/image';
import moment from 'moment';
import Link from 'next/link';
const PostCard = ({ post }) => {
/* console.log(post); */
{/* <div>
{post.title}
{post.author.name}
{post.excerpt}
{post.featuredImage.url}
</div> */}
return (
<div className="bg-white shadow-lg rounded-lg p-0 lg:p-8 pb-12 mb-8">
<div className="relative overflow-hidden shadow-md pb-80 mb-6">
<img
src={post.featuredImage.url}
alt={post.title}
className="object-top absolute h-80 w-full object-cover shadow-lg rounded-t-lg lg:rounded-lg"
/>
</div>
<h1 className="transition duration-700 text-center mb-8 cursor-pointer hover:text-pink-600 text-3xl font-semibold">
<Link href={`/post/${post.slug}`}>{post.title}</Link>
</h1>
<div className="block lg:flex text-center items-center justify-center mb-8 w-full">
<div className="flex items-center justify-center mb-4 lg:mb-0 w-full lg:w-auto mr-8 items-center">
<img
alt={post.author.name}
height="30px"
width="30px"
className="align-middle rounded-full"
src={post.author.photo.url}
/>
<p className="inline align-middle text-gray-700 ml-2 font-medium text-lg">{post.author.name}</p>
</div>
<div className="font-medium text-gray-700">
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6 inline mr-2 text-pink-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
<span className="align-middle">
{moment(post.createdAt).format('MMM DD, YYYY')}
</span>
</div>
</div>
<p className="text-center text-lg text-gray-700 font-normal px-4 lg:px-20 mb-8">
{post.excerpt}
</p>
<div className="text-center">
<Link href={`/post/${post.slug}`}>
<span className="transition duration-500 ease transform hover:-translate-y-1 inline-block bg-pink-600 text-lg font-medium rounded-full text-white px-8 py-3 cursor-pointer">
Continue Reading
</span>
</Link>
</div>
</div>
)
};
export default PostCard;
Can someone help, please? I tried to solve it but I couldn't.
Thank you
try passing the initial props like this
<div className="lg:col-span-8 col-span-1">
{
posts.map((post, index) => (
<PostCard post={post.node} key={post.title} />
))
}
</div>
Take a look on the guy that is calling PostCard because it's passing post.author as null.
A good approach to avoid this kind of error to be shown to users is to use lodash get(post, 'author.name', ''), but this will not solve your problem, only avoid user to see it. Your problem is in the guy that's calling PostCard.

Conditionally render download button in react

I have a download button from which the user can download the assets. but I want only authenticated users can download. If the user is not authenticated and click on the download button I want to show them a modal with a login button on it. I have a modal component. I am using React.
Please help me.
Getting currently authenticated user from the firebase.
const {currentUser} = useAuth();
This is my code for the download button.
<a className="bg-secondary text-white font-bold py-3
px-5 rounded text-2xl focus:outline-none mt-3 block w-48" href="YOUR_URL">
<i className="animate-bounce fas fa-arrow-down mr-2"></i>
Download
</a>
Modal Code:
import React from "react";
import { useState } from "react";
export default function Modal() {
const [showModal, setShowModal] = useState(true);
console.log('modal');
return (
<>
{showModal ? (
<>
<div
className="justify-center items-center flex overflow-x-hidden overflow-y-auto fixed inset-0 z-50 outline-none focus:outline-none"
onClick={() => setShowModal(false)}
>
<div className="relative w-auto my-6 mx-auto max-w-3xl">
{/*content*/}
<div className="border-0 rounded-lg shadow-lg relative flex flex-col w-full bg-white outline-none focus:outline-none">
{/*header*/}
<div className="flex items-start justify-between p-5 border-b border-solid border-gray-300 rounded-t">
<h3 className="text-3xl font-semibold">
Modal Title
</h3>
<button
className="p-1 ml-auto bg-transparent border-0 text-black opacity-5 float-right text-3xl leading-none font-semibold outline-none focus:outline-none"
onClick={() => setShowModal(false)}
>
<span className="bg-transparent text-black opacity-5 h-6 w-6 text-2xl block outline-none focus:outline-none">
×
</span>
</button>
</div>
{/*body*/}
<div className="relative p-6 flex-auto">
<p className="my-4 text-gray-600 text-lg leading-relaxed">
I always felt like I could do anything. That’s the main
thing people are controlled by! Thoughts- their perception
of themselves! They're slowed down by their perception of
themselves. If you're taught you can’t do anything, you
won’t do anything. I was taught I could do everything.
</p>
</div>
{/*footer*/}
<div className="flex items-center justify-end p-6 border-t border-solid border-gray-300 rounded-b">
<button
className="text-red-500 background-transparent font-bold uppercase px-6 py-2 text-sm outline-none focus:outline-none mr-1 mb-1"
type="button"
style={{ transition: "all .15s ease" }}
onClick={() => setShowModal(false)}
>
Close
</button>
<button
className="bg-green-500 text-white active:bg-green-600 font-bold uppercase text-sm px-6 py-3 rounded shadow hover:shadow-lg outline-none focus:outline-none mr-1 mb-1"
type="button"
style={{ transition: "all .15s ease" }}
onClick={() => setShowModal(false)}
>
Save Changes
</button>
</div>
</div>
</div>
</div>
<div className="opacity-25 fixed inset-0 z-40 bg-black"></div>
</>
) : null}
</>
);
}
You could use button instead of a and use onClick to check if currentUser exists when you click button.
This is final code:
function x {
const {currentUser} = useAuth();
const downloadAssets = () => {
if(currentUser){
window.open("url assets here", '_blank', 'noopener,noreferrer')
}else{
// Open modal here
alert("User not authenticated");
}
}
return {
<>
...
<button onClick={downloadAssets}><i className="animate-bounce fas fa-arrow-down mr-2"></I>Download</button>
...
</>
}

Resources