""" BreakPilot Studio - Base Layout Module Enthaelt: - TopBar (Logo, Navigation, Sprachauswahl, Theme Toggle, Login) - Sidebar (Navigation zu Modulen) - Footer - CSS-Variablen und Basis-Styles - Theme Toggle (Dark/Light Mode) - Login/Auth Modal """ class BaseLayoutModule: """Basis-Layout fuer das BreakPilot Studio.""" @staticmethod def get_css() -> str: """CSS-Variablen und Basis-Styles.""" return """ /* ========================================== BREAKPILOT DESIGN SYSTEM - CSS VARIABLES ========================================== */ :root { /* Primary Colors - Weinrot */ --bp-primary: #6C1B1B; --bp-primary-hover: #8B2323; --bp-primary-soft: rgba(108, 27, 27, 0.1); /* Background */ --bp-bg: #0f172a; --bp-surface: #1e293b; --bp-surface-elevated: #334155; /* Borders */ --bp-border: #475569; --bp-border-subtle: rgba(255, 255, 255, 0.1); /* Accent Colors */ --bp-accent: #5ABF60; --bp-accent-soft: rgba(90, 191, 96, 0.15); /* Text */ --bp-text: #e5e7eb; --bp-text-muted: #9ca3af; /* Status Colors */ --bp-danger: #ef4444; --bp-warning: #f59e0b; --bp-success: #22c55e; --bp-info: #3b82f6; /* Gold Accent */ --bp-gold: #F1C40F; /* Sidebar */ --sidebar-width: 280px; } /* Light Theme */ [data-theme="light"] { --bp-bg: #f8fafc; --bp-surface: #ffffff; --bp-surface-elevated: #f1f5f9; --bp-border: #e2e8f0; --bp-border-subtle: rgba(0, 0, 0, 0.1); --bp-text: #1e293b; --bp-text-muted: #64748b; } /* ========================================== RESET & BASE STYLES ========================================== */ * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: 'Manrope', system-ui, -apple-system, sans-serif; background: var(--bp-bg); color: var(--bp-text); min-height: 100vh; line-height: 1.5; } /* ========================================== APP ROOT LAYOUT ========================================== */ .app-root { display: flex; min-height: 100vh; } /* ========================================== TOPBAR ========================================== */ .topbar { position: fixed; top: 0; left: 0; right: 0; height: 56px; background: var(--bp-surface); border-bottom: 1px solid var(--bp-border); display: flex; align-items: center; justify-content: space-between; padding: 0 20px; z-index: 100; } .brand { display: flex; align-items: center; gap: 12px; } .brand-logo { width: 36px; height: 36px; background: var(--bp-primary); border-radius: 8px; display: flex; align-items: center; justify-content: center; color: white; font-weight: 700; font-size: 14px; } .brand-text-main { font-size: 18px; font-weight: 700; color: var(--bp-primary); } .brand-text-sub { font-size: 11px; color: var(--bp-text-muted); } .topbar-actions { display: flex; align-items: center; gap: 12px; } /* Language Selector */ .language-selector { display: flex; align-items: center; gap: 8px; } .language-selector select { background: var(--bp-surface-elevated); border: 1px solid var(--bp-border); border-radius: 6px; padding: 6px 10px; color: var(--bp-text); font-size: 12px; cursor: pointer; } /* Theme Toggle */ .theme-toggle { display: flex; align-items: center; gap: 6px; padding: 4px 10px; border-radius: 999px; border: 1px solid var(--bp-border-subtle); background: var(--bp-surface-elevated); color: var(--bp-text-muted); cursor: pointer; font-size: 11px; transition: all 0.2s; } .theme-toggle:hover { border-color: var(--bp-primary); color: var(--bp-primary); } .theme-toggle-icon { font-size: 14px; } /* Buttons */ .btn { display: inline-flex; align-items: center; justify-content: center; gap: 6px; padding: 8px 16px; border-radius: 8px; font-size: 13px; font-weight: 500; cursor: pointer; transition: all 0.2s; border: none; } .btn-sm { padding: 6px 12px; font-size: 12px; } .btn-primary { background: var(--bp-primary); color: white; } .btn-primary:hover { background: var(--bp-primary-hover); } .btn-ghost { background: transparent; border: 1px solid var(--bp-border); color: var(--bp-text-muted); } .btn-ghost:hover { background: var(--bp-surface-elevated); color: var(--bp-text); } /* ========================================== SIDEBAR ========================================== */ .sidebar { position: fixed; top: 56px; left: 0; bottom: 0; width: var(--sidebar-width); background: var(--bp-surface); border-right: 1px solid var(--bp-border); padding: 16px; overflow-y: auto; overflow-x: hidden; z-index: 50; } .sidebar-section-title { font-size: 11px; font-weight: 600; text-transform: uppercase; color: var(--bp-text-muted); margin: 16px 0 8px 8px; letter-spacing: 0.5px; } .sidebar-menu { display: flex; flex-direction: column; gap: 4px; } .sidebar-item { display: flex; align-items: center; justify-content: space-between; padding: 10px 12px; border-radius: 8px; cursor: pointer; font-size: 13px; color: var(--bp-text-muted); transition: all 0.2s; } .sidebar-item:hover { background: var(--bp-surface-elevated); color: var(--bp-text); } .sidebar-item.active { background: var(--bp-primary-soft); color: var(--bp-primary); border: 1px solid var(--bp-primary); } [data-theme="light"] .sidebar-item.active { background: var(--bp-primary-soft); color: var(--bp-primary); } .sidebar-item-label { display: flex; align-items: center; gap: 10px; } .sidebar-item-icon { font-size: 16px; } .sidebar-item-badge { font-size: 10px; padding: 2px 8px; border-radius: 999px; background: var(--bp-accent-soft); color: var(--bp-accent); } /* ========================================== MAIN CONTENT AREA ========================================== */ .main-content { margin-left: var(--sidebar-width); margin-top: 56px; padding: 24px; flex: 1; min-height: calc(100vh - 56px); } /* Module Container - wird dynamisch befuellt */ .module-container { background: var(--bp-surface); border-radius: 12px; border: 1px solid var(--bp-border); min-height: calc(100vh - 104px); } /* ========================================== MODAL BASE STYLES ========================================== */ .modal-overlay { display: none; position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.7); z-index: 200; align-items: center; justify-content: center; } .modal-overlay.active { display: flex; } .modal-content { background: var(--bp-surface); border-radius: 16px; border: 1px solid var(--bp-border); max-width: 500px; width: 90%; max-height: 90vh; overflow-y: auto; padding: 24px; } .modal-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; } .modal-title { font-size: 18px; font-weight: 600; } .modal-close { background: none; border: none; font-size: 24px; cursor: pointer; color: var(--bp-text-muted); } .modal-close:hover { color: var(--bp-text); } /* ========================================== FORM ELEMENTS ========================================== */ .form-group { margin-bottom: 16px; } .form-label { display: block; font-size: 13px; font-weight: 500; margin-bottom: 6px; color: var(--bp-text); } .form-input { width: 100%; padding: 10px 12px; border-radius: 8px; border: 1px solid var(--bp-border); background: var(--bp-surface-elevated); color: var(--bp-text); font-size: 14px; } .form-input:focus { outline: none; border-color: var(--bp-primary); } .form-input::placeholder { color: var(--bp-text-muted); } /* ========================================== UTILITY CLASSES ========================================== */ .hidden { display: none !important; } .flex { display: flex; } .items-center { align-items: center; } .justify-between { justify-content: space-between; } .gap-2 { gap: 8px; } .gap-4 { gap: 16px; } .text-muted { color: var(--bp-text-muted); } .text-sm { font-size: 13px; } """ @staticmethod def get_html() -> str: """HTML-Struktur fuer TopBar und Sidebar.""" return """
BP
BreakPilot
Studio
🏠 Start
Studio
📝 Arbeitsblaetter
📋 Klausurkorrektur
NEU
✉ Elternkommunikation
Lernmaterial
🎓 Content Creator
NEU
📚 Content Feed
NEU
Kommunikation
🎥 Videokonferenz
💬 Messenger
Online
📫 Unified Inbox
NEU
Leistungsbewertung
👥 Klassen & Schueler
📄 Klausuren & Tests
NEU
📊 Notenspiegel
📖 Klassenbuch
🏆 Zeugnisse
Abitur
📝 Klausur-Korrektur
NEU
📚 Dokumente (Admin)
Admin
Verwaltung
⚙ Einstellungen
👥 Lehrer & Rollen
Admin
🛠 Developer Admin
DevOps

Modul wird geladen...

Anmelden

""" @staticmethod def get_js() -> str: """JavaScript fuer Base-Funktionalitaet.""" return """ // ========================================== // BREAKPILOT STUDIO - BASE MODULE // ========================================== console.log('BreakPilot Studio - Base Module loaded'); // Aktuelles Modul let currentModule = 'dashboard'; // ========================================== // THEME TOGGLE // ========================================== (function initTheme() { const savedTheme = localStorage.getItem('bp-theme') || 'dark'; document.documentElement.setAttribute('data-theme', savedTheme); })(); function initThemeToggle() { console.log('initThemeToggle called'); const toggle = document.getElementById('theme-toggle'); const icon = document.getElementById('theme-icon'); const label = document.getElementById('theme-label'); console.log('Theme toggle elements:', { toggle, icon, label }); if (!toggle) { console.error('Theme toggle button not found!'); return; } function updateUI(theme) { console.log('Updating theme UI to:', theme); if (theme === 'light') { icon.innerHTML = '☀'; // Sun label.textContent = 'Light'; } else { icon.innerHTML = '🌙'; // Moon label.textContent = 'Dark'; } } const current = document.documentElement.getAttribute('data-theme') || 'dark'; console.log('Current theme on init:', current); updateUI(current); toggle.addEventListener('click', function(e) { console.log('Theme toggle clicked!', e); const currentTheme = document.documentElement.getAttribute('data-theme') || 'dark'; const newTheme = currentTheme === 'dark' ? 'light' : 'dark'; console.log('Switching from', currentTheme, 'to', newTheme); document.documentElement.setAttribute('data-theme', newTheme); localStorage.setItem('bp-theme', newTheme); updateUI(newTheme); console.log('Theme switched to:', newTheme); }); console.log('Theme toggle initialized successfully'); } // ========================================== // MODULE LOADING // ========================================== // Liste aller Panel-IDs const PANEL_IDS = [ 'panel-dashboard', 'panel-jitsi', 'panel-letters', 'panel-worksheets', 'panel-correction', 'panel-messenger', 'panel-admin', 'panel-content-creator', 'panel-content-feed' ]; function hideAllPanels() { PANEL_IDS.forEach(id => { const panel = document.getElementById(id); if (panel) { panel.style.display = 'none'; } }); } function hideStudioSubMenu() { // Placeholder fuer SubMenu-Logik falls vorhanden const subMenu = document.getElementById('studio-submenu'); if (subMenu) { subMenu.style.display = 'none'; } } function showPanel(panelId) { hideAllPanels(); const panel = document.getElementById(panelId); if (panel) { panel.style.display = 'flex'; } } function loadModule(moduleName) { console.log('Loading module:', moduleName); // Hide all panels first hideAllPanels(); hideStudioSubMenu(); // Update Sidebar active state document.querySelectorAll('.sidebar-item').forEach(item => { item.classList.remove('active'); }); const activeItem = document.getElementById('sidebar-' + moduleName); if (activeItem) { activeItem.classList.add('active'); } currentModule = moduleName; // Show the corresponding panel const panelId = 'panel-' + moduleName; showPanel(panelId); // Trigger module-specific load function if exists // Handle special cases with hyphens (e.g., klausur-korrektur -> KlausurKorrektur) let normalizedName = moduleName; if (moduleName.includes('-')) { normalizedName = moduleName.split('-').map(part => part.charAt(0).toUpperCase() + part.slice(1)).join(''); } else { normalizedName = moduleName.charAt(0).toUpperCase() + moduleName.slice(1); } const loadFnName = 'load' + normalizedName + 'Module'; const loadFn = window[loadFnName]; if (typeof loadFn === 'function') { loadFn(); } else { // Check for show function (e.g., showJitsiPanel) const showFnName = 'show' + normalizedName + 'Panel'; const showFn = window[showFnName]; if (typeof showFn === 'function') { showFn(); } else { console.log('No init function found for module:', moduleName); } } } function fetchModuleContent(moduleName) { const container = document.getElementById('module-container'); container.innerHTML = '

Modul "' + moduleName + '" wird geladen...

'; // API call to get module HTML fetch('/api/modules/' + moduleName) .then(response => response.json()) .then(data => { if (data.html) { container.innerHTML = data.html; // Execute module JS if provided if (data.initFunction && window[data.initFunction]) { window[data.initFunction](); } } }) .catch(err => { console.error('Error loading module:', err); container.innerHTML = '

Fehler beim Laden des Moduls.

'; }); } // ========================================== // LOGIN MODAL // ========================================== function showLoginModal() { document.getElementById('login-modal').classList.add('active'); } function closeLoginModal() { document.getElementById('login-modal').classList.remove('active'); } function handleLogin(event) { event.preventDefault(); const email = document.getElementById('login-email').value; const password = document.getElementById('login-password').value; console.log('Login attempt:', email); // TODO: Implement actual login fetch('/api/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, password }) }) .then(response => response.json()) .then(data => { if (data.token) { localStorage.setItem('bp-token', data.token); closeLoginModal(); location.reload(); } else { alert('Login fehlgeschlagen: ' + (data.error || 'Unbekannter Fehler')); } }) .catch(err => { console.error('Login error:', err); alert('Login fehlgeschlagen. Bitte versuchen Sie es erneut.'); }); } // ========================================== // INITIALIZATION // ========================================== document.addEventListener('DOMContentLoaded', function() { console.log('BreakPilot Studio initializing...'); initThemeToggle(); // Login button const loginBtn = document.getElementById('btn-login'); if (loginBtn) { loginBtn.addEventListener('click', showLoginModal); } // Close modal on overlay click document.getElementById('login-modal')?.addEventListener('click', function(e) { if (e.target === this) { closeLoginModal(); } }); // Load default module (Dashboard) loadModule('dashboard'); console.log('BreakPilot Studio ready'); }); """ def get_base_layout() -> dict: """Gibt das komplette Base-Layout als Dictionary zurueck.""" module = BaseLayoutModule() return { 'css': module.get_css(), 'html': module.get_html(), 'js': module.get_js() }