Grabbed dndbeyond's source code
``` ~/go/bin/sourcemapper -output ddb -jsurl https://media.dndbeyond.com/character-app/static/js/main.90aa78c5.js ```
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
import { Box } from "@mui/material";
|
||||
import { StepType, TourContext, TourProvider } from "@reactour/tour";
|
||||
import { Dispatch, ReactNode, SetStateAction, useState } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
import { rulesEngineSelectors } from "@dndbeyond/character-rules-engine";
|
||||
|
||||
import { checkContrast } from "../../utils/Color";
|
||||
import GuidedTourButton from "./GuidedTourButton";
|
||||
|
||||
interface GuidedTourProps {
|
||||
children?: ReactNode;
|
||||
steps?: StepType[];
|
||||
step?: number;
|
||||
setStep?: SetStateAction<any>;
|
||||
beforeClose?: (target: Element | null) => void;
|
||||
afterOpen?: (target: Element | null) => void;
|
||||
showOnFirstLoad?: boolean;
|
||||
cookieName?: string;
|
||||
}
|
||||
|
||||
export default ({
|
||||
children,
|
||||
step,
|
||||
setStep,
|
||||
steps = [],
|
||||
beforeClose,
|
||||
afterOpen,
|
||||
showOnFirstLoad,
|
||||
cookieName = "ddbGuidedTour",
|
||||
}: GuidedTourProps) => {
|
||||
const [defaultStep, setDefaultStep] = useState(0);
|
||||
const { isDarkMode, backgroundColor, themeColor } = useSelector(
|
||||
rulesEngineSelectors.getCharacterTheme
|
||||
);
|
||||
const bgColor = backgroundColor.slice(0, 7);
|
||||
const accentColor = checkContrast(backgroundColor, themeColor)
|
||||
? themeColor
|
||||
: "#C53131";
|
||||
|
||||
const handleBeforeClose = () => {
|
||||
const html = document.querySelector("html");
|
||||
if (html) html.style.overflowY = "visible";
|
||||
if (beforeClose) beforeClose(null);
|
||||
};
|
||||
|
||||
const handleAfterOpen = () => {
|
||||
const html = document.querySelector("html");
|
||||
if (html) html.style.overflowY = "hidden";
|
||||
if (afterOpen) afterOpen(null);
|
||||
};
|
||||
|
||||
const handleLoad = (setIsOpen: Dispatch<SetStateAction<boolean>>) => {
|
||||
if (showOnFirstLoad) {
|
||||
const viewedTour = localStorage.getItem(cookieName);
|
||||
|
||||
if (!viewedTour) {
|
||||
setIsOpen(true);
|
||||
localStorage.setItem(cookieName, "true");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
".reactour__popover": {
|
||||
backgroundColor: `${bgColor} !important`,
|
||||
color: isDarkMode
|
||||
? "rgba(255,255,255,0.9) !important"
|
||||
: "rgba(0,0,0,0.9) !important",
|
||||
borderRadius: 1,
|
||||
borderWidth: 1,
|
||||
borderStyle: "solid",
|
||||
borderColor: isDarkMode
|
||||
? "rgba(255,255,255,0.3) !important"
|
||||
: "rgba(0,0,0,0.3) !important",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<TourProvider
|
||||
steps={steps}
|
||||
currentStep={step || defaultStep}
|
||||
setCurrentStep={setStep || setDefaultStep}
|
||||
afterOpen={handleAfterOpen}
|
||||
beforeClose={handleBeforeClose}
|
||||
showDots={false}
|
||||
styles={{
|
||||
badge: (base) => ({
|
||||
...base,
|
||||
backgroundColor: accentColor,
|
||||
color: bgColor,
|
||||
fontWeight: 700,
|
||||
}),
|
||||
close: (base) => ({
|
||||
...base,
|
||||
color: isDarkMode ? "rgba(255,255,255,0.9)" : "rgba(0,0,0,0.9)",
|
||||
}),
|
||||
dot: (base, status) => ({
|
||||
...base,
|
||||
background: status?.current ? accentColor : "transparent",
|
||||
color: status?.current ? accentColor : "transparent",
|
||||
}),
|
||||
}}
|
||||
>
|
||||
<TourContext.Consumer>
|
||||
{({ setIsOpen }) => (
|
||||
<div onLoad={() => handleLoad(setIsOpen)}>
|
||||
{children}
|
||||
<GuidedTourButton />
|
||||
</div>
|
||||
)}
|
||||
</TourContext.Consumer>
|
||||
</TourProvider>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
import QuestionMarkIcon from "@mui/icons-material/QuestionMark";
|
||||
import { Button } from "@mui/material";
|
||||
import { useTour } from "@reactour/tour";
|
||||
|
||||
export default () => {
|
||||
const { setIsOpen } = useTour();
|
||||
|
||||
return (
|
||||
<Button
|
||||
className="ct-character-guided-tour"
|
||||
variant="contained"
|
||||
color="info"
|
||||
onClick={() => setIsOpen(true)}
|
||||
sx={{
|
||||
position: "fixed",
|
||||
zIndex: 9,
|
||||
p: 1,
|
||||
borderRadius: "100%",
|
||||
minWidth: 0,
|
||||
bottom: { xs: 100, md: 20 },
|
||||
right: 20,
|
||||
}}
|
||||
>
|
||||
<QuestionMarkIcon />
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
import GuidedTourButton from "./GuidedTourButton";
|
||||
|
||||
export default GuidedTourButton;
|
||||
export { GuidedTourButton };
|
||||
@@ -0,0 +1,50 @@
|
||||
import { Button, Typography } from "@mui/material";
|
||||
import { useTour } from "@reactour/tour";
|
||||
import { useSelector } from "react-redux";
|
||||
|
||||
import { rulesEngineSelectors } from "@dndbeyond/character-rules-engine";
|
||||
|
||||
import { checkContrast } from "../../../utils/Color";
|
||||
|
||||
export default ({ title, content, showClose = false }) => {
|
||||
const { themeColor, backgroundColor, isDarkMode } = useSelector(
|
||||
rulesEngineSelectors.getCharacterTheme
|
||||
);
|
||||
const { setIsOpen } = useTour();
|
||||
const accentColor = checkContrast(backgroundColor, themeColor)
|
||||
? themeColor
|
||||
: "#C53131";
|
||||
|
||||
return (
|
||||
<>
|
||||
<Typography variant="h4" component="p" mb={1}>
|
||||
{title}
|
||||
</Typography>
|
||||
<Typography
|
||||
component="div"
|
||||
variant="body2"
|
||||
sx={{ a: { color: accentColor, textDecoration: "none" } }}
|
||||
>
|
||||
{content}
|
||||
</Typography>
|
||||
{showClose && (
|
||||
<Button
|
||||
variant="outlined"
|
||||
onClick={() => setIsOpen(false)}
|
||||
sx={{
|
||||
display: "inherit",
|
||||
my: 1,
|
||||
mx: "auto",
|
||||
fontSize: 12,
|
||||
color: isDarkMode
|
||||
? "rgba(255,255,255,0.9) !important"
|
||||
: "rgba(0,0,0,0.9) !important",
|
||||
borderColor: accentColor,
|
||||
}}
|
||||
>
|
||||
Start Playing!
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user