Change inner div on hover in react grid tailwind - reactjs

So, for CSS I am using tailwindcss.
I have implemented integer based approach but when I hover quickly over the divs, the state remains un updated. If the value is 0, the first div is shown else the second div is shown.
Below is the code :
<div className="text-white m-8 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 grid-flow-row gap-8">
{
data.map((d,idx)=>(
<div onMouseEnter={()=>{toggleState(idx,1)}} onMouseLeave={()=>{toggleState(idx,0)}} key={'event'+idx} className="relative h-96 overflow-hidden" style={{background: "-webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0.1)), to(rgba(0, 0, 0, 1))), url('https://images.unsplash.com/photo-1475855581690-80accde3ae2b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=750&q=80') no-repeat",backgroundSize:'cover'}}>
{!v[idx] && (
<div className="absolute w-full py-2.5 bottom-0 inset-x-0 text-white text-center leading-4">
<div className='divide-y-2 px-2 h-full'>
<h2 class="mt-2 mb-2 font-bold text-2xl">{d.title}</h2>
<p class="text-lg">{d.dueDate}</p>
</div>
</div>
)}
{v[idx] && (
<div className="absolute w-full py-2.5 text-white text-center leading-4">
<div className='px-2 w-full'>
<h2 class="mt-2 mb-2 font-bold text-2xl">{d.title}</h2>
<p class="text-lg">{d.desc}</p>
<span className='bottom-0 right-0'>Go to Course =</span>
{/* <a href="#" className='align-bottom'>Go to the Course</a> */}
</div>
</div>
)}
</div>
))
}
</div>
The function for toggle state
const [v,setV] = useState([0,0,0,0,0,0,0]);
const toggleState = (idx,value)=>{
const newV = [...v];
newV[idx]=value;
setV(newV);
}
What is the best way to implement such utility?

