UNPKG

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.

114 lines (111 loc) • 3.88 kB
"use strict"; /** * @fileoverview Base View System - MVVM Architecture * @version 1.0.0 * @since 2025-08-04 * @module BaseView * @description Template rendering system with layout support and type safety * @contributors Claude Code Agent * @requirements REQ-UI-001 (MVVM Pattern), REQ-ARCH-002 (Clean Architecture) */ Object.defineProperty(exports, "__esModule", { value: true }); exports.BaseView = void 0; /** * Base HTML View Renderer */ class BaseView { /** * Render complete HTML page with layout */ static render(content, viewModel, config = {}) { const { includeNavigation = true, includeFooter = false, additionalCSS = [], additionalJS = [], } = config; return ` <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>${viewModel.title} - MCP Quiz Server</title> <link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet"> ${additionalCSS.map(css => `<link href="${css}" rel="stylesheet">`).join('\n ')} <script src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js" defer></script> ${additionalJS.map(js => `<script src="${js}"></script>`).join('\n ')} </head> <body class="bg-gray-50"> <div class="min-h-screen"> ${includeNavigation ? this.renderNavigation(viewModel.user) : ''} <main class="py-6"> ${content} </main> ${includeFooter ? this.renderFooter() : ''} </div> </body> </html>`; } /** * Render navigation component */ static renderNavigation(user) { var _a; if (!user) return ''; return ` <!-- Navigation --> <nav class="bg-white shadow-sm border-b"> <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> <div class="flex justify-between h-16"> <div class="flex items-center"> <h1 class="text-xl font-semibold text-gray-900">Quiz Dashboard</h1> </div> <div class="flex items-center space-x-4"> <span class="text-sm text-gray-700">Welcome, ${user.firstName || user.username}</span> <div class="flex items-center space-x-2"> <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800"> ${((_a = user.roles) === null || _a === void 0 ? void 0 : _a[0]) || 'User'} </span> <button onclick="logout()" class="text-sm text-red-600 hover:text-red-800">Logout</button> </div> </div> </div> </div> </nav>`; } /** * Render footer component */ static renderFooter() { return ` <!-- Footer --> <footer class="bg-white border-t mt-8"> <div class="max-w-7xl mx-auto py-4 px-4 sm:px-6 lg:px-8"> <p class="text-center text-sm text-gray-500"> © 2025 MCP Quiz Server. Built with Clean Architecture. </p> </div> </footer>`; } /** * Escape HTML content for security */ static escapeHtml(text) { const map = { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#039;', }; return text.replace(/[&<>"']/g, m => map[m]); } /** * Format date for display */ static formatDate(date) { return new Intl.DateTimeFormat('en-US', { year: 'numeric', month: 'long', day: 'numeric', }).format(date); } } exports.BaseView = BaseView;