import React from 'react';
import { sendGAEvent } from '@next/third-parties/google';
import type { SxProps } from '@mui/joy/styles/types';
import { Box, Button, Step, stepClasses, StepIndicator, stepIndicatorClasses, Stepper, Typography } from '@mui/joy';
import ArrowBackRoundedIcon from '@mui/icons-material/ArrowBackRounded';
import ArrowForwardRoundedIcon from '@mui/icons-material/ArrowForwardRounded';
import CheckRoundedIcon from '@mui/icons-material/CheckRounded';
import KeyboardArrowDownRoundedIcon from '@mui/icons-material/KeyboardArrowDownRounded';
import { AutoBlocksRenderer } from '~/modules/blocks/AutoBlocksRenderer';
import { AgiSquircleIcon } from '~/common/components/icons/AgiSquircleIcon';
import { ChatBeamIcon } from '~/common/components/icons/ChatBeamIcon';
import { ShortcutKey, useGlobalShortcuts } from '~/common/components/shortcuts/useGlobalShortcuts';
import { animationTextShadowLimey } from '~/common/util/animUtils';
import { hasGoogleAnalytics } from '~/common/components/GoogleAnalytics';
import { useIsMobile } from '~/common/components/useMatchMedia';
import { useUIContentScaling } from '~/common/state/store-ui';
// configuration
const colorButtons = 'neutral' as const;
const colorStepper = 'neutral' as const;
// Steps - the top stepper
interface ExplainerStep {
stepDigits: string,
stepName: string,
}
const stepSequenceSx: SxProps = {
// width: '100%',
[`& .${stepClasses.completed}::after`]: {
bgcolor: `${colorStepper}.500`,
},
[`& .${stepClasses.active} .${stepIndicatorClasses.root}`]: {
borderColor: `${colorStepper}.500`,
},
[`& .${stepClasses.root}:has(+ .${stepClasses.active})::after`]: {
color: `${colorStepper}.500`,
backgroundColor: 'transparent',
backgroundImage: 'radial-gradient(currentColor 2px, transparent 2px)',
backgroundSize: '7px 7px',
backgroundPosition: 'center left',
},
};
const buttonBaseSx: SxProps = {
justifyContent: 'space-between',
minHeight: '2.5rem',
minWidth: 120,
};
const buttonNextSx: SxProps = {
...buttonBaseSx,
boxShadow: `0 8px 24px -4px rgb(var(--joy-palette-${colorButtons}-mainChannel) / 20%)`,
minWidth: 180,
};
function AllStepsStepper(props: {
steps: ExplainerStep[],
activeIndex: number,
isMobile: boolean,
onStepClicked: (stepIndex: number) => void,
}) {
return (
{props.steps.map(((step, stepIndex) => {
const completed = props.activeIndex > stepIndex;
const active = props.activeIndex === stepIndex;
return (
props.onStepClicked(stepIndex)}
sx={{ cursor: 'pointer' }}
>
{completed ? : active ? : undefined}
}
>
{step.stepName}
}
>{step.stepDigits ?? null}
);
}))}
);
}
// The Explainer - Carousel of pages
export interface ExplainerPage extends ExplainerStep {
titlePrefix?: string,
titleSquircle?: boolean,
titleSpark?: string,
titleSuffix?: string,
mdContent: string
}
export function ExplainerCarousel(props: {
explainerId: string,
steps: ExplainerPage[],
footer?: React.ReactNode,
noStepper?: boolean,
onFinished: () => any,
}) {
// state
const [stepIndex, setStepIndex] = React.useState(0);
// external state
const isMobile = useIsMobile();
const contentScaling = useUIContentScaling();
// derived state
const { onFinished } = props;
const isFirstPage = stepIndex === 0;
const isLastPage = stepIndex === props.steps.length - 1;
const activeStep = props.steps[stepIndex] ?? null;
// handlers
const mdText = activeStep?.mdContent ?? null;
const handlePrevPage = React.useCallback(() => {
setStepIndex(step => step > 0 ? step - 1 : step);
}, []);
const handleNextPage = React.useCallback(() => {
if (isLastPage) {
hasGoogleAnalytics && sendGAEvent('event', 'tutorial_complete', { tutorial_id: props.explainerId });
onFinished();
} else
setStepIndex(step => step < props.steps.length - 1 ? step + 1 : step);
}, [isLastPage, onFinished, props.explainerId, props.steps.length]);
React.useEffect(() => {
const recordTutorialBegun = () => {
hasGoogleAnalytics && sendGAEvent('event', 'tutorial_begin', { tutorial_id: props.explainerId });
};
const timeoutId = setTimeout(recordTutorialBegun, 500);
return () => clearTimeout(timeoutId);
}, [props.explainerId]);
useGlobalShortcuts('ExplainerCarousel', React.useMemo(() => [
{ key: ShortcutKey.Left, action: handlePrevPage },
{ key: ShortcutKey.Right, action: handleNextPage },
], [handleNextPage, handlePrevPage]));
// [effect] restart from 0 if steps change
// React.useEffect(() => {
// setStepIndex(0);
// }, [props.steps]);
return (
{/* Page Title */}
{activeStep?.titlePrefix}{' '}
{!!activeStep?.titleSquircle && }
{!!activeStep?.titleSquircle && '-'}
{!!activeStep?.titleSpark &&
{activeStep.titleSpark}
}{activeStep?.titleSuffix}
{/* Page Message */}
{/* Main Card with the markdown body */}
{!!mdText && (
)}
{/* Advance Button */}
: }
sx={buttonNextSx}
>
{isLastPage ? 'Start' : 'Next'}
{/* Back Button */}
}
sx={buttonBaseSx}
>
Previous
{/* All Steps */}
{props.noStepper ? null : (
)}
{/* Final words of wisdom (also perfect for centering the other components) */}
{props.footer}
);
}