How to design a collapse component in reactjs with tailwind css - javascript

I am trying to create a collapse section component design in react JS with TailwindCSS, in the component, there will be an edit button to open and close the info section, and the edit info button will be next to the input field. The design is done(screenshot 1) but some adjustments are needed in the styling, which causes confusion about how to put the edit info button and info section code in a single component so that the design looks like the below screenshot.
<div>
<div
className={[
'flex',
'justify-between',
'relative',
'lg:px-20',
'xl:px-40',
'py-6',
].join(' ')}
>
<div className="flex items-center sm:flex-col lg:flex-row ">
<div className="flex flex-col lg:flex-row md:flex-row items-center">
<StreamTokenInputField />
//EDIT INFO BUTTON
<button
className="button"
onClick={() => setIsCollapseTrue(!isCollapseTrue)}
>
{i18n.t(Edit Info)}
{isCollapseTrue ? (
<IoIosArrowUp className="font-extrabold ml-2 text-lg" />
) : (
<FiChevronDown className="font-extrabold ml-2 text-lg" />
)}
</button>
</div>
</div>
</div>
// INFO SECTION
<div
className={[
'container',
'mx-auto',
'md:w-full',
'w-96',
'py-8',
'my-4',
'lg:py-20',
'lg:px-40',
'bg-skin-card',
'rounded-3xl',
!isCollapseTrue && 'hidden',
].join(' ')}
>
{/* OTHER CODES */}
</div>
</div>
screenshot 1
I have tried like this
<div
className={[
'flex',
'justify-between',
'relative',
'lg:px-20',
'xl:px-40',
'py-6',
].join(' ')}
>
<div className="flex items-center sm:flex-col lg:flex-row ">
<div className="flex flex-col lg:flex-row md:flex-row items-center">
<StreamTokenInputField />
<button
className={[
'flex',
'button',
'button-green',
'xl:px-6',
'md:px-2',
'lg:px-10',
'lg:my-6',
'md:my-6',
'mx-4',
'justify-center',
'uppercase',
'font-semibold',
].join(' ')}
onClick={() => setIsCollapseTrue(!isCollapseTrue)}
>
{i18n.t(buttonName)}
{isCollapseTrue ? (
<IoIosArrowUp className="font-extrabold ml-2 text-lg" />
) : (
<FiChevronDown className="font-extrabold ml-2 text-lg" />
)}
</button>
<div
className={[
'container',
'mx-auto',
'md:w-full',
'w-96',
'py-8',
'my-4',
'lg:py-20',
'lg:px-40',
'bg-skin-card',
'rounded-3xl',
!isCollapseTrue && 'hidden',
].join(' ')}
>
{/* OTHER CODES */}
</div>
</div>
</div>
</div>
However, the output shows like this: I want the info section to appear below the edit info button just like in the screenshot above.

If you want info section appear below button. You don't need lg:flex-row
So your code will be
<div className="flex items-center flex-col">
[...]
</div>
Also tailwind uses mobile-first breakpoint system. So you don't need to add sm: to sm:flex-col.
Same here <div className="flex flex-col lg:flex-row md:flex-row items-center">. You don't need to add lg:flex-row once you added md:flex-row. Any larger size than md will follow same class defined as md:
More information can be found here mobile-first-breakpoint-system

You can make use of the detail tag. Modify the animation anyhow you want or perhaps hide the default icon and specify a custom icon.
<details className="open:bg-white border-b open:ring-1 open:ring-black/5 open:shadow-lg p-6 rounded-lg transform-gpu delay-75 duration-100 ease-in-out ">
<summary className="leading-6 text-slate-900 dark:text-white font-semibold select-none">
Why do they call it Ovaltine?
</summary>
<div className="mt-3 text-sm leading-6 text-slate-600 dark:text-slate-400">
<p>The mug is round. The jar is round. They should call it Roundtine.</p>
</div>
</details>

Related

framer motion animation not working with element that rendered through map()

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

shrink a sticky div while scrolling down