It is hard to give you the best help given the out of context snippet of code you gave. But to improve the UX and the performance of your interaction you could avoid to handle all that in the list.
You could start isolating the components of the list and handle the mouse in/out in the single component.
Something like this:
<div>
{data.map((d,idx)=> <YourComponent d={d} />}
</div>
YourComponent:
function YourComponent(props) {
return (
<div onMouseEnter={...} onMouseLeave={...} >
...
</div>
)}
This way every single component would handle itself and the list will not re-render on every mouse move.

Related

Flexbox Items Not Vertically Centering In Tailwind

I am making a navbar in Tailwind consisting of links but I cannot get them to vertically center:
Here is what it looks like:
Steps I have tried:
items-center
justify-center
Setting the parent to flex-col
None of these options work.
How do you get the links to be exactly in the middle of the navbar vertically ?
Here is the code:
import React from 'react'
import Logo from '../images/Logo.png'
const Navbar = () => {
return (
<div className="flex justify-between items-center bg-gray-900">
<div className="">
<img className="w-40 py-2 px-2" src={Logo}></img>
</div>
<div className="flex flex-row items-center justify-center">
<p className="px-4 text-white">About</p>
<p className="px-4 text-white">Books</p>
<p className="px-4 text-white">Videos</p>
<p className="px-4 text-white">Quotes</p>
</div>
</div>
)
}
export default Navbar
The divs inside the flex class are aligned at the center, but the issue appears to be the first dive with the h-24 class which also contains the logo image. The logo aligns at the top of the div with the height of h-24 which is taller than the div containing the menu items. If you get rid of the h-24 or align the image vertically, they all align vertically. Try this:
<div class="flex justify-between items-center bg-gray-900">
<div class="h-24 flex items-center">
<img class="w-40 py-2 px-2" src="https://via.placeholder.com/150x50"></img>
</div>
<div class="flex">
<p class="px-4 text-white">About</p>
<p class="px-4 text-white">Books</p>
<p class="px-4 text-white">Videos</p>
<p class="px-4 text-white">Quotes</p>
</div>
</div>
It is working just fine. Please recheck the code you have sent, is it what it is producing the output you have produced in your question.
<div class="flex justify-between items-center bg-gray-900 h-24">
<div class="">
<img class="w-40 py-2 px-2" src=""></img>
</div>
<div class="flex ">
<p class="px-4 text-white">About</p>
<p class="px-4 text-white">Books</p>
<p class="px-4 text-white">Videos</p>
<p class="px-4 text-white">Quotes</p>
</div>
</div>
The output generated by the following code :
EDIT: The problem is that the list items were in tags and not tags - when changing the links from to , the list items centered vertically automatically without any further changes needed.
import React from 'react'
import Logo from '../images/Logo.png'
const Navbar = () => {
return (
<div className="flex justify-between items-center bg-gray-900 fixed inset-x-0 z-40">
<div className="">
<img className="w-40 px-2 mt-6" src={Logo}></img>
</div>
<div className="flex flex-row items-center justify-center mt-6">
<p className="px-4 text-white">About</p>
<p className="px-4 text-white">Books</p>
<p className="px-4 text-white">Videos</p>
<p className="px-4 text-white">Quotes</p>
</div>
</div>
)
}
export default Navbar

"Hydration failed because the initial UI does not match......" error showing when I m nesting multiple div inside next Link tag

React 18: Hydration failed because the initial UI does not match what was rendered on the server error showing when I am nesting multiple div in a Link tag
my code is given below:-
<Link href={'/product/wearcode'}>
<div className="lg:w-1/4 md:w-1/2 p-4 w-full">
<a className="block relative rounded overflow-hidden">
<img
alt="ecommerce"
className="m-auto h-[30vh] md:h-[36vh] block"
src="https://m.media-amazon.com/images/I/51QK16k7I6L._UL1000_.jpg"
/>
</a>
<div className="mt-4 text-center">
<h3 className="text-gray-500 text-xs tracking-widest title-font mb-1">
T-Shirts
</h3>
<h2 className="text-gray-900 title-font text-lg font-medium">
Wear The Code
</h2>
<p className="mt-1">₹216</p>
<p className="mt-1">S, M, L, XL, XXL</p>
</div>
</div>
</Link>
<Link href={'/product/wearcode'}>
<div className="lg:w-1/4 md:w-1/2 p-4 w-full">
<a className="block relative rounded overflow-hidden">
<img
alt="ecommerce"
className="m-auto h-[30vh] md:h-[36vh] block"
src="https://m.media-amazon.com/images/I/51QK16k7I6L._UL1000_.jpg"
/>
</a>
<div className="mt-4 text-center">
<h3 className="text-gray-500 text-xs tracking-widest title-font mb-1">
T-Shirts
</h3>
<h2 className="text-gray-900 title-font text-lg font-medium">
Wear The Code
</h2>
<p className="mt-1">₹216</p>
<p className="mt-1">S, M, L, XL, XXL</p>
</div>
</div>
</Link>
I want use this whole div as link so any client click on the image or text will go to the given page
This solution worked for me:
export default function MyApp({ Component, pageProps }: AppProps) {
const [showChild, setShowChild] = useState(false);
useEffect(() => {
setShowChild(true);
}, []);
if (!showChild) {
return null;
}
if (typeof window === 'undefined') {
return <></>;
} else {
return (
<Provider store={store}>
<Component {...pageProps} />
</Provider>
);
}
}

Tailwind CSS layout loses background

Using h-screen works until my datepicker comes up which expands the viewport
How do I make the background still fill (once a date box is hovered on it pops up the date picker)? The white space at the bottom of the date picker is the problem. I have a sidebar component for left-hand nav and a main content area.
Main content code:
.main-content {
#apply p-6 h-screen w-screen flex flex-col bg-slate-800 shadow-lg m-0 text-white;
}
Sidebar css:
.sidebar {
#apply h-screen w-20 flex flex-col bg-gray-900 shadow-lg m-0 px-3;
}
Datepicker code:
<div className="flex datepicker group-hover:scale-100 z-10">
<div className="grid grid-col-7 w-64 bg-gray-700 p-2 rounded-lg shadow-xl">
<div className="sub-text text-center">
{DateValue.monthLong} {DateValue.year}
<span
className="m-2 px-2 py-1 bg-gray-700 rounded-3xl hover:bg-gray-900 cursor-pointer"
onClick={(e) => changeMonth(e, false)}
>
<
</span>
<span
className="px-2 py-1 bg-gray-700 rounded-3xl hover:bg-gray-900 cursor-pointer"
onClick={(e) => changeMonth(e, true)}
>
>
</span>
</div>
<hr className="mb-2" />
<div className="grid grid-cols-7 pb-2">
<div className="text-center">Su</div>
<div className="text-center">Mo</div>
<div className="text-center">Tu</div>
<div className="text-center">We</div>
<div className="text-center">Th</div>
<div className="text-center">Fr</div>
<div className="text-center">Sa</div>
</div>
<div className="grid grid-cols-7">{daysAsInput()}</div>
</div>
</div>
CSS (Tailwind Apply)
.datepicker {
#apply absolute transition-all duration-100 scale-0;
}
.datepicker-day {
#apply m-1 bg-gray-700 rounded-lg shadow-lg
cursor-pointer items-center justify-center
p-1 text-sky-400 hover:bg-gray-900;
}
It scales to 100 when the input is hovered over.
Layout code:
<div className="flex">
<Sidebar />
<div className="main-content min-h-screen">{children}</div>
</div>
daysAsInput code:
const daysAsInput = () => {
// loop through the days in the month but start at the first day of the week
const inputs = [];
for (
let i = firstDayOfMonthAligned.day;
i <= firstDayOfMonthAligned.daysInMonth;
i++
) {
// create input that's grayed out if it's not in the current month
inputs.push(
<input
key={'previousMonth ' + i}
className="datepicker-day disabled:text-gray-400"
type="button"
value={i}
disabled={true}
onClick={dateChanged}
/>
);
}
for (let i = 1; i <= daysInMonth; i++) {
inputs.push(
<input
className="datepicker-day"
key={i}
type="button"
name="day {i}"
value={i}
onClick={dateChanged}
/>
);
}
return inputs;
};
The problem is caused by the fact that you position the datepicker absolute.
From the docs:
The element is removed from the normal document flow, and no space is
created for the element in the page layout.
You must take another approach, probably with z-index or javascript.
Try to change it to min-h-screen . That should do the magic
I think the problem is, we need to adjust the height styling of main-content class.
We can add "min-h-full" to the main-content class,
.main-content {
#apply p-6 h-screen w-screen flex flex-col bg-slate-800 shadow-lg m-0 text-white min-h-full;
}
This tailwind class will adjust the height of main-content to 100%. And the white background, have no room anymore.
Here was the reference of min-height
Thank you

Alignment with Tailwind and React

I'm trying to get two different visualizations to properly sit next to each other.
This is the current styling...
<div className="flex flex-col md:flex-row" >
<div className="w-full md:w-2/3">
<div className="text-center mt-4 flex justify-center items-center">
<h1 className="text-blue-500 text-lg font-semibold mr-5">
{format(new Date(selectedDate), 'do, MMMM - yyyy')}{' '}
</h1>
{isLoading && <Loader />}
</div>
<div>
<div className = "grid-cols-2 grid-flow-col" >
<div className = "grid-cols-1">
<h3 className="capitalize">Moodmap Daily Index</h3>
<Overview data={lineGraphData} timing={settingsData} />
</div>
<div>
<Expressions data={expressionsData} />
</div>
</div>
</div>
<div style={{ height: 100, width: 1000 }}>
<SubstanceDetails
fetchSubstances={fetchSubstances}
loading={loading}
data={data}
/>
</div>
</div>
</div>
For some reason when it renders, although I've made a bunch of changes, it comes out like this,
I want them to sit horizontally, with the bottom graph on the right hand side, ideally with the line graph a lot larger, taking up say 2/3. Unsure why this bug keeps happening.
You need to create a grid container by including the grid className in the element where you specify your grid columns:
<div className = "grid-cols-2 grid-flow-col" >
should become:
<div className = "grid grid-cols-2 grid-flow-col" >
https://tailwindcss.com/docs/display#grid
Note, to debug this you could have used the inspector to see that there was no grid container in your output.

Set state doesn't work when drop event is fired

When I remove the setState(in this case setImgDrag), the state does not take the value of the img selected, basically what I do is get the img from the sidebar and when the onDragStart event is fired I take the scr of the img and store it in a var called imgDrag, that works perfect, the point is that when I try to set the state of the img that is in the div, the state "imgDrag" does not get set. If you have a better implementation I will accept it.
import Img from "./img-card"
const DropImg=()=>{
const [img,setImg]=useState([])
const[imgDrag,setImgDrag]=useState()
const[position,setPosition]=useState({x:0,y:0})
let imgSelected;
let getImg=(e)=>{
let img=e.target.files
for(let i=0;i<img.length;i++){
setImg((prevState)=>{return ( img? [...prevState,URL.createObjectURL(img[i])] : [...prevState]) })
}
}
let dragOver=(e)=>{
e.preventDefault()
let xPosition=e.clientX
let yPosition=e.clientY
setPosition(()=>{return {["x"]:xPosition,["y"]:yPosition}})
console.log(position)
}
let drop=(e)=>{
e.preventDefault();
setImgDrag(imgSelected)
console.log(imgDrag)
}
return (
<div className="flex bg-gray-400">
<div className=" bg-gray-800 w-1/4 rem-width-25 px-5 pt-6 h-screen">
<div className="block">
<div className="relative bg-teal-500 border rounded py-12 m-auto text-center w-11/12 text-white ">
<input type="file" id="img" className="absolute top-0 m-auto left-0 cursor-pointer bg-gray-200 border border-gray-300 mb-3 outline-none py-10 px-5 rounded shadow-sm opacity-0" multiple onChange={getImg} />
Click Here Or Drop An Image
</div>
</div>
<div className="grid w-full grid-cols-3 gap-2 mt-10">
{(img? img.map((src,index)=>{return <Img key={index} id={index} draggable="true" onDragStart={e=>{ imgSelected= e.target.src}} src={src}/>}):null)}
</div>
</div>
<div onDrop={drop} onDragOver={dragOver} className="w-9/12 h-screen">
{imgDrag? <Img src={imgDrag} style={{width:400}}/>: null}
{img? null:<p id="drop-here" className="text-center">Drop Image Here!</p>}
</div>
</div>)
}
export default DropImg
It seems to have a problem using a variable - imgSelected, so try to also use useState for it.
// let imgSelected;
const [imgSelected, setImgSelected] = useState();
...
<div className="grid w-full grid-cols-3 gap-2 mt-10">
{(img? img.map((src,index)=>{
return <Img key={index}
id={index}
draggable="true"
// onDragStart={e=>{ imgSelected= e.target.src}}
onDragStart={e => setImgSelected(e.target.src) }
src={src}/>
}):null)
}
</div>

Resources