import React from "react"; import clsx from "clsx"; import { ArrowRightIcon } from "./icons/arrow-right"; import { RedoIcon } from "./icons/redo"; import { AnimatePresence, motion, useInView } from "framer-motion"; import Highlight, { defaultProps } from "prism-react-renderer"; import { usePrismTheme } from "@docusaurus/theme-common"; const WalkthroughCodeWindow = ({ code }: { code: string }) => { const theme = usePrismTheme(); return (
{["#FF5F5A", "#FFBE2E", "#2ACA44"].map((c) => (
))}
{({ tokens, getLineProps, getTokenProps }) => ( <> {tokens.map((line, i) => (
{line.map((token, key) => { const content = `${token.content}`.replace( "___", "    ", ); const { children: _children, ...tokenProps } = getTokenProps({ token, }); return ( ); })}
))} )}
); }; const WalkthroughNextButton = ({ onClick, children, }: { onClick: () => void; children: React.ReactNode; }) => { return (
{children}
); }; const WalkthroughRestartButton = ({ onClick }: { onClick: () => void }) => { return (
Start Over
); }; const WalkthroughNextButtonLabel = ({ text }: { text: string }) => { return ( Next: {text} ); }; const WalkthroughPhaseWrapper = ({ onClick, text, code, end, }: { onClick: () => void; code: string; text?: string; end?: boolean; }) => { return ( {end && } {text && ( )} ); }; const walkthroughPhases = [ "initial", "add-your-backend", "hook-the-table", "add-your-ui-framework", "add-more-crud-functions", "add-more-routes", "secure-your-app", "restart", ] as const; type WalkthroughPhase = (typeof walkthroughPhases)[number]; const phaseCheckpoints: Record<(typeof walkthroughPhases)[number], number> = { initial: 0.0, "add-your-backend": 0.8, "hook-the-table": 1.7, "add-your-ui-framework": 8, "add-more-crud-functions": 16, "add-more-routes": 17, "secure-your-app": 17.9, restart: 23.8, }; const phaseData: Record< WalkthroughPhase, { code?: string; text?: string; end?: boolean; } > = { initial: {}, "add-your-backend": { code: ` import { Refine } from "@refinedev/core"; /* ... */ } /> `, text: "Add your Backend", }, "hook-the-table": { code: ` import dataProvider from "@refinedev/nestjsx-crud"; `, text: "Hook the Table", }, "add-your-ui-framework": { code: ` import { useTable } from "@refinedev/core"; /* ... */ const tableValues = useTable(); /* ... */ {...}
`, text: "Add your UI Framework", }, "add-more-crud-functions": { code: ` import { Table } from "antd"; import { Layout, List } from "@refinedev/antd"; import { useTable } from "@refinedev/antd"; `, text: "Add more CRUD functions", }, "add-more-routes": { code: ` { ___name: "orders", ___list: "/orders", ___show: "/orders/show/:id", ___create: "/orders/create", ___edit: "/orders/edit:id", } `, text: "Add more Routes", }, "secure-your-app": { code: ` } /> } /> } /> `, text: "Secure your App", }, restart: { code: ` import { AuthPage } from "@refinedev/antd"; import { Auth0Provider } from "@auth0/auth0-react"; `, end: true, }, }; const getNextPhase = (phase: WalkthroughPhase) => { const currentIndex = walkthroughPhases.indexOf(phase); if (currentIndex === -1) { return "initial"; } if (currentIndex === walkthroughPhases.length - 1) { return "initial"; } return walkthroughPhases[currentIndex + 1]; }; const isAtCheckpoint = (currentTime: number, phase: WalkthroughPhase) => { // we can consider the checkpoint to be reached if we're at exact time or past 0.25s const lowerBound = phaseCheckpoints[phase]; const upperBound = phaseCheckpoints[phase] + 0.125; return currentTime >= lowerBound && currentTime <= upperBound; }; export const LandingWalkthroughVideo = () => { const videoRef = React.useRef(null); const [phase, setPhase] = React.useState("initial"); const [isPlaying, setIsPlaying] = React.useState(false); const inView = useInView(videoRef, { amount: "all", once: true, }); const onTime = React.useCallback( (currentTime: number) => { const nextPhase = getNextPhase(phase); const atNext = isAtCheckpoint(currentTime, nextPhase); if (atNext) { videoRef?.current?.pause(); setPhase(nextPhase); } }, [phase], ); React.useEffect(() => { if (isPlaying) { const interval = setInterval(() => { onTime(videoRef.current?.currentTime); }, 10); return () => { clearInterval(interval); }; } }, [isPlaying]); const onPhaseClick = React.useCallback(() => { videoRef.current?.play(); }, []); React.useEffect(() => { if (inView) { videoRef.current?.play(); } else { videoRef.current?.pause(); } }, [inView]); return (
{phase !== "initial" && !isPlaying && ( )}
); };