I made the following using the nextjs and framer motion
I have a list of images that I'm mapping over and assigning them a layoutid and an optional variant to animate. The layoutid corresponds to the layoutid on the model1, model2, model3 pages.
Current Behaviour
When first going to the home page and clicking on an image I update some state and set the variant animation to false, this then tells that image to use the layoutid, it then fades out the other images and animates the clicked image into place on the component that is loaded (model1, model2, model3)...Great it works!
If you then click home in the navigation and try clicking an item again it doesn't work, all images are faded out and the clicked image doesn't animated.
Click refresh on the homepage and it works as desired!
here is the code for the page, I suspect it could be something to do with the routing or settings in _app.js
export default function Home() {
const router = useRouter();
const [isClicked, setIsClicked] = useState(null);
const onHandlerClick = (item, href, e) => {
e.preventDefault();
setIsClicked(item);
router.push(href, { scroll: false });
};
return (
<div className="l-grid l-grid-outter">
<div className="c-home-maincontent">
<div>
<main>
<motion.div className="l-grid-3-col" initial="initial" animate="enter" exit="exit" variants={{ exit: { transition: { staggerChildren: 0.1 } } }}>
{images.map((item, index) => {
return (
<motion.div
key={index}
className="c-home-overflowimage c-home-overflowimage2"
layoutId={`imageAnimation${item}`}
variants={isClicked === item ? false : postVariants}
transition={{ ...transition }}
>
<a href={`/model${item}`} onClick={(event) => onHandlerClick(item, `/model${item}`, event)}>
<motion.img
src="/yasmeen.webp"
whileHover={{
scale: 1.1,
}}
/>
</a>
</motion.div>
);
})}
</motion.div>
</main>
</div>
</div>
<Footer />
</div>
);
}
function MyApp({ Component, pageProps }) {
const router = useRouter();
return (
<>
<DefaultSeo {...Seo} />
<AnimateSharedLayout type="crossfade">
<AnimatePresence exitBeforeEnter initial={false}>
<Component {...pageProps} key={router.asPath} />
</AnimatePresence>
</AnimateSharedLayout>
</>
);
}
export default MyApp;
Updated the code to include an animate set to false if its the clicked item
<motion.div className="l-grid-3-col" initial="initial" animate="enter" exit="exit">
{images.map((item, index) => {
return (
<motion.div
key={index}
className="c-home-overflowimage c-home-overflowimage2"
layoutId={`imageAnimation${item}`}
animate={isClicked === item ? false : true}
variants={isClicked === item ? false : postVariants}
transition={{ ...transition }}
>
<a href={`/model${item}`} onClick={(event) => onHandlerClick(item, `/model${item}`, event)}>
<motion.img
src="/yasmeen.webp"
whileHover={{
scale: 1.1,
}}
/>
</a>
</motion.div>
);
})}
</motion.div>
Related
Actually I wanna create slider with dots, slider is working, but dots are hidden. How should I make dots visible while using react swipper slider.
I am using styled components for css. The thing is, I cannot find what is false in this part of code. please help me to figure out with this problem.
I tried to make my slider dots visible, however they are not showing.
this is my code
import { Pagination, Navigation, Scrollbar, A11y } from 'swiper';
import { Images } from 'assets/images';
import { useWindowDimensions } from 'hooks/useWindowDimensions';
import { useNavigate } from 'react-router-dom';
import { ROUTES } from 'utils/routeNames';
import { Swiper, SwiperSlide } from 'swiper/react';
// Import Swiper styles
import 'swiper/swiper.scss';
import {
CardAndDescriptionBlock,
CardBlock,
CountryImage,
TripDurationAndPrice,
TripDuration,
CardDescription,
TripCountryAndPrice,
CountryStarsPriceWrapper,
TripCountryAndStars,
TripPrice,
PricePerPerson,
TripCountry,
ReadMore,
DescriptionContainer,
} from './styled';
export const HotOffersCarousel = ({ hotOffers }) => {
const navigate = useNavigate();
const { width } = useWindowDimensions();
const navigateToTour = (id) => {
navigate(`${ROUTES.HOT_TOURS}/${id}`);
};
return (
<Swiper
slidesPerView={width < 768 ? 2 : 1}
spaceBetween={10}
slidesPerGroup={width < 768 ? 2 : 1}
loop={true}
pagination={{
dynamicBullets: true,
}}
modules={[Pagination, Navigation, Scrollbar, A11y]}
className="mySwiper"
>
{hotOffers?.map((item) => (
<SwiperSlide key={item.id}>
<CardAndDescriptionBlock>
<CardBlock>
<CountryImage background={item?.main_image}>
<TripDurationAndPrice>
<TripDuration>
{item?.stay_days} Days / {item?.stay_nights} nights
</TripDuration>
<PricePerPerson> $ {item?.price}/Person </PricePerPerson>
</TripDurationAndPrice>
</CountryImage>
<TripCountryAndPrice>
<CountryStarsPriceWrapper>
<TripCountryAndStars>
<TripCountry> {item?.title} </TripCountry>
<img src={Images.stars} />
</TripCountryAndStars>
<TripPrice>$ {item?.price} </TripPrice>
</CountryStarsPriceWrapper>
<DescriptionContainer
isMedia
dangerouslySetInnerHTML={{ __html: item.description }}
/>
<ReadMore onClick={() => navigateToTour(item?.id)} isMedia>
Read More <img src={Images.mainColorRightArrow} />
</ReadMore>
</TripCountryAndPrice>
</CardBlock>
<CardDescription>
<TripCountryAndStars>
<TripCountry> Venice Italy </TripCountry>
<img src={Images.stars} />
</TripCountryAndStars>
<DescriptionContainer
dangerouslySetInnerHTML={{ __html: item.description }}
/>
<ReadMore onClick={() => navigateToTour(item?.id)}>
Read More <img src={Images.mainColorRightArrow} />
</ReadMore>
</CardDescription>
</CardAndDescriptionBlock>
</SwiperSlide>
))}
</Swiper>
);
};
I have some Cards made with Boostrap, they look like this.
function TimeLine(props) {
return props.data.map(
({ screenName, name, imageProfile, description, timeAgo }) => (
<TwitterCard
screenName={screenName}
name={name}
imageProfile={imageProfile}
description={description}
timeAgo={timeAgo}
/>
)
);
}
Nevertheless if I add the component Link from react router dom, I got this.
function TimeLine(props) {
return props.data.map(
({ screenName, name, imageProfile, description, timeAgo }) => (
<Link to={`/username${screenName}`}>
<TwitterCard
screenName={screenName}
name={name}
imageProfile={imageProfile}
description={description}
timeAgo={timeAgo}
/>
</Link>
)
);
}
How could I keep the align and avoid these underlined text? Is there some alternative to Link? Or a correct approach to do this? Notice that I'm interested in make the Card clickeable so I can use link there
Apply CSS/style to make them not block-level elements.
Example:
function TimeLine(props) {
return props.data.map(
({ screenName, name, imageProfile, description, timeAgo }) => (
<Link
key={`/username${screenName}`}
to={`/username${screenName}`}
style={{ display: "inline" }}
>
<TwitterCard
screenName={screenName}
name={name}
imageProfile={imageProfile}
description={description}
timeAgo={timeAgo}
/>
</Link>
)
);
}
Since the TwitterCard component is the component enforcing the flex/grid layout though the link should be moved into the TwitterCard component inside the Col component.
Example:
const TwitterCard = ({
screenName,
name,
imageProfile,
description,
timeAgo
}) => {
return (
<>
<style type="text/css">
{`
.bg-customBlack {
background-color: #26262C;
color: white;
},
`}
</style>
<Col md={4} className="p-2">
<Link to={`/username${screenName}`}> // <-- link here inside column component
<Card bg="customBlack" className="text-center">
<Card.Header>
#{screenName} - {name}
</Card.Header>
<Card.Body>
<Card.Title>
<Image width={65} height={65} roundedCircle src={imageProfile} />
</Card.Title>
<Card.Text>{description}</Card.Text>
</Card.Body>
<Card.Footer className="text-muted">{timeAgo}</Card.Footer>
</Card>
</Link>
</Col>
</>
);
};
function TimeLine(props) {
return props.data.map(
({ screenName, name, imageProfile, description, timeAgo }) => (
<TwitterCard
key={screenName}
screenName={screenName}
name={name}
imageProfile={imageProfile}
description={description}
timeAgo={timeAgo}
/>
)
);
}
I have following react code.
My code
What I would like is to when I hover first image than other image should hide (or become transparent, so that the positioning does not collapse).
Аnd so it would be for other pictures, for example if you make a hover on a third picture, then the first, second and fourth pictures should become hide or transparent.
I look in other topics like:
How to affect other elements when one element is hovered and Hide element on hover of another element but I can't fix my code.
Maybe it will be more easy to fix using some reactJS code?
Please help me.
I would do it like this:
Track the index of hovered item, and changeing the style opacity depending on that hovered index.
// SolutionBox.jsx
import React, { useState } from "react";
import SolutionItem from "./SolutionItem";
import Ecommerce from "../img/a.png";
import Middleware from "../img/b.png";
import SalesMarketing from "../img/c.png";
import Analytics from "../img/d.png";
import _ from "lodash";
function SolutionsSectionBox({ onBGChanged }) {
const [focused, setFocused] = useState(0);
let callBGChanged = menuName => {
if (_.isFunction(onBGChanged)) {
onBGChanged(menuName);
}
};
return (
<div className="solutions-section-box-box">
<SolutionItem
solutionIMG={Ecommerce}
onHover={state => {
setFocused(1);
callBGChanged(state === true ? "Ecommerce" : "default");
}}
focused={focused}
index={1}
onLeave={() => setFocused(0)}
/>
<SolutionItem
solutionIMG={SalesMarketing}
onHover={state => {
setFocused(2);
callBGChanged(state === true ? "SalesMarketing" : "default");
}}
focused={focused}
index={2}
onLeave={() => setFocused(0)}
/>
<SolutionItem
solutionIMG={Analytics}
onHover={state => {
setFocused(3);
callBGChanged(state === true ? "Analytics" : "default");
}}
focused={focused}
index={3}
onLeave={() => setFocused(0)}
/>
<SolutionItem
solutionIMG={Middleware}
onHover={state => {
setFocused(4);
callBGChanged(state === true ? "Middleware" : "default");
}}
focused={focused}
index={4}
onLeave={() => setFocused(0)}
/>
</div>
);
}
export default SolutionsSectionBox;
Solution Item:
// Solution Item:
import React from "react";
import _ from "lodash";
function SolutionsSectionBoxItem({
onLeave,
solutionIMG,
onHover,
index = 0,
focused = 0
}) {
let callOnHover = state => {
if (_.isFunction(onHover)) {
onHover(state);
}
};
return (
<div className="solutions-section-item-box">
<img
style={{
opacity: focused && focused !== index ? 0.5 : 1
}}
src={solutionIMG}
alt=""
onMouseEnter={() => {
callOnHover(true);
}}
onMouseLeave={() => {
callOnHover(false);
onLeave();
}}
className="solutions-section-item-img"
/>
</div>
);
}
export default SolutionsSectionBoxItem;
You can use your existing bgImg state to infer which is visible.
If you pass it as a prop to SolutionBox like
<SolutionBox bgImage={bgImage} onBGChanged={onBGChanged} />
and then for each SolutionItem
<SolutionItem
solutionIMG={Ecommerce}
visible={bgImage === Ecommerce}
onHover={state => {
callBGChanged(state === true ? "Ecommerce" : "default");
}}
/>
and use it to style in SolutionItem
<div className="solutions-section-item-box" style={{ opacity: visible ? 1 : 0.5}}>
I'm using a material UI library in a React project using react typescript. I want this button to have a picture as a background. However, the button does not accept src or imageURL and returns a typescript error and the css style background doesn't show the picture either. this is my code:
const noticon = require ('./../../images/nicon.png')
const Avatarpic = require ('./../../images/Avatar.png')
const ExampleButton = ({
// useOpenState hook handlers
handleToggle, handleClose, handleOpen, setOpenState, isOpen
}: DropdownButtonProps) => (
<Button onClick={handleToggle} style={{backgroundImage: '{noticon}'}} square>
</Button>
)
function Navbar () {
return (
<>
<TopBar style={{ backgroundColor: '#e6edec' }}>
<TopBarSection>
<TopBarTitle>
<Avatar imgUrl={Avatarpic} name='حسین ساداتی پور' style={{ fontFamily: 'IranSans', fontSize: '20px' }} />
</TopBarTitle>
<Dropdown ButtonComponent={ExampleButton}>
<DropdownItem>Item to click</DropdownItem>
</Dropdown>
</TopBarSection>
{// <TopBarSection>
// burger menu Icon
// </TopBarSection>
}
</TopBar>
<section
style={{
padding: 50,
textAlign: 'center'
}}
>
Some content
</section>
</>
)
}
export default Navbar
you need to do this instead:
<Button onClick={handleToggle} style={{backgroundImage: `url(${noticon})`}} square>
I've made a custom User Confirmation Dialog from Material UI Dialog component like here
I faced a problem to overwrite the Dialog's font. I can overwrite color or background color, but fonts in Dialog's header or buttons are inherited from Material-UI. I successfully overwrote Material-UI fonts in other components, but not in this part with callback:
const UserConfirmation = (
message: string,
callback: (shouldNavigate: boolean) => void
) => {
const container = document.createElement('div')
container.setAttribute('custom-confirmation-navigation', '')
document.body.appendChild(container)
const closeModal = (shouldNavigate: boolean) => {
ReactDOM.unmountComponentAtNode(container)
callback(shouldNavigate)
}
ReactDOM.render(
<>
<Dialog
fullWidth={true}
maxWidth="sm"
open={true}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitleWrapper
style={{fontFamily: `BuenosAires !important`, color: `orange`}}
>
Discard draft?
</DialogTitleWrapper>
<DialogContent>
<p> {message} </p>
</DialogContent>
<DialogActionsWrapper>
<Button
onClick={() => closeModal(true)}
fullWidth={true}
variant="outlined"
label="Discard"
/>
<div style={{ width: '80%' }} />
<Button
onClick={() => closeModal(false)}
fullWidth={true}
variant="contained"
label="Cancel"
/>
</DialogActionsWrapper>
</Dialog>
</>,
container
)
}
export default UserConfirmation
Thank Alex
That works brilliant for me:
<DialogTitle disableTypography="true">
Also, buttons' labels were fixed by that:
label={<h5 style={{ textTransform: 'none' }}>Cancel</h5>}
You can use classes object to Override or extend the styles applied to the component.
here
create custom styles like below
const useStyles = makeStyles({
customDialogTitle: {
fontFamily:'Impact'//sans-serif
}
});
and assign to classes
<DialogTitle disableTypography="true"
classes={{
root: classes.customDialogTitle
}}
>
.....
</DialogTitle>
sample sandbox