diff --git a/src/landing/AppAnimation.tsx b/src/landing/AppAnimation.tsx index ab00bf5d7..3c6580cb4 100644 --- a/src/landing/AppAnimation.tsx +++ b/src/landing/AppAnimation.tsx @@ -20,8 +20,8 @@ import { SiTypescript } from 'react-icons/si'; import { twMerge } from 'tailwind-merge'; import { motion } from 'framer-motion'; -export default function AppAnimation({ active }) { - const [step, setStep] = React.useState(0); +export default function AppAnimation({ active, only }) { + const [step, setStep] = React.useState(only ? 0 : -1); const [scriptStep, setScriptStep] = React.useState(0); const [buttonName, setButtonName] = React.useState('Press me'); const [clicked, setClicked] = React.useState(false); @@ -136,7 +136,7 @@ export default function AppAnimation({ active }) { } }; - useAnimateScroll(active, steps, appScrollCount, flowScrollCount + scriptScrollCount); + useAnimateScroll(active, steps, appScrollCount, only ? 0 : flowScrollCount + scriptScrollCount); return (
diff --git a/src/landing/FlowAnimation.tsx b/src/landing/FlowAnimation.tsx index c650c7715..2d301a6c9 100644 --- a/src/landing/FlowAnimation.tsx +++ b/src/landing/FlowAnimation.tsx @@ -48,7 +48,7 @@ const initialEdges = [ { id: '6-7', source: '6', target: '7' } ]; -export default function FlowAnimation({ active }) { +export default function FlowAnimation({ active, only }) { const [initialNodes, setInitialNodes] = React.useState< Array<{ id: string; @@ -110,7 +110,7 @@ export default function FlowAnimation({ active }) { const [windowIndex, setWindowIndex] = React.useState(0); const [bgColor, setBgColor] = React.useState('black'); - const [step, setStep] = React.useState(-1); + const [step, setStep] = React.useState(only ? 0 : -1); const nodeTypes = useMemo(() => ({ textUpdater: Node }), []); const [selectedFile, setSelectedFile] = React.useState('your_flow.yaml'); @@ -170,6 +170,7 @@ schema: i === 7 ? { ...node, data: { ...node.data, selected: true } } : node ) ); + setStep(0); }, rollback: () => { @@ -318,7 +319,7 @@ schema: } ]; - useAnimateScroll(active, steps, flowScrollCount, scriptScrollCount); + useAnimateScroll(active, steps, flowScrollCount, only ? 0 : scriptScrollCount); const currentText = `import Stripe from 'stripe'; diff --git a/src/landing/TutorialSection.tsx b/src/landing/TutorialSection.tsx index d8347aa24..1eda1c8b4 100644 --- a/src/landing/TutorialSection.tsx +++ b/src/landing/TutorialSection.tsx @@ -21,21 +21,26 @@ import { Lottie } from './LightFeatureCard'; import deployAtScale from '/illustrations/deploy_at_scale.json'; import { ArrowLongDownIcon } from '@heroicons/react/20/solid'; import { twMerge } from 'tailwind-merge'; +// @ts-ignore import BrowserOnly from '@docusaurus/BrowserOnly'; -export default function TutorialSection() { - const [step, setStep] = React.useState(0); + +export default function TutorialSection({ subIndex, children }) { + const [step, setStep] = React.useState(subIndex || 0); const containerRef = React.useRef(null); const [animationEnabled, setAnimationEnabled] = React.useState( // enabled on desktop, disabled on mobile typeof window !== 'undefined' ? window.innerWidth > 768 : false ); + const oneStep = subIndex !== undefined; + const maxHeight = oneStep ? 5000 : 15000; + const items = [ { key: 'scripts', content: (
- +
) }, @@ -43,7 +48,7 @@ export default function TutorialSection() { key: 'flows', content: (
- +
) }, @@ -51,7 +56,7 @@ export default function TutorialSection() { key: 'apps', content: (
- +
) } @@ -60,28 +65,42 @@ export default function TutorialSection() { const [px, setPx] = React.useState(0); useEffect(() => { - setPx((15000 - window.innerHeight) / 3); + setPx((maxHeight - window.innerHeight) / 3); }, []); function nextStep() { const top = containerRef.current.getBoundingClientRect().y * -1; + const steps = { scripts: { total: px, steps: [20, 40, 50, 60, 70, 80] }, flows: { total: px * 2, steps: [10, 20, 30, 40, 50, 60, 75, 80, 90] }, apps: { total: px * 3, steps: [10, 15, 30, 45, 60, 72, 90, 99] } }; - for (const section of Object.values(steps)) { - if (top < section.total) { - const res = smoothScrollToNextStep(top, section); + if (subIndex !== undefined) { + const stepKey = subIndex === 0 ? 'scripts' : subIndex === 1 ? 'flows' : 'apps'; + const section = steps[stepKey]; - if (res === 'next') { - window.scrollBy({ - top: section.total - top + 50, - behavior: 'smooth' - }); + if (!section) { + return; + } + + smoothScrollToNextStep(top, { + total: px, + steps: section.steps + }); + } else { + for (const section of Object.values(steps)) { + if (top < section.total) { + const res = smoothScrollToNextStep(top, section); + if (res === 'next') { + window.scrollBy({ + top: section.total - top + 50, + behavior: 'smooth' + }); + } + break; } - break; } } } @@ -135,35 +154,52 @@ export default function TutorialSection() { function prevStep() { const top = containerRef.current.getBoundingClientRect().y * -1; let foundSection = false; + const steps = { scripts: { total: px, steps: [20, 40, 50, 60, 70, 80] }, flows: { total: px * 2, steps: [10, 20, 30, 40, 50, 60, 75, 80, 90] }, apps: { total: px * 3, steps: [10, 15, 30, 45, 60, 72, 90, 99] } }; - for (const [sectionName, section] of Object.entries(steps)) { - if (top <= section.total) { - const res = smoothScrollToPreviousStep(top, section); - - if (res === 'previous' && sectionName !== 'scripts') { - const previousSectionName = - Object.keys(steps)[Object.keys(steps).indexOf(sectionName) - 1]; - const previousSection = steps[previousSectionName]; + if (subIndex !== undefined) { + const stepKey = subIndex === 0 ? 'scripts' : subIndex === 1 ? 'flows' : 'apps'; + const section = steps[stepKey]; - if (!previousSection) { - return; - } + if (!section) { + return; + } - const lastStepPercentage = previousSection.steps[previousSection.steps.length - 1]; - const scrollAmount = (lastStepPercentage * px) / 100 + (previousSection.total - px); + console.log(px, section); - window.scrollBy({ - top: scrollAmount - top, - behavior: 'smooth' - }); + smoothScrollToPreviousStep(top, { + total: px, + steps: section.steps + }); + } else { + for (const [sectionName, section] of Object.entries(steps)) { + if (top <= section.total) { + const res = smoothScrollToPreviousStep(top, section); + + if (res === 'previous' && sectionName !== 'scripts') { + const previousSectionName = + Object.keys(steps)[Object.keys(steps).indexOf(sectionName) - 1]; + const previousSection = steps[previousSectionName]; + + if (!previousSection) { + return; + } + + const lastStepPercentage = previousSection.steps[previousSection.steps.length - 1]; + const scrollAmount = (lastStepPercentage * px) / 100 + (previousSection.total - px); + + window.scrollBy({ + top: scrollAmount - top, + behavior: 'smooth' + }); + } + foundSection = true; + break; } - foundSection = true; - break; } } @@ -182,7 +218,7 @@ export default function TutorialSection() { } useEffect(() => { - setPx((15000 - window.innerHeight) / 3); + setPx((maxHeight - window.innerHeight) / 3); const handleKeyDown = (event) => { if (event.key === 'ArrowRight') { @@ -208,117 +244,125 @@ export default function TutorialSection() { setAnimationEnabled(false); }} animationEnabled={animationEnabled} + count={oneStep ? 1 : 3} > -
-
-
- {'Develop and iterate with instant feedback'} -
-
- {animationEnabled ? ( - <> +
+
{children}
+
+
+
+ {subIndex === undefined ? 'Develop and iterate with instant feedback' : ''} +
+
+ {animationEnabled ? ( + <> + + + + ) : ( - - - ) : ( - - )} + )} +
-
-
- {animationEnabled === false && ( -
-
- Animation disabled - +
+ {animationEnabled === false && ( +
+
+ Animation disabled + +
-
- )} -
- { - containerRef.current.scrollIntoView({ behavior: 'instant' }); - - window.scrollBy({ - top: i * px + 50, - behavior: 'instant' - }); - }} - /> - - - -
-
Scroll or use the arrow keys to navigate
-
- - +
+ { + containerRef.current.scrollIntoView({ behavior: 'instant' }); + + window.scrollBy({ + top: i * px + 50, + behavior: 'instant' + }); + }} + subIndex={subIndex} + /> + + + +
+
Scroll or use the arrow keys to navigate
+
+ + +
-
-
- +
+ +
)} diff --git a/src/landing/animations/AnimationCarousel.tsx b/src/landing/animations/AnimationCarousel.tsx index 3e4a28584..3f7f952cc 100644 --- a/src/landing/animations/AnimationCarousel.tsx +++ b/src/landing/animations/AnimationCarousel.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { motion, AnimatePresence } from 'framer-motion'; export default function AnimationCarousel({ items, currentIndex, itemWidth = 1000 }) { - const initialOffsetX = -(currentIndex * itemWidth + currentIndex * 16); + const initialOffsetX = items.length === 1 ? 0 : -(currentIndex * itemWidth + currentIndex * 16); return (
); }; -export default function ProgressBars({ setStep, handleClick }) { - const x = useContext(ScrollContext); +export default function ProgressBars({ setStep, handleClick, subIndex }) { + const ctx = useContext(ScrollContext); const [progress, setProgress] = React.useState(0); - useEffect( - () => - x.onChange((latest) => { - const latestAsNumber = latest; - setProgress(latestAsNumber); + useEffect(() => { + ctx?.on('change', (latest) => { + const latestAsNumber = latest; + setProgress(latestAsNumber); - let newStep = 0; - if (latestAsNumber < scriptScrollCount) { - newStep = 0; - } else if ( - latestAsNumber >= scriptScrollCount && - latestAsNumber < scriptScrollCount + flowScrollCount - ) { - newStep = 1; - } else if (latestAsNumber >= scriptScrollCount + flowScrollCount) { - newStep = 2; - } + let newStep = 0; + if (latestAsNumber < scriptScrollCount) { + newStep = 0; + } else if ( + latestAsNumber >= scriptScrollCount && + latestAsNumber < scriptScrollCount + flowScrollCount + ) { + newStep = 1; + } else if (latestAsNumber >= scriptScrollCount + flowScrollCount) { + newStep = 2; + } - setStep(newStep); - }), - [] - ); + setStep(newStep); + }); + }, []); - return ( -
- handleClick(0)} - title={'Scripts'} - progressColor="dark:bg-blue-600 bg-blue-400" - steps={[20, 40, 50, 60, 70, 80]} - barColor="bg-blue-700" - /> - scriptScrollCount} - onClick={() => handleClick(1)} - progressColor="dark:bg-green-600 bg-green-400" - title={'Flows'} - steps={[10, 20, 30, 40, 50, 60, 75, 80, 90]} - barColor="bg-green-700" - /> - scriptScrollCount + flowScrollCount} - onClick={() => handleClick(2)} - progressColor="dark:bg-orange-600 bg-orange-400" - title={'Apps'} - steps={[10, 15, 30, 45, 60, 72, 90, 99]} - barColor="bg-orange-700" - /> -
- ); + if (subIndex === undefined) { + return ( +
+ handleClick(0)} + title={'Scripts'} + progressColor="dark:bg-blue-600 bg-blue-400" + steps={[20, 40, 50, 60, 70, 80]} + barColor="bg-blue-700" + /> + scriptScrollCount} + onClick={() => handleClick(1)} + progressColor="dark:bg-green-600 bg-green-400" + title={'Flows'} + steps={[10, 20, 30, 40, 50, 60, 75, 80, 90]} + barColor="bg-green-700" + /> + scriptScrollCount + flowScrollCount} + onClick={() => handleClick(2)} + progressColor="dark:bg-orange-600 bg-orange-400" + title={'Apps'} + steps={[10, 15, 30, 45, 60, 72, 90, 99]} + barColor="bg-orange-700" + /> +
+ ); + } else if (subIndex === 0) { + return ( +
+ handleClick(0)} + title={'Scripts'} + progressColor="dark:bg-blue-600 bg-blue-400" + steps={[20, 40, 50, 60, 70, 80]} + barColor="bg-blue-700" + /> +
+ ); + } else if (subIndex === 1) { + return ( +
+ handleClick(1)} + progressColor="dark:bg-green-600 bg-green-400" + title={'Flows'} + steps={[10, 20, 30, 40, 50, 60, 75, 80, 90]} + barColor="bg-green-700" + /> +
+ ); + } else if (subIndex === 2) { + return ( +
+ handleClick(2)} + progressColor="dark:bg-orange-600 bg-orange-400" + title={'Apps'} + steps={[10, 15, 30, 45, 60, 72, 90, 99]} + barColor="bg-orange-700" + /> +
+ ); + } } diff --git a/src/landing/animations/SmoothScroll.tsx b/src/landing/animations/SmoothScroll.tsx index 55faa589d..91abad983 100644 --- a/src/landing/animations/SmoothScroll.tsx +++ b/src/landing/animations/SmoothScroll.tsx @@ -3,7 +3,7 @@ import React, { useEffect, useRef, useState } from 'react'; import ScrollContext from './ScrollContext'; import { flowScrollCount, scriptScrollCount, appScrollCount } from './useAnimateScroll'; -export default function SmoothScrol({ children, onReachEnd, animationEnabled }) { +export default function SmoothScrol({ children, onReachEnd, animationEnabled, count }) { const targetRef = useRef(null); const [hasReachedEnd, setHasReachedEnd] = useState(false); const { scrollYProgress } = useScroll({ @@ -18,7 +18,9 @@ export default function SmoothScrol({ children, onReachEnd, animationEnabled }) useEffect(() => { const unsubscribe = scrollYProgress.onChange((value) => { - if (value >= 0.999 && !hasReachedEnd) { + const coef = count === 1 ? 3 : 1; + + if (value * coef >= 0.999 && !hasReachedEnd) { setHasReachedEnd(true); onReachEnd(); window.scrollTo({ @@ -53,7 +55,7 @@ export default function SmoothScrol({ children, onReachEnd, animationEnabled }) ref={targetRef} className="relative max-w-7xl px-4 lg:px-8 mx-auto w-full" style={{ - height: hasReachedEnd ? '100vh' : 15000 + height: hasReachedEnd ? '100vh' : 5000 * count }} >
-
+ +
{'Develop and iterate with instant feedback'}
-
- - Apps - -
-
+ +
diff --git a/src/pages/flows.jsx b/src/pages/flows.jsx index 9c882187c..f10eb79a7 100644 --- a/src/pages/flows.jsx +++ b/src/pages/flows.jsx @@ -8,7 +8,7 @@ import CallToAction from '../landing/CallToAction'; import LogoClouds from '../landing/LogoClouds'; import RadialBlur from '../landing/RadialBlur'; import HubExamples from '../landing/HubExamples'; -import Window from '../landing/animations/Window'; +import TutorialSection from '../landing/TutorialSection'; const hubExamples = [ { @@ -66,26 +66,13 @@ export default function FlowPage() { -
+
{'Develop and iterate with instant feedback'}
-
- - Flows - -
-
+
diff --git a/src/pages/index.js b/src/pages/index.js index 62650c520..c205b7433 100644 --- a/src/pages/index.js +++ b/src/pages/index.js @@ -25,7 +25,7 @@ function HomepageHeader() {
- +
diff --git a/src/pages/scripts.jsx b/src/pages/scripts.jsx index 73c958de3..16cfc5492 100644 --- a/src/pages/scripts.jsx +++ b/src/pages/scripts.jsx @@ -8,7 +8,7 @@ import CallToAction from '../landing/CallToAction'; import LogoClouds from '../landing/LogoClouds'; import RadialBlur from '../landing/RadialBlur'; import HubExamples from '../landing/HubExamples'; -import Window from '../landing/animations/Window'; +import TutorialSection from '../landing/TutorialSection'; const hubExamples = [ { @@ -81,26 +81,14 @@ export default function ScriptPage() { -
+ +
{'Develop and iterate with instant feedback'}
-
- - Scripts - -
-
+