@daimo/pay
Version:
Seamless crypto payments. Onboard users from any chain, any coin into your app with one click.
130 lines (127 loc) • 6.8 kB
JavaScript
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
import { useState, useRef, useEffect } from 'react';
import { Slider, ImageContainer, ImageContainerInner, Slides, Slide, MobileImageContainer, Dots, Dot } from './styles.js';
import { MotionConfig, AnimatePresence } from 'framer-motion';
import useLocales from '../../../hooks/useLocales.js';
import { usePayContext } from '../../../hooks/usePayContext.js';
import Button from '../../Common/Button/index.js';
import FitText from '../../Common/FitText/index.js';
import { OrDivider } from '../../Common/Modal/index.js';
import { ModalH1, ModalBody, PageContent, ModalContent } from '../../Common/Modal/styles.js';
import { SlideOne, SlideTwo, SlideThree } from './graphics.js';
const About = () => {
const locales = useLocales({
//CONNECTORNAME: connector.name,
});
const context = usePayContext();
const ctaUrl = context.options?.ethereumOnboardingUrl ?? locales.aboutScreen_ctaUrl;
const [ready, setReady] = useState(true);
const [slider, setSlider] = useState(0);
const interacted = useRef(false);
const scrollPos = useRef(0);
const animationEase = [0.16, 1, 0.3, 1];
const animationDuration = 600;
let interval;
useEffect(() => {
return () => clearInterval(interval);
}, []); // eslint-disable-line react-hooks/exhaustive-deps
const isSwipe = () => {
if (sliderRef.current) {
const { overflow } = getComputedStyle(sliderRef.current);
return overflow !== "visible";
}
return false;
};
const gotoSlide = (index) => {
setReady(false);
if (isSwipe()) {
scrollToSlide(index);
}
else {
setSlider(index);
}
};
const scrollToSlide = (index) => {
if (sliderRef.current) {
const { offsetWidth: width } = sliderRef.current;
sliderRef.current.scrollLeft = width * index;
setTimeout(() => setSlider(index), 100);
}
};
// This event should not fire on mobile
const onScroll = () => {
if (!sliderRef.current)
return;
const { offsetWidth: width, scrollLeft: x } = sliderRef.current;
const prevScroll = scrollPos.current;
scrollPos.current = x;
// Limit when the slider should be set after swipe
const threshold = 4;
if (prevScroll - x > -threshold && prevScroll - x < threshold) {
const currentSlide = Math.round(x / width);
setSlider(currentSlide);
}
};
const onTouchMove = () => {
didInteract();
};
const onTouchEnd = () => {
const { offsetWidth: width, scrollLeft: x } = sliderRef.current;
const currentSlide = Math.round(x / width);
setSlider(currentSlide);
};
const didInteract = () => {
interacted.current = true;
clearTimeout(interval);
};
const sliderRef = useRef(null);
useEffect(() => {
const slider = sliderRef.current;
if (slider == null)
return;
slider.addEventListener("scroll", onScroll);
slider.addEventListener("touchmove", onTouchMove);
slider.addEventListener("touchend", onTouchEnd);
return () => {
slider.removeEventListener("scroll", onScroll);
slider.removeEventListener("touchmove", onTouchMove);
slider.removeEventListener("touchend", onTouchEnd);
};
}, [sliderRef.current]); // eslint-disable-line react-hooks/exhaustive-deps
const graphics = [
jsx(SlideOne, { layoutId: "graphicCircle", duration: animationDuration, ease: animationEase }, "slideOne"),
jsx(SlideTwo, { layoutId: "graphicCircle", duration: animationDuration, ease: animationEase }, "slideTwo"),
jsx(SlideThree, { layoutId: "graphicCircle", duration: animationDuration, ease: animationEase }, "slideThree"),
];
const mobileGraphics = [
jsx(SlideOne, { duration: animationDuration, ease: animationEase }, "slideOne"),
jsx(SlideTwo, { duration: animationDuration, ease: animationEase }, "slideTwo"),
jsx(SlideThree, { duration: animationDuration, ease: animationEase }, "slideThree"),
];
// Adjust height of ModalBody to fit content based on language
const slideHeight = (() => {
switch (context.options?.language) {
case "en-US":
case "zh-CN":
return 64;
default:
return 84;
}
})();
const slides = [
jsxs(Fragment, { children: [jsx(ModalH1, { style: { height: 24 }, "$small": true, children: jsx(FitText, { children: locales.aboutScreen_a_h1 }) }), jsx(ModalBody, { style: { height: slideHeight }, children: jsx(FitText, { children: locales.aboutScreen_a_p }) })] }),
jsxs(Fragment, { children: [jsx(ModalH1, { style: { height: 24 }, "$small": true, children: jsx(FitText, { children: locales.aboutScreen_b_h1 }) }), jsx(ModalBody, { style: { height: slideHeight }, children: jsx(FitText, { children: locales.aboutScreen_b_p }) })] }),
jsxs(Fragment, { children: [jsx(ModalH1, { style: { height: 24 }, "$small": true, children: jsx(FitText, { children: locales.aboutScreen_c_h1 }) }), jsx(ModalBody, { style: { height: slideHeight }, children: jsx(FitText, { children: locales.aboutScreen_c_p }) })] }),
];
return (jsxs(PageContent, { children: [jsxs(Slider, { children: [jsx(ImageContainer, { children: jsx(MotionConfig, { transition: {
duration: animationDuration / 1000,
ease: animationEase,
}, children: jsx(AnimatePresence, { initial: false, onExitComplete: () => setReady(true), children: graphics.map((g, i) => slider === i && (jsx(ImageContainerInner, { style: { position: "absolute" }, children: g }, i))) }) }) }), jsx(Slides, { ref: sliderRef, children: jsx(AnimatePresence, { children: slides.map((s, i) => (jsxs(Slide, { "$active": slider === i, children: [jsx(MobileImageContainer, { children: jsx(MotionConfig, { transition: {
duration: 0,
}, children: jsx(ImageContainerInner, { children: mobileGraphics[i] }) }) }), jsx(ModalContent, { style: { gap: 8, paddingBottom: 0 }, children: s })] }, i))) }) })] }), jsx(OrDivider, { children: jsx(Dots, { children: slides.map((s, i) => (jsx(Dot, { "$active": slider === i, onClick: () => {
didInteract();
gotoSlide(i);
} }, i))) }) }), jsx(Button, { href: ctaUrl, arrow: true, children: locales.aboutScreen_ctaText })] }));
};
export { About as default };
//# sourceMappingURL=index.js.map