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 && (
)}
);
};