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.
487 lines (441 loc) • 34.6 kB
HTML
<!--
/**
* @moduleName: Quiz Platform - Multi-Quiz Interface
* @version: 2.0.0
* @since: 2025-07-21
* @lastUpdated: 2025-07-22
* @projectSummary: Enhanced multi-quiz platform with sidebar navigation, card-based layout, and database integration
* @techStack: HTML5, Tailwind CSS, TypeScript, Responsive Design, Grid Layout
* @dependency: output.css (Tailwind), dist/main.js (compiled modular TypeScript)
* @interModuleDependency: js/main.ts (modular frontend architecture), enhanced backend REST API
* @requirementsTraceability: REQ-031 (Web Interface), REQ-032 (Responsive Design), REQ-034 (Multi-Quiz Management)
* @briefDescription: Modern quiz platform with sidebar navigation, card-based quiz selection, search functionality, and enhanced user experience
* @contributors: Jorge Sequeira, Database Integration Team
* @examples: Accessible at http://localhost:3000 when enhanced server running
* @vulnerabilitiesAssessment: Static HTML, XSS prevention via controlled script execution, HTTPS recommended for production
*/
-->
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI Quiz Platform</title>
<link href="output.css?v=3" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/lucide@latest/dist/umd/lucide.js"></script>
</head>
<body class="bg-surface-50 dark:bg-surface-900 min-h-screen transition-colors">
<!-- Header -->
<header class="bg-white dark:bg-surface-800 shadow-sm border-b border-surface-200 dark:border-surface-700">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between items-center h-16">
<div class="flex items-center">
<h1 class="text-xl font-bold text-surface-900 dark:text-surface-100">AI Quiz Platform</h1>
</div>
<div class="flex items-center space-x-4">
<!-- Settings Button -->
<div class="relative">
<button id="settings-menu-btn" class="flex items-center space-x-2 px-3 py-2 rounded-lg text-sm font-medium text-surface-700 dark:text-surface-300 hover:bg-surface-100 dark:hover:bg-surface-700 transition-colors">
<i data-lucide="settings" class="w-4 h-4"></i>
<span class="hidden sm:inline">Settings</span>
</button>
<!-- Settings Dropdown -->
<div id="settings-dropdown" class="absolute right-0 mt-2 w-80 bg-white dark:bg-surface-800 rounded-lg shadow-lg border border-surface-200 dark:border-surface-600 z-50 hidden">
<div class="p-4">
<div class="flex items-center justify-between mb-4">
<h3 class="text-lg font-medium text-surface-900 dark:text-surface-100">Settings</h3>
<button id="close-settings-menu" class="text-surface-400 hover:text-surface-600 dark:hover:text-surface-300">
<i data-lucide="x" class="w-4 h-4"></i>
</button>
</div>
<!-- UI Preferences -->
<div class="space-y-4">
<div>
<h4 class="text-sm font-medium text-surface-900 dark:text-surface-100 mb-2">Settings</h4>
<!-- 🎮 Quiz Experience (Primary Settings) -->
<div class="space-y-4">
<h5 class="text-xs font-medium text-surface-600 dark:text-surface-400 uppercase tracking-wide">Quiz Experience</h5>
<!-- Quiz Mode (Unified Control) -->
<div class="flex items-center justify-between">
<div>
<label class="text-sm text-surface-700 dark:text-surface-300">Quiz Mode</label>
<div class="text-xs text-surface-500 dark:text-surface-400">How answers are displayed and selected</div>
</div>
<select id="quiz-mode" class="text-sm border-surface-300 dark:border-surface-600 rounded px-2 py-1 bg-white dark:bg-surface-800">
<option value="traditional">Traditional (radio buttons)</option>
<option value="cards" selected>Click-to-select cards</option>
<option value="instant">Instant feedback mode</option>
</select>
</div>
<!-- Auto-advance (Unified Control) -->
<div class="flex items-center justify-between">
<div>
<label class="text-sm text-surface-700 dark:text-surface-300">Auto-advance</label>
<div class="text-xs text-surface-500 dark:text-surface-400">Automatically move to next question</div>
</div>
<select id="auto-advance-mode" class="text-sm border-surface-300 dark:border-surface-600 rounded px-2 py-1 bg-white dark:bg-surface-800">
<option value="off">Off - manual navigation</option>
<option value="basic">Basic (2 seconds)</option>
<option value="enhanced" selected>Enhanced with feedback (3 seconds)</option>
<option value="custom">Custom delay...</option>
</select>
</div>
<!-- Custom delay (hidden by default) -->
<div class="flex items-center justify-between" id="custom-delay-row" style="display: none;">
<div>
<label class="text-sm text-surface-700 dark:text-surface-300">Custom delay</label>
<div class="text-xs text-surface-500 dark:text-surface-400">Seconds to wait before advancing</div>
</div>
<div class="flex items-center space-x-2">
<input type="range" id="auto-advance-delay-slider" min="1" max="10" value="3" class="w-20">
<span id="delay-value" class="text-sm text-surface-600 dark:text-surface-400 min-w-[4rem]">3 seconds</span>
</div>
</div>
</div>
<!-- ⚡ Quick Settings (Secondary) -->
<div class="border-t border-surface-200 dark:border-surface-700 pt-4 space-y-4">
<h5 class="text-xs font-medium text-surface-600 dark:text-surface-400 uppercase tracking-wide">Quick Settings</h5>
<div class="space-y-3">
<label class="flex items-center justify-between cursor-pointer">
<span class="text-sm text-surface-700 dark:text-surface-300">Show question numbers</span>
<input type="checkbox" id="show-question-numbers" checked class="rounded border-surface-300 dark:border-surface-600 text-primary-600 focus:ring-primary-500">
</label>
<!-- Timer settings moved to QuizStartModal for better UX -->
<div class="text-xs text-surface-500 dark:text-surface-400 italic">
💡 Timer settings available when starting a quiz
</div>
</div>
</div>
<!-- 🔧 Advanced Settings (Collapsed) -->
<div class="border-t border-surface-200 dark:border-surface-700 pt-4">
<details class="advanced-settings">
<summary class="text-xs font-medium text-surface-600 dark:text-surface-400 uppercase tracking-wide cursor-pointer hover:text-surface-800 dark:hover:text-surface-200">
Advanced Settings
</summary>
<div class="mt-3 space-y-3">
<label class="flex items-center justify-between cursor-pointer">
<span class="text-sm text-surface-700 dark:text-surface-300">Smart submit behavior</span>
<input type="checkbox" id="smart-submit-logic" checked class="rounded border-surface-300 dark:border-surface-600 text-primary-600 focus:ring-primary-500">
</label>
<label class="flex items-center justify-between cursor-pointer">
<span class="text-sm text-surface-700 dark:text-surface-300">Enable animations</span>
<input type="checkbox" id="enable-animations" checked class="rounded border-surface-300 dark:border-surface-600 text-primary-600 focus:ring-primary-500">
</label>
<label class="flex items-center justify-between cursor-pointer">
<span class="text-sm text-surface-700 dark:text-surface-300">Hide disabled navigation</span>
<input type="checkbox" id="hide-nav-buttons" class="rounded border-surface-300 dark:border-surface-600 text-primary-600 focus:ring-primary-500">
</label>
</div>
</details>
</div>
</div>
<!-- Quiz Defaults -->
<div class="border-t border-surface-200 dark:border-surface-700 pt-4">
<h4 class="text-sm font-medium text-surface-900 dark:text-surface-100 mb-2">Quiz Defaults</h4>
<div class="space-y-3">
<!-- Default view mode -->
<div class="flex items-center justify-between">
<label class="text-sm text-surface-700 dark:text-surface-300">Default view mode</label>
<select id="default-view-mode" class="text-sm border border-surface-300 dark:border-surface-600 rounded px-2 py-1 bg-white dark:bg-surface-700 text-surface-900 dark:text-surface-100">
<option value="list">All Questions</option>
<option value="single">Single Question</option>
</select>
</div>
<!-- Animation preferences -->
<div class="flex items-center justify-between">
<label class="text-sm text-surface-700 dark:text-surface-300">Enable animations</label>
<input type="checkbox" id="enable-animations" checked class="rounded border-surface-300 dark:border-surface-600 text-primary-600 focus:ring-primary-500">
</div>
</div>
</div>
<!-- Reset Settings -->
<div class="border-t border-surface-200 dark:border-surface-700 pt-4">
<button id="reset-settings" class="w-full text-sm text-surface-600 dark:text-surface-400 hover:text-surface-800 dark:hover:text-surface-200 border border-surface-300 dark:border-surface-600 rounded px-3 py-2 hover:bg-surface-50 dark:hover:bg-surface-700 transition-colors">
Reset to Defaults
</button>
</div>
</div>
</div>
</div>
</div>
<!-- Theme Selector -->
<div class="relative">
<button id="theme-menu-btn" class="flex items-center space-x-2 px-3 py-2 rounded-lg text-sm font-medium text-surface-700 dark:text-surface-300 hover:bg-surface-100 dark:hover:bg-surface-700 transition-colors">
<i data-lucide="palette" class="w-4 h-4"></i>
<span class="hidden sm:inline">Theme</span>
</button>
<!-- Theme Dropdown -->
<div id="theme-dropdown" class="absolute right-0 mt-2 w-64 bg-white dark:bg-surface-800 rounded-lg shadow-lg border border-surface-200 dark:border-surface-600 z-50 hidden">
<div class="p-4">
<div class="flex items-center justify-between mb-4">
<h3 class="text-lg font-medium text-surface-900 dark:text-surface-100">Theme</h3>
<button id="close-theme-menu" class="text-surface-400 hover:text-surface-600 dark:hover:text-surface-300">
<i data-lucide="x" class="w-4 h-4"></i>
</button>
</div>
<!-- Modern Theme Options -->
<div class="space-y-2">
<button class="theme-option active" data-theme="light">
<div class="theme-icon bg-yellow-100 text-yellow-600">
<i data-lucide="sun" class="w-5 h-5"></i>
</div>
<div class="flex-1 text-left">
<div class="font-medium text-surface-900 dark:text-surface-100">Light</div>
<div class="text-sm text-surface-500 dark:text-surface-400">Clean and bright interface</div>
</div>
</button>
<button class="theme-option" data-theme="dark">
<div class="theme-icon bg-blue-100 text-blue-600 dark:bg-blue-900 dark:text-blue-400">
<i data-lucide="moon" class="w-5 h-5"></i>
</div>
<div class="flex-1 text-left">
<div class="font-medium text-surface-900 dark:text-surface-100">Dark</div>
<div class="text-sm text-surface-500 dark:text-surface-400">Easy on the eyes</div>
</div>
</button>
<button class="theme-option" data-theme="system">
<div class="theme-icon bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400">
<i data-lucide="monitor" class="w-5 h-5"></i>
</div>
<div class="flex-1 text-left">
<div class="font-medium text-surface-900 dark:text-surface-100">System</div>
<div class="text-sm text-surface-500 dark:text-surface-400">Follow system preference</div>
</div>
</button>
</div>
</div>
</div>
</div>
<button id="create-quiz-btn" class="bg-primary-600 hover:bg-primary-700 text-white px-4 py-2 rounded-md text-sm font-medium flex items-center transition-colors">
<i data-lucide="plus" class="w-4 h-4 mr-2"></i>
Create Quiz
</button>
</div>
</div>
</div>
</header>
<!-- Main Layout -->
<div class="flex h-screen pt-16">
<!-- Sidebar -->
<aside id="sidebar" class="w-80 bg-white dark:bg-surface-800 shadow-sm border-r border-surface-200 dark:border-surface-700 flex flex-col transition-all duration-300 ease-in-out">
<!-- Sidebar Header with Toggle -->
<div class="p-4 border-b border-surface-200 dark:border-surface-700 flex items-center justify-between">
<h2 class="text-lg font-semibold text-surface-900 dark:text-surface-100">Quizzes</h2>
<button id="sidebar-toggle" class="p-1 rounded-lg hover:bg-surface-100 dark:hover:bg-surface-700 transition-colors" title="Toggle sidebar">
<i data-lucide="panel-left-close" class="w-5 h-5 text-surface-600 dark:text-surface-400"></i>
</button>
</div>
<!-- Search Bar -->
<div class="p-4 border-b border-surface-200 dark:border-surface-700">
<div class="relative">
<input
type="text"
id="search-input"
placeholder="Search quizzes..."
class="w-full pl-10 pr-4 py-2 border border-surface-300 dark:border-surface-600 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent bg-white dark:bg-surface-700 text-surface-900 dark:text-surface-100 placeholder-surface-500 dark:placeholder-surface-400"
>
<i data-lucide="search" class="absolute left-3 top-2.5 w-4 h-4 text-surface-400 dark:text-surface-500"></i>
</div>
</div>
<!-- Filter Tabs -->
<div class="px-4 py-2 border-b border-surface-200 dark:border-surface-700">
<div class="flex items-center justify-between">
<div class="flex space-x-1">
<button class="filter-tab active px-3 py-1 text-sm rounded-md bg-primary-100 dark:bg-primary-900 text-primary-700 dark:text-primary-300" data-filter="all">
All
</button>
<button class="filter-tab px-3 py-1 text-sm rounded-md text-surface-600 dark:text-surface-400 hover:bg-surface-100 dark:hover:bg-surface-700" data-filter="recent">
Recent
</button>
<button class="filter-tab px-3 py-1 text-sm rounded-md text-surface-600 dark:text-surface-400 hover:bg-surface-100 dark:hover:bg-surface-700" data-filter="favorites">
Favorites
</button>
</div>
<!-- Refresh Button -->
<button id="refresh-quizzes-btn" class="p-1 text-surface-500 dark:text-surface-400 hover:text-surface-700 dark:hover:text-surface-300 hover:bg-surface-100 dark:hover:bg-surface-700 rounded-md transition-colors" title="Refresh quiz list">
<i data-lucide="refresh-cw" class="w-4 h-4"></i>
</button>
</div>
</div>
<!-- Quiz List -->
<div class="flex-1 overflow-y-auto">
<div id="quiz-list" class="p-4 space-y-3">
<!-- Quiz cards will be populated here -->
</div>
</div>
</aside>
<!-- Main Content -->
<main id="main-content" class="flex-1 overflow-hidden transition-all duration-300 ease-in-out">
<!-- Floating Sidebar Toggle (when collapsed) -->
<button id="floating-sidebar-toggle" class="fixed top-20 left-4 z-40 p-3 bg-white dark:bg-surface-800 rounded-lg shadow-lg border border-surface-200 dark:border-surface-600 hover:bg-surface-50 dark:hover:bg-surface-700 transition-colors hidden" title="Show sidebar">
<i data-lucide="panel-left-open" class="w-5 h-5 text-surface-600 dark:text-surface-400"></i>
</button>
<!-- Welcome Screen -->
<div id="welcome-screen" class="h-full flex items-center justify-center">
<div class="text-center">
<i data-lucide="brain" class="w-16 h-16 text-gray-400 mx-auto mb-4"></i>
<h2 class="text-2xl font-bold text-gray-900 mb-2">Welcome to AI Quiz Platform</h2>
<p class="text-gray-600 mb-6">Select a quiz from the sidebar to get started</p>
<button id="welcome-create-btn" class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-3 rounded-lg font-medium">
Create Your First Quiz
</button>
</div>
</div>
<!-- Quiz Content -->
<div id="quiz-content" class="hidden h-full flex flex-col">
<!-- Quiz Header with Enhanced Status Bar - STICKY TOP -->
<div class="sticky top-0 z-30 bg-white dark:bg-surface-800 border-b border-surface-200 dark:border-surface-700 px-3 lg:px-6 py-4 shadow-sm">
<!-- Top Status Bar with Progress and Timer -->
<div class="flex items-center justify-between mb-3 pb-3 border-b border-gray-100 dark:border-surface-600">
<div class="flex items-center space-x-3">
<!-- Breadcrumb Navigation -->
<nav class="flex items-center space-x-2 text-sm text-gray-500 dark:text-surface-400">
<span>Quiz Platform</span>
<i data-lucide="chevron-right" class="w-3 h-3"></i>
<span id="quiz-breadcrumb" class="text-gray-900 dark:text-surface-100 font-medium">Loading...</span>
</nav>
</div>
<!-- Progress Indicator with Timer -->
<div class="flex items-center space-x-4">
<!-- Timer (when enabled) -->
<div id="quiz-timer" class="hidden items-center space-x-2 text-sm text-orange-600 dark:text-orange-400">
<i data-lucide="clock" class="w-4 h-4"></i>
<span id="timer-display">05:00</span>
</div>
<!-- Progress -->
<div class="flex items-center space-x-3">
<span id="quiz-progress-text" class="text-sm text-gray-600 dark:text-surface-300">Question 1 of 10</span>
<div class="w-32 h-2 bg-gray-200 dark:bg-surface-600 rounded-full overflow-hidden">
<div id="quiz-progress-bar" class="h-full bg-primary-500 rounded-full transition-all duration-300" style="width: 10%"></div>
</div>
<span id="quiz-completion" class="text-sm font-medium text-primary-600 dark:text-primary-400">10%</span>
</div>
</div>
</div>
<!-- Quiz Title Section -->
<div class="flex items-center justify-between">
<div>
<h2 id="quiz-title" class="text-xl font-bold text-gray-900 dark:text-surface-100"></h2>
<p id="quiz-description" class="text-gray-600 dark:text-surface-300 text-sm mt-1"></p>
</div>
<div class="flex items-center space-x-3">
<!-- Timer Display (Display-only, configured in quiz start modal) -->
<div id="timer-display" class="flex items-center space-x-2 text-sm">
<span class="text-gray-500 dark:text-surface-400">⏱️</span>
<span id="timer-status" class="text-gray-600 dark:text-surface-300">Not configured</span>
<span id="timer-countdown" class="font-mono text-gray-800 dark:text-surface-200 hidden">00:00</span>
</div>
<!-- View Mode Toggle -->
<div id="view-mode-toggle" class="flex items-center space-x-2">
<span class="text-sm text-gray-500 dark:text-surface-400">View:</span>
<div class="flex bg-gray-100 dark:bg-surface-700 rounded-lg p-1">
<button id="view-mode-single" class="view-mode-btn px-3 py-1 text-xs rounded-md transition-all duration-200" data-mode="single">
📝 Single
</button>
<button id="view-mode-list" class="view-mode-btn px-3 py-1 text-xs rounded-md transition-all duration-200 bg-white dark:bg-surface-600 shadow-sm" data-mode="list">
📋 All
</button>
</div>
</div>
<button id="reset-quiz-btn" class="text-gray-400 hover:text-gray-600 dark:text-surface-500 dark:hover:text-surface-300" title="Reset Quiz">
<i data-lucide="refresh-cw" class="w-4 h-4"></i>
</button>
</div>
</div>
</div>
<!-- Quiz Questions - NO INTERNAL SCROLLING -->
<div class="flex-1 min-h-0 p-3 lg:p-6">
<div id="quiz-container" class="max-w-5xl mx-auto h-full w-full px-4">
<!-- Quiz questions will be populated here -->
</div>
</div>
<!-- Quiz Actions - FIXED BOTTOM -->
<div id="quiz-navigation-bar" class="quiz-navigation-bar fixed bottom-0 left-0 right-0 z-30 bg-white dark:bg-surface-800 border-t border-surface-200 dark:border-surface-700 px-3 lg:px-6 py-4 shadow-sm">
<div class="flex justify-between items-center">
<button id="prev-btn" class="nav-button prev-button flex items-center space-x-2 px-4 py-2 rounded-lg font-medium transition-all duration-300 disabled:opacity-30 disabled:cursor-not-allowed disabled:transform-none hover:scale-105 active:scale-95" disabled>
<div class="nav-icon-container">
<i data-lucide="chevron-left" class="w-4 h-4"></i>
</div>
<span>Previous Question</span>
</button>
<button id="submit-button" class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-2 rounded-lg font-medium transition duration-200">
Submit Quiz
</button>
<button id="next-btn" class="nav-button next-button flex items-center space-x-2 px-4 py-2 rounded-lg font-medium transition-all duration-300 disabled:opacity-30 disabled:cursor-not-allowed disabled:transform-none hover:scale-105 active:scale-95">
<span>Next Question</span>
<div class="nav-icon-container">
<i data-lucide="chevron-right" class="w-4 h-4"></i>
</div>
</button>
</div>
</div>
</div>
<!-- Results Modal -->
<div id="result-modal" class="fixed inset-0 bg-black bg-opacity-50 hidden items-center justify-center z-50 p-4">
<!-- Mobile: slide up animation, Desktop: center modal -->
<div class="bg-white dark:bg-surface-800 rounded-lg shadow-xl w-full max-w-lg md:max-w-2xl
transform transition-all duration-300 ease-out
max-h-[85vh] md:max-h-[80vh] flex flex-col
translate-y-full md:translate-y-0 modal-content">
<!-- Fixed Header -->
<div class="flex items-center justify-between p-4 md:p-6 border-b border-surface-200 dark:border-surface-600 flex-shrink-0">
<h3 class="text-lg md:text-xl font-bold text-surface-900 dark:text-surface-100">Quiz Results</h3>
<button id="close-results-btn" class="text-surface-400 hover:text-surface-600 dark:hover:text-surface-300 p-1 rounded-full hover:bg-surface-100 dark:hover:bg-surface-700 transition-colors">
<i data-lucide="x" class="w-5 h-5 md:w-6 md:h-6"></i>
</button>
</div>
<!-- Scrollable Content -->
<div class="flex-1 overflow-y-auto overscroll-contain">
<div id="result-container" class="p-4 md:p-6">
<!-- Results will be displayed here -->
</div>
</div>
<!-- Fixed Footer with Actions -->
<div id="result-actions" class="p-4 md:p-6 border-t border-surface-200 dark:border-surface-600 bg-surface-50 dark:bg-surface-700/50 flex-shrink-0">
<!-- Action buttons will be moved here -->
</div>
</div>
</div>
<!-- Tour Modal - SIMPLIFIED FOR BETTER VISIBILITY -->
<div id="tour-modal" class="fixed inset-0 bg-black bg-opacity-80 hidden items-center justify-center z-[9999] p-4">
<div class="bg-white rounded-xl border-4 border-blue-500 shadow-2xl w-full max-w-lg
p-8 text-center relative
min-h-[300px]
modal-content">
<!-- Simple Header -->
<div class="mb-6">
<h2 id="tour-title" class="text-2xl font-bold text-black mb-2">Welcome to Quiz Server!</h2>
<button id="tour-close-btn" class="absolute top-4 right-4 text-black hover:text-red-500 text-2xl font-bold">
×
</button>
</div>
<!-- Simple Content -->
<div class="mb-8">
<div id="tour-content" class="text-black text-lg leading-relaxed">
This is your first time here! Would you like a quick tour of the features?
</div>
</div>
<!-- Simple Buttons -->
<div class="flex gap-4 justify-center">
<button id="tour-skip-btn" class="bg-gray-300 hover:bg-gray-400 text-black px-6 py-3 rounded-lg text-lg font-semibold">
Skip Tour
</button>
<button id="tour-next-btn" class="bg-blue-500 hover:bg-blue-600 text-white px-6 py-3 rounded-lg text-lg font-semibold">
Start Tour
</button>
<button id="tour-prev-btn" class="hidden bg-gray-300 hover:bg-gray-400 text-black px-6 py-3 rounded-lg text-lg font-semibold">
Previous
</button>
</div>
</div>
</div>
</main>
</div>
<script src="dist/main.js?v=4" type="module"></script>
<script src="debug-settings-timer.js"></script>
<script>
// Initialize Lucide icons
lucide.createIcons();
</script>
</body>
</html>