Skip to main content
Glama
TutorialProvider.tsx2.93 kB
import { useState, useEffect } from 'react' import Joyride, { CallBackProps, STATUS, Step } from 'react-joyride' import { dashboardSteps, serverViewSteps, TUTORIAL_STORAGE_KEY, TUTORIAL_SERVER_VIEW_KEY } from './tutorialSteps.tsx' export type TutorialType = 'dashboard' | 'server' interface TutorialProviderProps { run: boolean type: TutorialType onComplete: () => void } const joyrideStyles = { options: { primaryColor: '#3B82F6', zIndex: 10000, }, tooltip: { borderRadius: 8, padding: 16, }, tooltipTitle: { fontSize: 16, fontWeight: 600, marginBottom: 8, }, tooltipContent: { fontSize: 14, lineHeight: 1.6, whiteSpace: 'pre-line' as const, }, buttonNext: { backgroundColor: '#3B82F6', borderRadius: 6, padding: '8px 16px', }, buttonBack: { color: '#6B7280', marginRight: 8, }, buttonSkip: { color: '#9CA3AF', }, } const joyrideLocale = { back: 'back', close: 'close', last: 'last', next: 'next', skip: 'skip', } function TutorialProvider({ run, type, onComplete }: TutorialProviderProps) { const [stepIndex, setStepIndex] = useState(0) const [joyrideKey, setJoyrideKey] = useState(0) const steps: Step[] = type === 'dashboard' ? dashboardSteps : serverViewSteps const storageKey = type === 'dashboard' ? TUTORIAL_STORAGE_KEY : TUTORIAL_SERVER_VIEW_KEY // run이 true로 바뀔 때 stepIndex를 리셋하고 Joyride 인스턴스를 재생성 useEffect(() => { if (run) { setStepIndex(0) setJoyrideKey(prev => prev + 1) } }, [run]) const handleCallback = (data: CallBackProps) => { const { status, index, action, type: callbackType } = data const finishedStatuses: string[] = [STATUS.FINISHED, STATUS.SKIPPED] console.log('[Tutorial] Callback:', { status, index, action, callbackType }) // step 변경 추적 if (callbackType === 'step:after' && action === 'next') { setStepIndex(index + 1) } else if (callbackType === 'step:after' && action === 'prev') { setStepIndex(index - 1) } // 에러 발생 시 튜토리얼 종료 if (status === STATUS.ERROR) { console.error('[Tutorial] Error occurred, ending tutorial') onComplete() return } if (finishedStatuses.includes(status)) { localStorage.setItem(storageKey, 'true') onComplete() } } return ( <Joyride key={joyrideKey} steps={steps} stepIndex={stepIndex} run={run} continuous showSkipButton showProgress hideCloseButton scrollToFirstStep={false} disableScrolling={false} disableOverlayClose={true} disableCloseOnEsc={false} spotlightClicks={true} callback={handleCallback} styles={joyrideStyles} locale={joyrideLocale} floaterProps={{ disableAnimation: true, }} /> ) } export default TutorialProvider

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/seungwon9201/MCP-Dandan'

If you have feedback or need assistance with the MCP directory API, please join our Discord server