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
JavaScript
"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 `
<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 = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": ''',
};
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;