react-intersection-observer#useInView JavaScript Examples
The following examples show how to use
react-intersection-observer#useInView.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: 10-react-apps-series-b.js From make-react-apps-site with MIT License | 6 votes |
export default function ReactApps() {
const [topRef, topInView] = useInView()
const showFloatingButton = !topInView
return (
<>
<SEO title="Make 10 React Apps - Practical React Learning" />
<FloatingButton
isShowing={showFloatingButton}
url="/10-react-apps-series-b#pricing"
/>
<div ref={topRef}>
<AppsHero whichCourse="b" />
</div>
<WhatWellBuild whichCourse="b" />
<Pricing whichCourse="b" />
<LessonList whichCourse="b" />
<WhoAmI />
<FAQ />
{/* <Bundle /> */}
<Footer />
</>
)
}
Example #2
Source File: HomeContent.js From ar-episode2 with MIT License | 6 votes |
HomeContent = () => {
const animation = useAnimation()
const [contentRef, inView] = useInView({
triggerOnce: true,
rootMargin: "-300px",
})
useEffect(() => {
if (inView) {
animation.start("visible")
}
}, [animation, inView])
return (
<HomeContentSection
ref={contentRef}
animate={animation}
initial="hidden"
variants={{
visible: {
opacity: 1,
y: 0,
transition: { duration: 0.8, ease: [0.6, 0.05, -0.01, 0.9] },
},
hidden: { opacity: 0, y: 72 },
}}
>
<Container>
<Content>
Great stories don’t just happen— <br /> they need to be uncovered. And
we dig deep to discover the great stories that lie just below the
surface. Dirt under our fingernails and all.
</Content>
</Container>
</HomeContentSection>
)
}
Example #3
Source File: Span.js From mui-storyblok with MIT License | 6 votes |
Span = ({
align,
color,
height,
width,
rootClass,
content,
variant,
key,
storyblokClass,
dataBlokC,
dataBlokUid,
transitionClass,
}) => {
const { ref, inView } = useInView({ threshold: 0, triggerOnce: true });
const defaultStyles = {
height,
width,
};
const styles = Storyblok.arrayToMuiStyles(rootClass, defaultStyles);
return (
<MuiTypography
component="span"
key={key}
className={`${styles.root} ${storyblokClass} ${inView && transitionClass}`}
variant={variant}
align={align}
color={color}
data-blok-c={dataBlokC}
data-blok-uid={dataBlokUid}
inView={inView}
ref={ref}
style={{ opacity: inView ? 1 : 0 }}
>
{` ${content} `}
</MuiTypography>
);
}
Example #4
Source File: DecentralisedWebsites.js From ensdomains-v2 with MIT License | 6 votes |
export default function DecentralisedWebsites(props) {
const { t } = useTranslation()
const [ref, inView] = useInView({
/* Optional options */
threshold: 0,
rootMargin: "-200px",
})
return (
<Container id="home-decentralised-websites">
<AnchorContainer href={"#home-decentralised-websites"}>
<H2>
{t("home.decentralisedWebsites.title")}
<Anchor />
</H2>
</AnchorContainer>
<P>{t("home.decentralisedWebsites.text")}</P>
<ImageAnimation ref={ref}>
<ImageTransition>
<motion.img src={website2} style={{ opacity: inView ? 0 : 1 }} />
<motion.img src={blur1} style={{ opacity: inView ? 1 : 0 }} />
</ImageTransition>
<ImageTransition>
<img src={website1} alt={t("website")} />
</ImageTransition>
<ImageTransition>
<motion.img src={website3} animate={{ opacity: inView ? 0 : 1 }} />
<motion.img src={blur2} animate={{ opacity: inView ? 1 : 0 }} />
</ImageTransition>
</ImageAnimation>
<Button href="https://medium.com/the-ethereum-name-service/cloudflare-and-fleek-make-ens-ipfs-site-deployment-as-easy-as-ever-262c990a7514">
{t("c.learnMore")}
</Button>
</Container>
)
}
Example #5
Source File: StickyMobileSection.jsx From covince with MIT License | 6 votes |
StickyMobileSection = props => {
const options = useMemo(() => ({
threshold: [1]
}), [])
const { ref, inView } = useInView(options)
return (
<>
<div
className={classNames(
props.className,
'sticky bottom-0 bg-white dark:bg-gray-700 rounded-t-lg transition-colors',
'border-solid border-0 border-t border-transparent',
{ 'shadow-2xl dark:bg-gray-600 border-gray-200 dark:border-gray-400 z-30': !inView }
)}
>
{props.children}
</div>
{/* "sentinel" element - https://developers.google.com/web/updates/2017/09/sticky-headers */}
<div className='h-0' ref={ref} />
</>
)
}
Example #6
Source File: index.js From make-react-apps-site with MIT License | 6 votes |
export default function ReactApps() {
const [topRef, topInView] = useInView()
const showFloatingButton = !topInView
return (
<>
<SEO title="Make 10 React Apps - Practical React Learning" />
<FloatingButton
isShowing={showFloatingButton}
url="/#pricing"
/>
<div ref={topRef}>
<AppsHero />
</div>
<WhatWellBuild />
<Pricing />
<LessonList />
<WhoAmI />
<FAQ />
{/* <Bundle /> */}
<Footer />
</>
)
}
Example #7
Source File: StickyActionButton.jsx From covince with MIT License | 6 votes |
StickyActionButton = props => {
const options = useMemo(() => ({
threshold: [1]
}), [])
const { ref, inView } = useInView(options)
return (
<>
<PillButton
className={classNames('sticky z-30 bottom-6 mx-auto mt-6 transition-shadow', { 'shadow-xl': !inView })}
onClick={props.onClick}
>
{props.children}
</PillButton>
{/* "sentinel" element - https://developers.google.com/web/updates/2017/09/sticky-headers */}
<div className='h-6' ref={ref} />
</>
)
}
Example #8
Source File: homeAbout.js From ar-episode2 with MIT License | 5 votes |
HomeAbout = ({ onCursor }) => {
//Default state, using number for our id. Which ever the number/id is in the state. That will be opened.
const [expanded, setExpanded] = useState(0)
const animation = useAnimation()
const [aboutRef, inView] = useInView({
triggerOnce: true,
// Giving our scrollwheel additional 300px before executing animation
rootMargin: "-300px",
})
useEffect(() => {
if (inView) {
animation.start("visible")
}
}, [animation, inView])
return (
<HomeAboutSection
ref={aboutRef}
animate={animation}
initial="hidden"
variants={{
visible: {
opacity: 1,
y: 0,
transition: { duration: 0.8, ease: [0.6, 0.05, -0.01, 0.9] },
},
hidden: { opacity: 0, y: 72 },
}}
>
<Container>
<Flex alignTop>
<About>
<h2>
Furrow is an integrated, full-service creative studio offering
video production, creative development, and post-production
services.
</h2>
<p>
Everybody’s got a story. And we don’t stop until we’ve uncovered
what makes yours worth telling. Whether it’s working directly with
you, an agency partner, or putting the finishing touches on
something special, we’re ready to dig in and get our hands
dirty—are you?
</p>
</About>
<Services>
<h3>Services</h3>
{accordionIds.map((details, index) => (
<Accordion
key={index}
details={details}
expanded={expanded}
setExpanded={setExpanded}
onCursor={onCursor}
/>
))}
</Services>
</Flex>
</Container>
</HomeAboutSection>
)
}
Example #9
Source File: DetachedTextBlockEditor.jsx From volto-slate with MIT License | 5 votes |
DetachedTextBlockEditor = (props) => {
const {
data,
index,
properties,
onSelectBlock,
onChangeBlock,
block,
selected,
formTitle,
formDescription,
} = props;
const { value } = data;
const intl = useIntl();
const placeholder =
data.placeholder || formTitle || intl.formatMessage(messages.text);
let instructions = data?.instructions?.data || data?.instructions;
if (!instructions || instructions === '<p><br/></p>') {
instructions = formDescription;
}
const { ref, inView } = useInView({
threshold: 0,
rootMargin: '0px 0px 200px 0px',
});
return (
<div className="text-slate-editor-inner detached-slate-editor" ref={ref}>
<SlateEditor
index={index}
readOnly={!inView}
properties={properties}
renderExtensions={[]}
value={value}
block={block /* is this needed? */}
debug={DEBUG}
onFocus={() => {
if (!selected) {
onSelectBlock(block);
}
}}
onChange={(value, selection, editor) => {
onChangeBlock(block, {
...data,
value,
plaintext: serializeNodesToText(value || []),
// TODO: also add html serialized value
});
}}
selected={selected}
placeholder={placeholder}
onKeyDown={handleKeyDetached}
/>
</div>
);
}
Example #10
Source File: Hero.js From halo-lab with MIT License | 5 votes |
Hero = ({ animation }) => {
// eslint-disable-next-line no-unused-vars
const { quotes, ...infoAssets } = useHomeHeroAssets();
const { ref, inView } = useInView({
threshold: 0,
});
return (
<section ref={ref} className={styles.container}>
<div className={styles.wrapper}>
<div className={styles.title}>
<h1 className={styles.titleText}>
Design-driven development of your web product for years
</h1>
<Title className={styles.titleSvg} />
</div>
<animated.div
style={{
transform: inView ? animation.xy.interpolate(trans1) : 'none',
}}
className={`${styles.circleWrapper} ${styles.circleSm1Pos}`}
>
<div className={`${styles.circle} ${styles.circleSm1}`} />
</animated.div>
<animated.div
style={{
transform: inView ? animation.xy.interpolate(trans2) : 'none',
}}
className={`${styles.circleWrapper} ${styles.circleSm2Pos}`}
>
<div className={`${styles.circle} ${styles.circleSm2}`} />
</animated.div>
<animated.div
style={{
transform: inView ? animation.xy.interpolate(trans3) : 'none',
}}
className={`${styles.circleWrapper} ${styles.circleMdPos}`}
>
<div className={`${styles.circle} ${styles.circleMd}`} />
</animated.div>
</div>
<Info {...infoAssets} />
</section>
);
}
Example #11
Source File: IndexHeroFeaturedIn.jsx From pooltogether-landing-site with MIT License | 5 votes |
IndexHeroFeaturedIn = () => {
const controls = useAnimation()
const [ref, inView] = useInView()
useEffect(() => {
if (inView) {
controls.start('visible')
}
}, [controls, inView])
const containerVariants = {
visible: {
transition: {
staggerChildren: 0.12
}
},
hidden: {}
}
return (
<div id='featured-in' className='text-center pt-10'>
<div className='pool-container mx-auto'>
<h5 className='my-0 sm:mt-4 leading-tight'>Featured in:</h5>
<motion.div
className={classnames(
'flex flex-col xs:flex-row xs:flex-wrap justify-start items-start',
'mt-2 mb-4 px-4 xs:px-8 rounded-xl -mx-4 sm:-mx-12 lg:-mx-16'
)}
ref={ref}
animate={controls}
initial='hidden'
variants={containerVariants}
>
<GridItemSupportedBy
altBg
title={'Binance Academy'}
img={BinanceAcademySvg}
url='https://academy.binance.com/en/articles/how-pool-together-turns-saving-money-into-a-game'
/>
<GridItemSupportedBy
altBg
title={'Zapper'}
img={ZapperFiSvg}
url='https://learn.zapper.fi/articles/how-to-tranfer-eth-from-coinbase-to-defi'
/>
<GridItemSupportedBy
altBg
title={'Ethereum.org'}
img={EthereumPng}
url='https://ethereum.org/en/dapps/'
/>
<GridItemSupportedBy
altBg
title={'Bankless'}
img={BanklessPng}
url='https://shows.banklesshq.com/p/early-access-meet-the-nation-pooltogether'
/>
<GridItemSupportedBy
altBg
title={'CoinDesk'}
img={CoinDeskPng}
url='https://www.coindesk.com/tag/pooltogether'
/>
</motion.div>
</div>
</div>
)
}
Example #12
Source File: GridItem.js From mui-storyblok with MIT License | 4 votes |
GridItem = ({
components,
alignContent,
alignItems,
rootClass,
direction,
justify,
lg,
md,
sm,
wrap,
spacing,
xs,
xl,
content,
dataBlokC,
dataBlokUid,
storyblokClass,
transition,
only,
backgroundImageUrl,
}) => {
let heroClass;
const { ref, inView } = useInView({ threshold: 0.2, triggerOnce: true });
const gridClass = window?.Storyblok?.inEditor ? {
borderStyle: 'solid',
borderColor: '#3889FF',
borderWidth: '.1em',
} : {};
if (backgroundImageUrl) {
heroClass = {
...{
backgroundImage: `url(${backgroundImageUrl})`,
backgroundPosition: 'center',
backgroundRepeat: 'no-repeat',
backgroundSize: 'cover',
position: 'relative',
padding: 0,
margin: 0,
},
};
}
const styles = Storyblok.arrayToMuiStyles(rootClass, { ...heroClass });
return (
<Hidden only={only}>
<Grid
item
container
alignContent={alignContent}
alignItems={alignItems}
direction={direction}
justify={justify}
wrap={wrap}
spacing={Number(spacing)}
xs={sizeGrid(xs)}
sm={sizeGrid(sm)}
md={sizeGrid(md)}
lg={sizeGrid(lg)}
xl={sizeGrid(xl)}
data-blok-c={dataBlokC}
data-blok-uid={dataBlokUid}
className={`${styles.root} ${storyblokClass} ${inView && transition}`}
style={{ ...gridClass, opacity: inView ? 1 : 0 }}
inView={inView}
ref={ref}
>
{!content.length && <Box minHeight={200} width={{ xs: '100%' }} />}
{content.length > 0
&& content.map((component, key) => (
<Suspense fallback={<></>} key={key}>
{renderComponentsWithBridge({ ...components }, {
...component,
components,
key,
}, key)}
</Suspense>
))
}
</Grid>
</Hidden>
);
}
Example #13
Source File: HomeFeatured.js From ar-episode2 with MIT License | 4 votes |
HomeFeatured = ({ onCursor }) => {
const [hovered, setHovered] = useState(false)
const animation = useAnimation()
const [featured, inView] = useInView({
triggerOnce: true,
rootMargin: "-300px",
})
useEffect(() => {
if (inView) {
animation.start("visible")
}
}, [animation, inView])
return (
<HomeFeaturedSection
ref={featured}
animate={animation}
initial="hidden"
variants={{
visible: {
opacity: 1,
y: 0,
transition: { duration: 0.8, ease: [0.6, 0.05, -0.01, 0.9] },
},
hidden: { opacity: 0, y: 72 },
}}
>
<Container>
<Link to="/">
<FeaturedContent
onHoverStart={() => setHovered(!hovered)}
onHoverEnd={() => setHovered(!hovered)}
onMouseEnter={() => onCursor("hovered")}
onMouseLeave={onCursor}
>
<Flex spaceBetween>
<h3>Featured Project</h3>
<motion.div
animate={{ opacity: hovered ? 1 : 0 }}
transition={{ duration: 0.6, ease: [0.6, 0.05, -0.01, 0.9] }}
className="meta"
>
<h4>PEI Seafood</h4>
<h4>2019</h4>
</motion.div>
</Flex>
<h2 className="featured-title">
NOT <br /> HUMBLE
<span className="arrow">
<motion.svg
animate={{ x: hovered ? 48 : 0 }}
transition={{ duration: 0.6, ease: [0.6, 0.05, -0.01, 0.9] }}
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 101 57"
>
<path
d="M33 34H0V24h81.429L66 7.884 73.548 0l19.877 20.763.027-.029L101 28.618 73.829 57l-7.548-7.884L80.753 34H33z"
fill="#FFF"
fillRule="evenodd"
></path>
</motion.svg>
</span>
</h2>
</FeaturedContent>
<FeaturedVideo>
<video
loop
autoPlay
src={require("../../assets/video/featured-video.mp4")}
></video>
</FeaturedVideo>
</Link>
</Container>
<Container>
<FeaturedProjects>
<Flex flexEnd>
<button>
<span>All Projects</span>
</button>
</Flex>
</FeaturedProjects>
</Container>
</HomeFeaturedSection>
)
}
Example #14
Source File: footer.js From ar-episode2 with MIT License | 4 votes |
Footer = ({ setHamburgerPosition, onCursor }) => {
const instagramRef = useRef(null)
const instagramPosition = useElementPosition(instagramRef)
const facebookRef = useRef(null)
const facebookPosition = useElementPosition(facebookRef)
const vimeoRef = useRef(null)
const vimeoPosition = useElementPosition(vimeoRef)
const animation = useAnimation()
const [footerRef, inView] = useInView({
triggerOnce: true,
rootMargin: "-100px",
})
useEffect(() => {
if (inView) {
animation.start("visible")
}
}, [animation, inView])
const menuHover = x => {
onCursor("locked")
setHamburgerPosition({ x: x })
}
return (
<FooterNav
ref={footerRef}
animate={animation}
initial="hidden"
variants={{
visible: {
opacity: 1,
y: 0,
transition: { duration: 0.8, ease: [0.6, 0.05, -0.01, 0.9] },
},
hidden: { opacity: 0, y: 72 },
}}
>
<Container>
<Flex spaceBetween>
<FooterContent>
<p>902.315.1279</p>
<p>[email protected]</p>
</FooterContent>
<FooterContent wider>
<p>15 Camburhill Ct Unit C</p>
<p>Charlottetown, PE C1E 0E2</p>
</FooterContent>
<FooterSocial>
<a
onMouseEnter={() => menuHover(instagramPosition.x)}
onMouseLeave={onCursor}
ref={instagramRef}
href="/"
target="_blank"
>
<Instagram />
</a>
<a
onMouseEnter={() => menuHover(facebookPosition.x)}
onMouseLeave={onCursor}
ref={facebookRef}
href="/"
target="_blank"
>
<Facebook />
</a>
<a
onMouseEnter={() => menuHover(vimeoPosition.x)}
onMouseLeave={onCursor}
ref={vimeoRef}
href="/"
target="_blank"
>
<Vimeo />
</a>
</FooterSocial>
</Flex>
</Container>
</FooterNav>
)
}
Example #15
Source File: IndexSupportedBy.jsx From pooltogether-landing-site with MIT License | 4 votes |
IndexSupportedBy = () => {
const controls = useAnimation()
const [ref, inView] = useInView()
useEffect(() => {
if (inView) {
controls.start('visible')
}
}, [controls, inView])
const containerVariants = {
visible: {
transition: {
staggerChildren: 0.12
}
},
hidden: {}
}
return (
<div id='backed-by' className='bg-darkened text-center pt-12 pb-6 sm:pt-20 sm:pb-16'>
<div className='pool-container mx-auto'>
<h3 className='text-sm xs:text-lg sm:text-xl my-0 sm:mb-12 leading-tight'>
Protocol supported by
</h3>
<motion.div
className={classnames(
'flex flex-col xs:flex-row xs:flex-wrap justify-start items-start',
'mt-2 mb-4 px-4 xs:px-8 rounded-xl -mx-4 sm:-mx-12 lg:-mx-16'
)}
ref={ref}
animate={controls}
initial='hidden'
variants={containerVariants}
>
<GridItemSupportedBy
title={'ConsenSys'}
img={ConsensysSvg}
url='https://www.consensys.com'
/>
<GridItemSupportedBy
title={'IDEO'}
img={IdeoSvg}
url='https://www.ideo.com'
maxHeight={30}
/>
<GridItemSupportedBy
title={'DTC Capital'}
img={DTCCapitalSvg}
url='https://www.dtc.capital'
/>
<GridItemSupportedBy title={'ParaFi'} img={ParaFiSvg} url='https://www.parafi.capital/' />
<GridItemSupportedBy
title={'MetaCartel Ventures'}
img={MetaCartelSvg}
url='https://metacartel.org'
/>
<GridItemSupportedBy title={'The LAO'} img={TheLaoSvg} url='https://thelao.io' />
<GridItemSupportedBy
title={'Robot Ventures'}
img={RobotVenturesSvg}
url='https://twitter.com/robotventures'
/>
</motion.div>
{/* <div className='flex justify-center items-center sm:-mx-2'>
<a
href='https://makerdao.com'
title='View the Maker site'
target='_blank'
rel='noopener noreferrer'
>
<img
src={MakerDaoSvg}
className='mt-4'
/>
</a>
</div> */}
</div>
</div>
)
}
Example #16
Source File: IndexIntegrations.jsx From pooltogether-landing-site with MIT License | 4 votes |
IndexIntegrations = () => {
const controls = useAnimation()
const [ref, inView] = useInView()
useEffect(() => {
if (inView) {
controls.start('visible')
}
}, [controls, inView])
const containerVariants = {
visible: {
transition: {
staggerChildren: 0.2
}
},
hidden: {}
}
return (
<>
<div className='bg-secondary'>
<div className='pool-container mx-auto pt-12 pb-6 sm:pt-20 sm:pb-16'>
<div className='lg:px-20'>
<div className='flex items-center justify-between'>
<h1 className='leading-10 sm:leading-tight'>
<div className='text-flashy'>Protocol</div>{' '}
<div className='block -mt-2'>Integrations</div>
</h1>
</div>
<div className='flex flex-col py-4'>
<p className='text-sm xs:text-xl sm:text-xl lg:text-3xl lg:max-w-3xl'>
Try community-built interfaces and get inspired by what you can build on the
PoolTogether protocol.
</p>
<motion.div
className={classnames(
'flex flex-col sm:flex-row sm:flex-wrap',
'mt-8 mb-4 rounded-xl text-base lg:text-lg -mx-4 sm:-mx-4 lg:-mx-8'
)}
ref={ref}
animate={controls}
initial='hidden'
variants={containerVariants}
>
{/* <GridItem
title={'Argent'}
description={`Use the Argent app to join the pool.`}
img={ArgentSvg}
url='https://www.argent.xyz/'
/> */}
<GridItem
altBg
title={'Dharma'}
description={`Deposit into PoolTogether from your US bank.`}
img={DharmaSvg}
url='https://www.dharma.io/'
/>
<GridItem
altBg
title={'ZapperFi'}
description={`Join PoolTogether using this portal to DeFi.`}
img={ZapperFiSvg}
url='https://www.zapper.fi/#/dashboard'
/>
<GridItem
altBg
title={'Zerion'}
description={`Access DeFi & view your PoolTogether deposits.`}
img={ZerionSvg}
url='https://zerion.io/'
/>
<GridItem
altBg
title={'Twitter Bot'}
description={`Updates each time someone joins or wins!`}
img={BotSvg}
url='https://twitter.com/PoolTogetherBot'
attribution={`bot icon by Sophia Bai from the Noun Project`}
/>
{/*
<GridItem
title={'EBO'}
description={`EBO Finance is a wallet app for joining the pool.`}
img={EBOSvg}
url='https://ebo.io/'
/> */}
</motion.div>
</div>
</div>
<div className='bg-card rounded-xl mx-auto text-center p-4 xs:p-12 sm:pt-12 sm:pb-12 sm:mt-10'>
<div className='flex flex-col items-center'>
<h2 className='mt-4 mb-8 text-center'>Check out our developer documentation</h2>
<p className='text-sm xs:text-lg sm:text-xl max-w-lg text-center'>
Learn about the PoolTogether protocol and emerging use cases
</p>
<ButtonLink
secondary
textSize='2xl'
href='https://docs.pooltogether.com'
as='https://docs.pooltogether.com'
className='my-8 w-3/4 sm:w-1/2'
>
Go to docs
</ButtonLink>
</div>
</div>
</div>
</div>
</>
)
}
Example #17
Source File: BrandAssetsPage.jsx From pooltogether-landing-site with MIT License | 4 votes |
BrandAssetsPage = (props) => {
const controls = useAnimation()
const [ref, inView] = useInView()
useEffect(() => {
if (inView) {
controls.start('visible')
}
}, [controls, inView])
return <>
<div
className='pool-container mx-auto flex flex-col text-base h-full z-10 relative mb-20'
>
<h4
className='my-0'
>
Brand Assets
</h4>
<h2
className='mb-6'
>
PoolTogether Logos & Usage
</h2>
<p>
Here is a handy zipped-up package of all the latest logos, wordmarks, and symbols to assist you in building PoolTogether integrations or linking to us:
</p>
<BoxLinkWithIcon
isExternal
href='https://github.com/pooltogether/pooltogether--brand-assets/blob/141936c859553a2a42ac96ed807551b85a4d56d9/pooltogether-brand-assets-v1.2.0.zip?raw=true'
title='Download brand assets zip package'
icon={'download'}
>
pooltogether-brand-assets-v1.2.0.zip
</BoxLinkWithIcon>
<br/>
<h4
className='my-5'
>
By Style
</h4>
<p>
If you would rather download one or two specific styles you can find them on the <a href='https://github.com/pooltogether/pooltogether--brand-assets'>GitHub brand assets repository</a>.
</p>
<div className='my-5'>
<p className='text-base my-0 text-accent-1'>
Examples:
</p>
<motion.div
className={classnames(
'flex flex-col xs:flex-row xs:flex-wrap justify-start items-start',
'mt-2 mb-4 px-4 xs:px-8 rounded-xl -mx-4 lg:-mx-8',
)}
ref={ref}
animate={controls}
initial='hidden'
variants={{
visible: {
transition: {
staggerChildren: 0.2
}
},
hidden: {
},
}}
>
<GridItemBrandAssets
title={`Purple Wordmark`}
img={PoolTogetherPurpleWordmarkImg}
/>
<GridItemBrandAssets
title={`White Mark`}
img={PoolTogetherWhiteMarkImg}
/>
<GridItemBrandAssets
title={`Trophy`}
img={PoolTogetherTrophyImg}
/>
</motion.div>
</div>
<h4
className='my-5'
>Usage</h4>
<p>
We would like you to use any of the the assets 'as is'. If you need a modified version of any of the logos feel free to <a
href='mailto:[email protected]'
>reach out to us</a> and we'll be happy to help.
</p>
<p>
Please do not use any of the PoolTogether assets as the logo or in your logo for your app or brand. Thanks!
</p>
</div>
</>
}
Example #18
Source File: Grid.js From mui-storyblok with MIT License | 4 votes |
Grid = ({
alignContent,
alignItems,
rootClass,
direction,
justify,
wrap,
spacing,
content,
components,
style,
dataBlokC,
dataBlokUid,
storyblokClass,
height,
backgroundImageUrl,
transition,
only,
backgroundColor,
}) => {
const { ref, inView } = useInView({ threshold: 0, triggerOnce: true });
const gridClass = window?.Storyblok?.inEditor ? {
borderStyle: 'solid',
borderColor: '#FF2020',
borderWidth: '.1em',
} : {};
let gridBackgroundColor = {};
let heroClass = {
...style,
height,
};
if (backgroundImageUrl) {
heroClass = {
...heroClass,
...{
backgroundImage: `url(${backgroundImageUrl})`,
backgroundPosition: 'center',
backgroundRepeat: 'no-repeat',
backgroundSize: 'cover',
position: 'relative',
padding: 0,
margin: 0,
},
};
}
if (backgroundColor && !backgroundImageUrl) {
gridBackgroundColor = { backgroundColor: backgroundColor.color };
}
const styles = Storyblok.arrayToMuiStyles(rootClass, { ...heroClass, ...gridBackgroundColor });
return (
<Hidden only={only}>
<Box width={{ xs: '100%' }}>
<MuiGrid
container
alignContent={alignContent}
alignItems={alignItems}
direction={direction}
justify={justify}
wrap={wrap}
spacing={Number(spacing)}
data-blok-c={dataBlokC}
data-blok-uid={dataBlokUid}
className={`${styles.root} ${storyblokClass} ${inView && transition}`}
style={{ ...gridClass, opacity: inView ? 1 : 0 }}
inView={inView}
ref={ref}
>
{!content.length && <Box minHeight={200} width={{ xs: '100%' }} />}
{content.length > 0 && content.map((component, key) => (
<Suspense fallback={<Box width={{ xs: '100%' }} key={key} />}>
{renderComponentsWithBridge({ ...{ GridItem }, ...components }, {
...component,
components,
key,
}, key)}
</Suspense>
))}
</MuiGrid>
</Box>
</Hidden>
);
}
Example #19
Source File: index.jsx From react-animated-numbers with MIT License | 4 votes |
AnimatedNumber = ({
animateToNumber,
fontStyle,
configs,
includeComma,
}) => {
const { ref, inView } = useInView({ triggerOnce: true });
const keyCount = React.useRef(0);
const animteTonumberString = includeComma
? Math.abs(animateToNumber).toLocaleString()
: String(Math.abs(animateToNumber));
const animateToNumbersArr = Array.from(animteTonumberString, Number).map(
(x, idx) => (isNaN(x) ? animteTonumberString[idx] : x)
);
const [numberHeight, setNumberHeight] = React.useState(0);
const numberDivRef = React.useRef(null);
const setConfig = (configs, number, index) => {
if (typeof configs === "function") {
return configs(number, index);
}
return configs
? configs[getRandomIntInclusive(0, configs.length - 1)]
: undefined;
};
React.useEffect(() => {
const height = numberDivRef.current.getClientRects()?.[0]?.height;
if (height) {
setNumberHeight(height);
}
}, [animateToNumber, fontStyle]);
return (
<>
{numberHeight !== 0 && (
<div
ref={ref}
style={{ display: "flex", flexDirection: "row" }}
className="animated-container"
>
{inView && animateToNumber < 0 && <div style={fontStyle}>-</div>}
{inView &&
animateToNumbersArr.map((n, index) => {
if (typeof n === "string") {
return (
<div key={index} style={{ ...fontStyle }}>
{n}
</div>
);
}
return (
<div
key={index}
style={{
height: numberHeight,
overflow: "hidden",
}}
>
<Spring
key={`${keyCount.current++}`}
from={{
transform: "translateY(0px)",
}}
to={{
transform: `translateY(${
-1 * (numberHeight * animateToNumbersArr[index]) -
numberHeight * 20
})`,
}}
config={setConfig(configs, n, index)}
>
{(props) =>
NUMBERS.map((number, i) => (
<animated.div
key={i}
style={{ ...fontStyle,...props }}
>
{number}
</animated.div>
))
}
</Spring>
</div>
);
})}
</div>
)}
<div
ref={numberDivRef}
style={{ position: "absolute", top: -9999, ...fontStyle }}
>
{0}
</div>
</>
);
}
Example #20
Source File: GridView.js From gutenberg-forms with GNU General Public License v2.0 | 4 votes |
GridView = memo(function GridView() {
const isMounted = useIsMounted()
const templates = useTemplatesStore((state) => state.templates)
const appendTemplates = useTemplatesStore((state) => state.appendTemplates)
const [serverError, setServerError] = useState('')
const retryOnce = useRef(false)
const [nothingFound, setNothingFound] = useState(false)
const [loading, setLoading] = useState(false)
const [loadMoreRef, inView] = useInView()
const searchParamsRaw = useTemplatesStore((state) => state.searchParams)
const currentType = useGlobalStore((state) => state.currentType)
const resetTemplates = useTemplatesStore((state) => state.resetTemplates)
const open = useGlobalStore((state) => state.open)
const taxonomies = useTaxonomyStore((state) => state.taxonomies)
const updateType = useTemplatesStore((state) => state.updateType)
const updateTaxonomies = useTemplatesStore(
(state) => state.updateTaxonomies,
)
// Store the next page in case we have pagination
const nextPage = useRef(useTemplatesStore.getState().nextPage)
const searchParams = useRef(useTemplatesStore.getState().searchParams)
const taxonomyType =
searchParams.current.type === 'pattern' ? 'patternType' : 'layoutType'
const currentTax = searchParams.current.taxonomies[taxonomyType]
const defaultOrAlt = useTestGroup('default-or-alt-sitetype', ['A', 'B'])
// Subscribing to the store will keep these values updates synchronously
useEffect(() => {
return useTemplatesStore.subscribe(
(state) => state.nextPage,
(n) => (nextPage.current = n),
)
}, [])
useEffect(() => {
return useTemplatesStore.subscribe(
(state) => state.searchParams,
(s) => (searchParams.current = s),
)
}, [])
// Fetch the templates then add them to the current state
const fetchTemplates = useCallback(() => {
if (!defaultOrAlt) {
return
}
setServerError('')
setNothingFound(false)
const defaultError = __(
'Unknown error occured. Check browser console or contact support.',
'extendify',
)
const args = { offset: nextPage.current }
// AB test the default or defaultAlt site type
const defaultSiteType =
defaultOrAlt === 'A' ? { slug: 'default' } : { slug: 'defaultAlt' }
const siteType = searchParams.current.taxonomies?.siteType?.slug?.length
? searchParams.current.taxonomies.siteType
: defaultSiteType
// End AB test - otherwise use { slug: 'default' } when empty
const params = cloneDeep(searchParams.current)
params.taxonomies.siteType = siteType
TemplatesApi.get(params, args)
.then((response) => {
if (!isMounted.current) return
if (response?.error?.length) {
setServerError(response?.error)
return
}
if (response?.records?.length <= 0) {
setNothingFound(true)
return
}
if (
searchParamsRaw === searchParams.current &&
response?.records?.length
) {
useTemplatesStore.setState({
nextPage: response?.offset ?? '',
})
appendTemplates(response.records)
setLoading(false)
}
})
.catch((error) => {
if (!isMounted.current) return
console.error(error)
setServerError(defaultError)
})
}, [appendTemplates, isMounted, searchParamsRaw, defaultOrAlt])
useEffect(() => {
if (templates?.length === 0) {
setLoading(true)
return
}
}, [templates?.length, searchParamsRaw])
useEffect(() => {
// If there's a server error, retry the request
// This is temporary until we upgrade the bckend and add
// a tool like react query to handle this automatically
if (!retryOnce.current && serverError.length) {
retryOnce.current = true
fetchTemplates()
}
}, [serverError, fetchTemplates])
useEffect(() => {
// This will check the URL for a pattern type and set that and remove it
// TODO: possibly refactor this if we exapnd it to support layouts
if (!open || !taxonomies?.patternType?.length) return
const search = new URLSearchParams(window.location.search)
if (!search.has('ext-patternType')) return
const term = search.get('ext-patternType')
// Delete it right away
search.delete('ext-patternType')
window.history.replaceState(
null,
null,
window.location.pathname + '?' + search.toString(),
)
// Search the slug in patternTypes
const tax = taxonomies.patternType.find((t) => t.slug === term)
if (!tax) return
updateTaxonomies({ patternType: tax })
updateType('pattern')
}, [open, taxonomies, updateType, updateTaxonomies])
// This is the main driver for loading templates
// This loads the initial batch of templates. But if we don't yet have taxonomies.
// There's also an option to skip loading on first mount
useEffect(() => {
if (!Object.keys(searchParams.current?.taxonomies)?.length) {
return
}
if (useTemplatesStore.getState().skipNextFetch) {
// This is useful if the templates are fetched already and
// the library moves to/from another state that re-renders
// The point is to keep the logic close to the list. That may change someday
useTemplatesStore.setState({
skipNextFetch: false,
})
return
}
fetchTemplates()
return () => resetTemplates()
}, [fetchTemplates, searchParams, resetTemplates])
// Fetches when the load more is in view
useEffect(() => {
nextPage.current && inView && fetchTemplates()
}, [inView, fetchTemplates, templates])
if (serverError.length && retryOnce.current) {
return (
<div className="text-left">
<h2 className="text-left">{__('Server error', 'extendify')}</h2>
<code
className="mb-4 block max-w-xl p-4"
style={{ minHeight: '10rem' }}>
{serverError}
</code>
<Button
isTertiary
onClick={() => {
retryOnce.current = false
fetchTemplates()
}}>
{__('Press here to reload')}
</Button>
</div>
)
}
if (nothingFound) {
return (
<div className="-mt-2 flex h-full w-full items-center justify-center sm:mt-0">
<h2 className="text-sm font-normal text-extendify-gray">
{sprintf(
searchParams.current.type === 'template'
? __(
'We couldn\'t find any layouts in the "%s" category.',
'extendify',
)
: __(
'We couldn\'t find any patterns in the "%s" category.',
'extendify',
),
currentTax?.title ?? currentTax.slug,
)}
</h2>
</div>
)
}
return (
<>
{loading && (
<div className="-mt-2 flex h-full w-full items-center justify-center sm:mt-0">
<Spinner />
</div>
)}
<Grid type={currentType} templates={templates}>
{templates.map((template) => {
return (
<ImportTemplateBlock
maxHeight={
currentType === 'template' ? 520 : 'none'
}
key={template.id}
template={template}
/>
)
})}
</Grid>
{nextPage.current && (
<>
<div className="my-20">
<Spinner />
</div>
{/* This is a large div that, when in view, will trigger more patterns to load */}
<div
className="relative flex -translate-y-full transform flex-col items-end justify-end"
ref={loadMoreRef}
style={{
zIndex: -1,
marginBottom: '-100%',
height:
currentType === 'template' ? '150vh' : '75vh',
}}
/>
</>
)}
</>
)
})
Example #21
Source File: DefaultTextBlockEditor.jsx From volto-slate with MIT License | 4 votes |
DefaultTextBlockEditor = (props) => {
const {
block,
blocksConfig,
data,
detached = false,
index,
onChangeBlock,
onInsertBlock,
onMutateBlock,
onSelectBlock,
pathname,
properties,
selected,
uploadRequest,
uploadContent,
uploadedContent,
defaultSelection,
saveSlateBlockSelection,
allowedBlocks,
formTitle,
formDescription,
} = props;
const { slate } = config.settings;
const { textblockExtensions } = slate;
const { value } = data;
// const [addNewBlockOpened, setAddNewBlockOpened] = React.useState();
const [showDropzone, setShowDropzone] = React.useState(false);
const [uploading, setUploading] = React.useState(false);
const [newImageId, setNewImageId] = React.useState(null);
const prevReq = React.useRef(null);
const withBlockProperties = React.useCallback(
(editor) => {
editor.getBlockProps = () => props;
return editor;
},
[props],
);
const slateSettings = React.useMemo(
() => ({
...config.settings.slate,
persistentHelpers: [
...config.settings.slate.persistentHelpers,
PersistentSlashMenu,
],
}),
[],
);
const onDrop = React.useCallback(
(files) => {
// TODO: need to fix setUploading, treat uploading indicator
// inteligently, show progress report on uploading files
setUploading(true);
files.forEach((file) => {
const [mime] = file.type.split('/');
if (mime !== 'image') return;
readAsDataURL(file).then((data) => {
const fields = data.match(/^data:(.*);(.*),(.*)$/);
uploadContent(
getBaseUrl(pathname),
{
'@type': 'Image',
title: file.name,
image: {
data: fields[3],
encoding: fields[2],
'content-type': fields[1],
filename: file.name,
},
},
block,
);
});
});
setShowDropzone(false);
},
[pathname, uploadContent, block],
);
const { loaded, loading } = uploadRequest;
const imageId = uploadedContent['@id'];
const prevLoaded = prevReq.current;
React.useEffect(() => {
if (loaded && !loading && !prevLoaded && newImageId !== imageId) {
const url = flattenToAppURL(imageId);
setNewImageId(imageId);
createImageBlock(url, index, props);
}
prevReq.current = loaded;
}, [props, loaded, loading, prevLoaded, imageId, newImageId, index]);
const handleUpdate = React.useCallback(
(editor) => {
// defaultSelection is used for things such as "restoring" the selection
// when joining blocks or moving the selection to block start on block
// split
if (defaultSelection) {
const selection = parseDefaultSelection(editor, defaultSelection);
if (selection) {
setTimeout(() => {
Transforms.select(editor, selection);
saveSlateBlockSelection(block, null);
}, 120);
// TODO: use React sync render API
// without setTimeout, the join is not correct. Slate uses internally
// a 100ms throttle, so setting to a bigger value seems to help
}
}
},
[defaultSelection, block, saveSlateBlockSelection],
);
const onEditorChange = (value, editor) => {
ReactDOM.unstable_batchedUpdates(() => {
onChangeBlock(block, {
...data,
value,
plaintext: serializeNodesToText(value || []),
// TODO: also add html serialized value
});
deconstructToVoltoBlocks(editor);
});
};
// Get editing instructions from block settings or props
let instructions = data?.instructions?.data || data?.instructions;
if (!instructions || instructions === '<p><br/></p>') {
instructions = formDescription;
}
const intl = useIntl();
const placeholder =
data.placeholder || formTitle || intl.formatMessage(messages.text);
const schema = TextBlockSchema(data);
const disableNewBlocks = data?.disableNewBlocks || detached;
const { ref, inView } = useInView({
threshold: 0,
rootMargin: '0px 0px 200px 0px',
});
const handleFocus = React.useCallback(() => {
if (!selected) {
onSelectBlock(block);
}
}, [onSelectBlock, selected, block]);
return (
<div className="text-slate-editor-inner" ref={ref}>
<>
<Dropzone
disableClick
onDrop={onDrop}
className="dropzone"
onDragOver={() => setShowDropzone(true)}
onDragLeave={() => setShowDropzone(false)}
>
{({ getRootProps, getInputProps }) => {
return showDropzone ? (
<div className="drop-indicator">
{uploading ? (
<Dimmer active>
<Loader indeterminate>Uploading image</Loader>
</Dimmer>
) : (
<Message>
<center>
<img src={imageBlockSVG} alt="" />
</center>
</Message>
)}
</div>
) : (
<>
<SlateEditor
index={index}
readOnly={!inView}
properties={properties}
extensions={textblockExtensions}
renderExtensions={[withBlockProperties]}
value={value}
block={block /* is this needed? */}
defaultSelection={defaultSelection}
onUpdate={handleUpdate}
debug={DEBUG}
onFocus={handleFocus}
onChange={(value, editor) => onEditorChange(value, editor)}
onKeyDown={handleKey}
selected={selected}
placeholder={placeholder}
slateSettings={slateSettings}
/>
{DEBUG ? <div>{block}</div> : ''}
</>
);
}}
</Dropzone>
{selected && !data.plaintext?.trim() && !disableNewBlocks && (
<BlockChooserButton
data={data}
block={block}
onInsertBlock={(id, value) => {
onSelectBlock(onInsertBlock(id, value));
}}
onMutateBlock={onMutateBlock}
allowedBlocks={allowedBlocks}
blocksConfig={blocksConfig}
size="24px"
className="block-add-button"
properties={properties}
/>
)}
<SidebarPortal selected={selected}>
<div id="slate-plugin-sidebar"></div>
{instructions ? (
<Segment attached>
<div dangerouslySetInnerHTML={{ __html: instructions }} />
</Segment>
) : (
<>
<ShortcutListing />
<MarkdownIntroduction />
<BlockDataForm
schema={schema}
title={schema.title}
onChangeField={(id, value) => {
onChangeBlock(block, {
...data,
[id]: value,
});
}}
formData={data}
block={block}
/>
</>
)}
</SidebarPortal>
</>
</div>
);
}
Example #22
Source File: DistrictDashboard.js From dashboard with MIT License | 4 votes |
function DistrictDashboard() {
const todayDate = new Date();
const params = useParams();
const [isOpen, setIsOpen] = useState(false);
const [timeseries, setTimeseries] = useState(false);
const [filterDistrict, setFilterDistrict] = useState(ACTIVATED_DISTRICTS[0]);
const [filterFacilityTypes, setFilterFacilityTypes] =
useState(FACILITY_TYPES);
const [content, setContent] = useState(
CONTENT[params.content?.toUpperCase()] || CONTENT.CAPACITY
);
const [dates, datesOnChange] = useState([
getNDateBefore(todayDate, 14),
todayDate,
]);
const [date, dateOnChange] = useState(todayDate);
const [ref, inView] = useInView({
threshold: 0,
});
const getDistrict = (name) => {
const district = ACTIVATED_DISTRICTS.find(
(district) => district.name.toLowerCase() === name?.toLowerCase()
);
return district === undefined ? ACTIVATED_DISTRICTS[0] : district;
};
useEffect(() => {
setFilterDistrict(getDistrict(params.district));
}, [params.district]);
useEffect(() => {
setContent(CONTENT[params.content?.toUpperCase()] || CONTENT.CAPACITY);
}, [params.content]);
useEffect(() => {
window.history.replaceState(
null,
"Care Dashboard",
`/district/${filterDistrict.name.toLowerCase()}/${Object.entries(CONTENT)
.find((a) => a[1] === content)[0]
.toLowerCase()}`
);
}, [content, filterDistrict]);
const renderContent = () => {
switch (content) {
case CONTENT.CAPACITY:
return !timeseries ? (
<Capacity
filterDistrict={filterDistrict}
filterFacilityTypes={filterFacilityTypes}
date={date}
/>
) : (
<CapacityTimeseries
filterDistrict={filterDistrict}
filterFacilityTypes={filterFacilityTypes}
dates={dates}
/>
);
case CONTENT.PATIENT:
return !timeseries ? (
<Patient
filterDistrict={filterDistrict}
filterFacilityTypes={filterFacilityTypes}
date={date}
/>
) : (
<PatientTimeseries
filterDistrict={filterDistrict}
filterFacilityTypes={filterFacilityTypes}
dates={dates}
/>
);
case CONTENT.TESTS:
return !timeseries ? (
<Tests
filterDistrict={filterDistrict}
filterFacilityTypes={filterFacilityTypes}
date={date}
/>
) : (
<TestsTimeseries
filterDistrict={filterDistrict}
filterFacilityTypes={filterFacilityTypes}
dates={dates}
/>
);
case CONTENT.TRIAGE:
return !timeseries ? (
<Triage
filterDistrict={filterDistrict}
filterFacilityTypes={filterFacilityTypes}
date={date}
/>
) : (
<TriageTimeseries
filterDistrict={filterDistrict}
filterFacilityTypes={filterFacilityTypes}
dates={dates}
/>
);
case CONTENT.LSG:
return !timeseries ? (
<Lsg filterDistrict={filterDistrict} date={date} />
) : (
<div>Work in Progress</div>
);
case CONTENT.OXYGEN:
return !timeseries ? (
<OxygenMonitor
filterDistrict={filterDistrict}
filterFacilityTypes={filterFacilityTypes}
date={date}
/>
) : (
<div>Work in Progress</div>
);
case CONTENT.MAP:
return !timeseries ? (
<DistrictMap
filterDistrict={filterDistrict}
filterFacilityTypes={filterFacilityTypes}
date={date}
/>
) : (
<div>Work in Progress</div>
);
default:
return <div />;
}
};
function ConditionalFilter({ floating }) {
return (
<Filter
floating={floating}
timeseries={timeseries}
setTimeseries={setTimeseries}
date={date}
dateOnChange={dateOnChange}
dates={dates}
datesOnChange={datesOnChange}
maxDate={todayDate}
filterFacilityTypes={filterFacilityTypes}
setFilterFacilityTypes={setFilterFacilityTypes}
content={content}
/>
);
}
const transitions = useTransition(content, null, {
from: { opacity: 0 },
enter: { opacity: 1 },
leave: { opacity: 1 },
});
return (
<div className="overflow-hidden md:overflow-auto">
<PageTitle>District Dashboard</PageTitle>
<div className="flex flex-col items-center justify-between mb-2 px-4 py-2 bg-primary-500 rounded-lg shadow-md md:flex-row">
<p className="text-white font-semibold">{filterDistrict.name}</p>
<div className="md:flex md:space-x-2">
<div className="flex flex-wrap justify-center dark:text-gray-700 dark:bg-gray-900 bg-white rounded-lg space-x-1 space-y-1 md:space-x-0 md:space-y-0">
{Object.keys(CONTENT).map((k, i) => {
let t = "shadow-xs ";
if (i === 0) {
t += "md:rounded-r-none";
} else if (i === Object.keys(CONTENT).length - 1) {
t += "md:rounded-l-none";
} else {
t += "md:rounded-l-none md:rounded-r-none";
}
return (
<Button
layout="link"
onClick={() => setContent(CONTENT[k])}
className={t}
disabled={content === CONTENT[k]}
key={i}
>
<span className="capitalize">{k.toLowerCase()}</span>
</Button>
);
})}
</div>
<div className="relative mt-2 dark:bg-gray-900 bg-white rounded-lg md:mt-0">
<Button
layout="link"
onClick={() => setIsOpen(!isOpen)}
aria-label="Select district"
aria-haspopup="true"
disabled={false}
iconRight={ChevronDown}
className="w-full shadow-xs"
>
{filterDistrict.name}
</Button>
<Dropdown
isOpen={isOpen}
align="right"
onClose={() => setIsOpen(false)}
className="z-40"
>
{ACTIVATED_DISTRICTS.map((d, i) => (
<DropdownItem
key={i}
onClick={() => {
setFilterDistrict(d);
setIsOpen(false);
}}
>
<span>{d.name}</span>
</DropdownItem>
))}
</Dropdown>
</div>
</div>
</div>
<div ref={ref}>
<ConditionalFilter floating={false} />
</div>
{!inView && <ConditionalFilter floating />}
<Suspense fallback={<ThemedSuspense />}>
<SWRConfig
value={{
suspense: true,
loadingTimeout: 10_000,
refreshInterval: 300_000,
onError: (error, key) => {
// eslint-disable-next-line no-console
console.error(error, key);
},
}}
>
{transitions.map(({ key, props }) => (
<animated.div key={key} style={props}>
{renderContent()}
</animated.div>
))}
</SWRConfig>
</Suspense>
</div>
);
}