mcp-quiz-server
Version:
🧠AI-Powered Quiz Management via Model Context Protocol (MCP) - Create, manage, and take quizzes directly from VS Code, Claude, and other AI agents.
209 lines • 8.04 kB
JavaScript
import { TourService } from '../services/TourService';
import { DOMUtils } from '../utils/index';
import { Component } from './Component';
export class TourModal extends Component {
constructor() {
super('#tour-modal');
this.currentStep = null;
this.currentState = null;
this.tourService = TourService.getInstance();
this.tourService.setTourModal(this);
}
render() {
}
bindEvents() {
this.element.addEventListener('click', e => {
if (e.target === this.element) {
this.tourService.skipTour();
}
});
const prevBtn = this.element.querySelector('#tour-prev-btn');
const nextBtn = this.element.querySelector('#tour-next-btn');
const skipBtn = this.element.querySelector('#tour-skip-btn');
const closeBtn = this.element.querySelector('#tour-close-btn');
prevBtn?.addEventListener('click', () => {
this.tourService.previousStep();
});
nextBtn?.addEventListener('click', () => {
this.tourService.nextStep();
});
skipBtn?.addEventListener('click', () => {
this.tourService.skipTour();
});
closeBtn?.addEventListener('click', () => {
this.tourService.skipTour();
});
document.addEventListener('keydown', this.handleKeydown.bind(this));
const video = this.element.querySelector('#tour-video');
if (video) {
video.addEventListener('ended', () => {
const autoAdvance = this.element.querySelector('#auto-advance-toggle');
if (autoAdvance?.checked && this.currentState?.canGoNext) {
setTimeout(() => this.tourService.nextStep(), 1000);
}
});
}
}
handleKeydown(e) {
if (!this.currentState?.isActive)
return;
switch (e.key) {
case 'Escape':
this.tourService.skipTour();
break;
case 'ArrowLeft':
if (this.currentState.canGoBack) {
e.preventDefault();
this.tourService.previousStep();
}
break;
case 'ArrowRight':
case 'Enter':
case ' ':
if (this.currentState.canGoNext) {
e.preventDefault();
this.tourService.nextStep();
}
else if (!this.currentState.canGoNext &&
this.currentState.currentStep === this.currentState.totalSteps) {
e.preventDefault();
this.tourService.completeTour();
}
break;
}
}
showStep(step, state) {
this.currentStep = step;
this.currentState = state;
this.updateContent(step);
this.updateNavigation(state);
this.updateProgress(state);
this.show();
const nextBtn = this.element.querySelector('#tour-next-btn');
const skipBtn = this.element.querySelector('#tour-skip-btn');
(nextBtn || skipBtn)?.focus();
}
updateContent(step) {
const title = this.element.querySelector('#tour-title');
if (title) {
title.textContent = step.title;
}
const content = this.element.querySelector('#tour-content');
if (content) {
content.innerHTML = DOMUtils.escapeHtml(step.content);
}
const videoSection = this.element.querySelector('#tour-video-section');
const videoElement = this.element.querySelector('#tour-video');
if (step.video && videoSection) {
videoSection.classList.remove('hidden');
if (videoElement) {
videoElement.src = step.video;
videoElement.load();
}
}
else if (videoSection) {
videoSection.classList.add('hidden');
}
}
updateNavigation(state) {
const prevBtn = this.element.querySelector('#tour-prev-btn');
const nextBtn = this.element.querySelector('#tour-next-btn');
const skipBtn = this.element.querySelector('#tour-skip-btn');
if (prevBtn) {
prevBtn.disabled = !state.canGoBack;
prevBtn.classList.toggle('opacity-50', !state.canGoBack);
prevBtn.classList.toggle('cursor-not-allowed', !state.canGoBack);
}
if (nextBtn) {
nextBtn.disabled = !state.canGoNext;
nextBtn.classList.toggle('opacity-50', !state.canGoNext);
nextBtn.classList.toggle('cursor-not-allowed', !state.canGoNext);
if (state.currentStep === state.totalSteps) {
nextBtn.textContent = 'Finish';
nextBtn.classList.add('bg-green-600', 'hover:bg-green-700');
nextBtn.classList.remove('bg-primary-600', 'hover:bg-primary-700');
}
else {
nextBtn.textContent = 'Next';
nextBtn.classList.remove('bg-green-600', 'hover:bg-green-700');
nextBtn.classList.add('bg-primary-600', 'hover:bg-primary-700');
}
}
if (skipBtn) {
skipBtn.classList.toggle('hidden', !state.canSkip);
}
}
updateProgress(state) {
const stepCounter = this.element.querySelector('#tour-step-counter');
if (stepCounter) {
stepCounter.textContent = `${state.currentStep} of ${state.totalSteps}`;
}
const progressBar = this.element.querySelector('#tour-progress-bar');
if (progressBar) {
const percentage = (state.currentStep / state.totalSteps) * 100;
progressBar.style.width = `${percentage}%`;
}
const dots = this.element.querySelectorAll('.tour-progress-dot');
dots.forEach((dot, index) => {
if (index < state.currentStep) {
dot.classList.add('bg-primary-600');
dot.classList.remove('bg-surface-300');
}
else {
dot.classList.remove('bg-primary-600');
dot.classList.add('bg-surface-300');
}
});
}
loadVideo(videoUrl) {
const video = this.element.querySelector('#tour-video');
if (!video)
return;
video.src = videoUrl;
video.load();
const playButton = this.element.querySelector('#video-play-btn');
if (playButton) {
playButton.classList.remove('hidden');
playButton.addEventListener('click', () => {
video.play();
playButton.classList.add('hidden');
});
}
video.addEventListener('play', () => {
video.controls = true;
});
}
show() {
this.element.classList.remove('hidden');
this.element.classList.add('flex');
setTimeout(() => {
const content = this.element.querySelector('.modal-content');
content?.classList.remove('translate-y-full', 'md:translate-y-0');
content?.classList.add('translate-y-0');
}, 10);
document.body.style.overflow = 'hidden';
}
hide() {
const content = this.element.querySelector('.modal-content');
content?.classList.add('translate-y-full', 'md:translate-y-0');
content?.classList.remove('translate-y-0');
setTimeout(() => {
this.element.classList.add('hidden');
this.element.classList.remove('flex');
document.body.style.overflow = '';
const video = this.element.querySelector('#tour-video');
if (video) {
video.pause();
video.currentTime = 0;
video.removeAttribute('src');
}
}, 300);
}
getCurrentStep() {
return this.currentStep;
}
getCurrentState() {
return this.currentState;
}
}
//# sourceMappingURL=TourModal.js.map