hey i have in my site a stick div to create a new post
i want this div to animated shrink to a little box the will stick to the header while user scrolls down
and when im pressing on it or scrolling up this div will be visable again
any one can help me how to do this
<form
onSubmit={(e) => {
handleSubmit(e);
}}
className={` top-[106px] z-10 bg-main px-3 pt-2 rounded-lg border border-gray-300`}
>
{titlePost()}
{isPostActive && (
<div className="flex flex-col py-2 ">
<CommunitySelect community={community} setCommunity={setCommunity} />
{textArea()}
{imageBoxOpen && (
<DropzoneComponent
setImages={setImages}
maxImagesLength={maxImageLength}
/>
)}
{createPostButton()}
</div>
)}
</form>```

State Update prevents classList.toggle()

I am making a timeslot-picker component and want to toggle the class of each individual timeslot-item so it changes color and also add the timeslot information to an array of objects. If I update the state array with an onClick function the classList.toggle function doesn't seem to work, as none of the timeslots change color. I would appreciate any help on how to combine both functionalites. This is the part of my component required for the functionality:
<ul className="w-[180px] h-[400px] overflow-y-scroll flex flex-col gap-1 pt-4 relative">
<div className="text-center ">{day.day}</div>
{timeslots.map((timeslot) => (
<li key={Math.random()} className="mt-3">
<button
onClick={(e) => {
e.currentTarget.classList.toggle('bg-violet-500');
setRequestedTimeslots([
...requestedTimeslots,
{
day: day.day,
start: timeslot.start,
end: timeslot.end,
},
]);
}}
className="px-4 py-2 bg-[#F5F5F5] rounded-xl w-full text-center"
>
{timeslot.start} - {timeslot.end}
</button>
</li>
))}
</ul>

Drag and Drop ghost trailing on drop w/React

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>
))}

Tailwind Flex Box Responsive Grid with Cards issue

Here is where i started with
Preview
Code :
<div class="container my-12 mx-auto">
<div className="flex flex-wrap ">
{error ? <p>{error.message}</p> : null}
{!isLoading ? (
users.map(user => {
const { username, name, email } = user;
return (
<div
key={username}
className="w-full md:w-1/2 lg:w-1/3 my-5"
>
<article class="overflow-hidden rounded-lg shadow-lg">
<img
alt="Placeholder"
className="block h-auto w-full"
src="https://picsum.photos/600/400/?random"
/>
<header class="flex items-center justify-between leading-tight p-2 bg-white invisible lg:visible">
<h1 class="text-lg">{name}</h1>
<p class="text-grey-darker text-sm">
{email}
</p>
</header>
</article>
</div>
Then i tried to make it more spaced out like shown in the codepen example here :
https://codepen.io/codetimeio/pen/RYMEJe
but everytime i try to add some padding and margin it escapes to the next line and i cant figure out why it does that or how i can stop it
Here is the line i updated :
<div key={username} className="w-full md:w-1/2 lg:w-1/3 my-5 mx-5">
Here is my tailwind config file
module.exports = {
theme: {
container: {
center: true
},
screens: {
sm: "640px",
md: "768px",
lg: "1024px",
xl: "1280px"
},
fontFamily: {
display: ["Gilroy", "sans-serif"],
body: ["Graphik", "sans-serif"]
},
extend: {}
},
variants: {},
plugins: []
};
I really want to understand what im doing wrong so that i can use tailwind as my main templating framework
Here is updated code as per the given answer below
<div class="container my-12 mx-auto bg-gray-400">
<div className="flex flex-wrap ">
{error ? <p>{error.message}</p> : null}
{!isLoading ? (
users.map(user => {
const { username, name, email } = user;
return (
<div key={username} className="w-full p-5 md:w-1/2 lg:w-1/3">
<article className="overflow-hidden rounded-lg shadow-lg">
<img alt="Placeholder" className="w-full" src="https://picsum.photos/600/400/?random" />
<header className="flex items-center justify-between leading-tight p-2 bg-white">
<h1 className="text-lg">{name}</h1>
<p className="text-grey-darker text-sm">
{email}
</p>
</header>
</article>
</div>
It's happening because of the extra margins, w-1/3 means ~ width: 33.3333% If you add a margin on top of it, three can't fit in one line.
There are alternative ways (widths taking into account the gutter or gap property), but in exactly this case you could just use padding instead of margins, because you already have a presentational wrapping element around your cards.
Example: https://codepen.io/tlgreg/pen/RmLMOx
Not related, but few notes looking at your code:
Unless you use the old color palette in the config, grey-darker will not work.
img is block by default in v1.
invisible and lg:visible changes visibility, the header will take up space, if that not what you want, it should be hidden and lg:flex.

Categories

Resources