This is the current output, as you can see the image inside the circle is not positioned to the center of the circle. object-center is not doing anything.
I tried
// Skill component
function Skill({ directionLeft }: Props) {
return (
{/* Outer div */}
<div className='relative flex cursor-pointer group'>
{/* Inner image */}
<motion.img
className='object-center w-12 h-12 max-w-full border border-gray-500 rounded-full md:h-24 md:w-24 xl:w-32 xl:h-32 filter group-hover:grayscale'
initial={{ x: directionLeft ? -200 : 200, opacity: 0 }}
transition={{ duration: 1 }}
whileInView={{ x: 0, opacity: 1}}
src="typescript.png"/>
</div>
)
}
And these <Skill /> components are used inside here
<div className='grid grid-cols-4 gap-5'>
<Skill />
<Skill />
</div>
EDIT
First bug
object-position: center is used to position elements that have adjusted with the object-size property.
You can adjust how the replaced element's object's intrinsic size (that is, its natural size) is adjusted to fit within the element's box using the object-fit property. MDN
You'll want to center the <img> element from the parent with either Flexbox or Grid. I would recommend the latter using the grid and place-items-center Tailwind utility classes. place-items is a shorthand version of align-items and justify-items.
function Skill({ directionLeft }: Props) {
return (
{/* Outer div */}
<div className='grid place-items-center relative cursor-pointer group'>
{/* Inner image */}
<motion.img
className='object-center w-12 h-12 max-w-full border border-gray-500 rounded-full md:h-24 md:w-24 xl:w-32 xl:h-32 filter group-hover:grayscale'
initial={{ x: directionLeft ? -200 : 200, opacity: 0 }}
transition={{ duration: 1 }}
whileInView={{ x: 0, opacity: 1}}
src="typescript.png"/>
</div>
)
}
Related
I have a following set of images each with its own div and I want to show a popup with information on hover. Refer the following component code-
function Skill({ directionLeft, skill }: Props) {
return (
//group hover filter class in motion img used for special effect
<div className='group relative flex cursor-pointer'>
<motion.div
initial={{
x: directionLeft ? -200 : 200,
opacity: 0
}}
transition={{ duration: 0 }}
whileInView={{ opacity: 1, x: 0 }}
className='w-16 h-16 rounded-full border border-gray-500 object-cover xl:w-20 xl:h-20 filter group-hover:grayscale transition duration-300 ease-in-out'
>
<Image
src={urlFor(skill.skillImage).url()}
height={108} width={192} alt='' className=' w-16 h-16 rounded-full border border-gray-500 object-cover xl:w-20 xl:h-20 filter group-hover:grayscale transition duration-300 ease-in-out' />
</motion.div>
<div className='absolute opacity-0 group-hover:opacity-90 transition duration-300 ease-in-out z-20 group-hover:bg-[#1e313f] h-54 xl:w-72 rounded-lg p-5'>
<div className='flex flex-col items-center justify-center h-full'>
{/*loop over if multiple skill supports*/}
{skill.relevantWorkDone.map((relevantWorkDone, index) => (
<p key={index} className='uppercase tracking-[5px] text-gray-200 text-sm overflow-y-auto opacity-100 z-20= justify-center'>
-{relevantWorkDone}
</p>
))}
</div>
</div>
</div>
)
}
Now I want to adjust the hovering of the popup messages according to the location of the parent div in super parent grid.
Eg- instead of 1
I want something like 2-
The image div being hovered on is the one in the one in the last column if the 2nd last row.
I know I can pass a prop with the grid location like I and create a function depending upon the remainder to make it flow either left or right and if I is in the first half or second half of total elements to make it flow from either top or bottom.
But I don't know what tailwind CSS classes to use to achieve this.
Any help would be appreciated.
I'm trying to animate something like this :
https://drive.google.com/file/d/1WQCg7j49xd5XfuaYuC2YFQCUU-UXassp/view?usp=sharing
and here's my code :
<motion.div layout className="grid grid-cols-2 md:grid-cols-3 gap-8 py-10">
<motion.div
layout
style={cardOpen && { gridColumn: "1 / -1" }}
className={`card group relative w-full h-72 bg-primary rounded-lg overflow-hidden ${cardOpen ? "flex gap-5 p-10 shadow-inner" : "cursor-pointer"}`}
onClick={() => {
if (cardOpen) return;
setCardOpen(true);
}}
>
<AnimatePresence mode="wait">
{cardOpen && (
<motion.div
className="h-full absolute -bottom-32 -left-4 group-hover:brightness-30"
animate={{ y: [-100, 0] }}
>
<motion.img
className="h-full z-0"
src="/img/highlighted_projects/bg/moladin.svg"
alt=""
/>
</motion.div>
)}
{cardOpen || (
<motion.img
transition={{ ease: "easeIn", duration: 0.1 }}
initial={{ x: -500 }}
animate={{ x: [-500, 0] }}
exit={{ opacity: [1, 0] }}
className="absolute top-0 left-0 rounded-lg duration-300 w-full h-full object-cover brightness-50 group-hover:scale-110 group-hover:brightness-100"
src="/img/highlighted_projects/supra.jpeg"
alt=""
/>
)}
</AnimatePresence>
<motion.div className={`duration-300 text-white z-10 w-full ${cardOpen ? "" : "absolute bottom-3 left-3 group-hover:bottom-5"}`}>
<motion.div layout="position">
{cardOpen && <span className="montserrat font-light text-xs">Dec 2021 - Present</span>}
<div className="flex justify-between">
<h1 className="text-4xl font-bold">Moladin</h1>
{cardOpen && <X className="cursor-pointer" onClick={() => setCardOpen(false)} />}
</div>
<div className="flex gap-2 text-xs">
<span className="border rounded-full py-px px-2">Javascript</span>
<span className="border rounded-full py-px px-2">React</span>
<span className="border rounded-full py-px px-2">SCSS</span>
</div>
</motion.div>
{cardOpen && (
<motion.div className="mt-2" animate={{ opacity: [0, 1] }} transition={{ duration: 1, ease: "easeIn" }}>
<p className="montserrat">Yes. I'm one of many moladians you saw out there. We make selling/buying cars easier, safer, and profitable! My responsibility is mainly on CRM side of Moladin. But I sometimes handle the B2C side as well.</p>
</motion.div>
)}
</motion.div>
</motion.div>
<motion.div layout className="card w-full h-44 bg-blue-400">
moladin
</motion.div>
<motion.div layout className="card w-full h-44 bg-blue-400">
moladin
</motion.div>
</motion.div>
It is working, but then I make a component out of it and provide data for it. Now it's not working : https://drive.google.com/file/d/1XdqN-_BA5ABdNpQThI_KfF6D9UPlQKXO/view?usp=share_link
Here's the code :
{featuredProjects.map(project => <FeaturedProject key={project.projectName} {...project} /> )}
I tried this Framer motion new animation and exit not working with mapping
but it seems like not working to me or I wasn't able to understand it
How do I make it work?
Thanks.
I happen to make it working by using AnimatedSharedLayout :
<AnimateSharedLayout>
{featuredProjects.map(project => (
<FeaturedProject key={project.id} {...project} />
))}
</AnimateSharedLayout>
But I notice that it is deprecated and recommends me to use layoutId instead.
I tried using layoutId but it's not working...
and even removing layout itself :
As for now my question is kind of solved but I don't think its actually solved yet. So I'll just keep this thread open
I am having this problem when I try to reorder elements by dragging them. The reorder works but the functionality of changing places is not performing as desired. When you drag an element/image from a position x to position y it will change the position and it will stay there but on drop handler a "ghost" section it tries to go to the old position and the delete button on the overlay disappears.
I've provided a CodeSandbox link.
This is the component throwing the error.
as oposed to
I tried adding more event handlers like :
onDragOver
onDragDrop
onDragStart
onDragEnter
onDragLeave
and tried to add some logic to metigate the transition of images, but nothing worked.
{imageList.map((image, index, isDragging) => (
<div
key={index}
className="image-item w-1/2 sm:w-40 h-36 sm:p-2 px-1 pt-2"
draggable
onDragStart={(e) => handleDragStart(e, index)}
onDragEnd={(e) => handleDragEnd(e)}
onDragEnter={(e) => handleDragEnter(e, index)}
onDragLeave={(e) => handleDragLeave(e)}
onDragOver={(e) => handleDragOver(e, index)}
onDrop={(e) => handleDrop(e, index)}
>
<div
className={`border relative bg-white h-full transition duration-200 ease-in-out `}
>
{/* //!IMAGE */}
<span
className={` w-full h-full bg-center bg-contain bg-no-repeat `}
style={
{
// backgroundImage: `url(${image.dataURL})`
}
}
>
<img src={image.dataURL} width="200" alt="" />
</span>
{/* OVERLAY */}
<div className="z-10 overlay absolute w-full h-full flex items-center justify-center opacity-0 hover:opacity-100 transition-opacity duration-300 bg-black bg-opacity-50">
<div className="flex">
<button
type="button"
onClick={() => onImageRemove(index)}
title=""
>
<span className="w-5 h-5">
<button>delete</button>
</span>
</button>
</div>
</div>
</div>
</div>
))}
I'm creating a component in react that will display the avatar of the user but the catch is there will be limit on how many avatar will show. The solution that I'm thinking is using .slice(0,4).map then I'm gonna make a condition statement that if the length of the list is greater than 4 the button show all will appear. If the user click the button that rest of the user will pop up. The problem is how can display the rest of the user inside the pop up container?
<div className='pl-12 pr-6'>
<div className='flex items-center justify-right'>
{filterInfo &&
filterInfo
.slice(1, 10)
.map((data) => (
<img
className={`mr-2 rounded-full border-1px ${
active === data.creator[0]._id
? 'border-primary p-0.5 opacity-100'
: ''
} cursor-pointer transition duration-75 ease-in opacity-70`}
key={data._id}
id={data.creator[0]._id}
src={data.creator[0].accountProfileUploaded}
alt={`${data.creator[0].firstName} ${data.creator[0].lastName}`}
title={`${data.creator[0].firstName} ${data.creator[0].lastName}`}
style={{ width: '40px', height: '40px' }}
onClick={handleOnFilterByProfile}
/>
))}
{filterInfo && filterInfo.length >= 2 ? (
<div
className='shadow-md rounded-full relative'
style={{ width: '40px', height: '40px' }}
>
<ChevronDoubleDownIcon
className='h-4 w-4 absolute mt-3.5 ml-3 opacity-60 cursor-pointer hover:text-primary'
aria-hidden='true'
/>
</div>
) : null}
</div>
</div>
Thanks!
I am trying to fade out one div in the same space as I am trying to fade another div in using Framer Motion. Even with a delay on the transition, the object itself renders immediately which causes the other object in the same space to jump around.
Here is a small code example of what I'm trying to do:
const [short, setShort] = useState(false);
return (
<div>
<img src="image.jpg" />
<AnimatePresence>
{!short && (
<motion.span
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ delay: 1.5 }}
key="logoText"
>
TEXT
</motion.span>
)}
{short && (
<motion.span
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{delay: 1.5}}
key="searchBox"
>
SOME DIFFERENT TEXT
</motion.span>
)}
</AnimatePresence>
<Button onClick={() => setShort(!short)}>Toggle</Button>
</div>
);
};
Essentially the space taken up by SOME DIFFERENT TEXT instantly appears, pushing the Toggle button out to the right, and then pushes in once TEXT has disappeared. And then SOME DIFFERENT TEXT is pushed out again to the right as soon as the button is clicked.
How can I get both items to take up the same space, so they seamlessly transition into each other?
You can add the exitBeforeEnter prop (https://www.framer.com/api/motion/animate-presence/#animatepresenceprops.exitbeforeenter) to the AnimatePresence component, which will ensure TEXT is fully removed before SOME DIFFERENT TEXT appears