""" Companion Dashboard Module - Begleiter-Modus UI. Das Dashboard zeigt: - Aktuelle Phase im Schuljahr - Priorisierte Vorschläge - Fortschritts-Anzeige - Kommende Termine """ def get_companion_css() -> str: """CSS für das Companion Dashboard.""" return """ /* Companion Dashboard Styles */ .companion-container { max-width: 900px; margin: 0 auto; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; } .companion-header { text-align: center; margin-bottom: 30px; } .companion-header h1 { font-size: 28px; color: #1a1a2e; margin-bottom: 8px; } .companion-header .phase-badge { display: inline-block; background: linear-gradient(135deg, #6C1B1B, #8B2525); color: white; padding: 6px 16px; border-radius: 20px; font-size: 14px; font-weight: 500; } /* Phase Indicator */ .phase-indicator { background: #f8f9fa; border-radius: 12px; padding: 20px; margin-bottom: 24px; } .phase-timeline { display: flex; justify-content: space-between; align-items: center; position: relative; padding: 0 10px; } .phase-timeline::before { content: ''; position: absolute; top: 15px; left: 30px; right: 30px; height: 3px; background: #e0e0e0; z-index: 0; } .phase-step { display: flex; flex-direction: column; align-items: center; z-index: 1; cursor: pointer; } .phase-dot { width: 30px; height: 30px; border-radius: 50%; background: #e0e0e0; display: flex; align-items: center; justify-content: center; margin-bottom: 8px; transition: all 0.3s ease; } .phase-dot.completed { background: #22c55e; } .phase-dot.current { background: #6C1B1B; box-shadow: 0 0 0 4px rgba(108, 27, 27, 0.2); } .phase-dot .material-icons { font-size: 16px; color: white; } .phase-label { font-size: 11px; color: #666; text-align: center; max-width: 70px; } .phase-label.current { color: #6C1B1B; font-weight: 600; } /* Suggestions List */ .suggestions-section { margin-bottom: 24px; } .section-title { font-size: 18px; font-weight: 600; color: #1a1a2e; margin-bottom: 16px; display: flex; align-items: center; gap: 8px; } .suggestion-card { display: flex; align-items: center; background: white; border: 1px solid #e5e7eb; border-radius: 12px; padding: 16px; margin-bottom: 12px; transition: all 0.2s ease; cursor: pointer; } .suggestion-card:hover { border-color: #6C1B1B; box-shadow: 0 4px 12px rgba(0,0,0,0.08); transform: translateY(-1px); } .priority-bar { width: 4px; height: 50px; border-radius: 2px; margin-right: 16px; flex-shrink: 0; } .priority-bar.urgent { background: #ef4444; } .priority-bar.high { background: #f97316; } .priority-bar.medium { background: #3b82f6; } .priority-bar.low { background: #9ca3af; } .suggestion-icon { width: 40px; height: 40px; border-radius: 10px; background: #f3f4f6; display: flex; align-items: center; justify-content: center; margin-right: 16px; flex-shrink: 0; } .suggestion-icon .material-icons { color: #6C1B1B; } .suggestion-content { flex: 1; } .suggestion-title { font-weight: 600; color: #1a1a2e; margin-bottom: 4px; } .suggestion-description { font-size: 13px; color: #6b7280; } .suggestion-action { color: #6C1B1B; font-weight: 600; font-size: 14px; display: flex; align-items: center; gap: 4px; } .suggestion-time { font-size: 12px; color: #9ca3af; margin-top: 4px; } /* Empty State */ .empty-state { text-align: center; padding: 40px 20px; background: #f0fdf4; border-radius: 12px; } .empty-state .material-icons { font-size: 48px; color: #22c55e; margin-bottom: 12px; } .empty-state h3 { color: #166534; margin-bottom: 8px; } .empty-state p { color: #6b7280; } /* Stats Cards */ .stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 12px; margin-bottom: 24px; } .stat-card { background: white; border: 1px solid #e5e7eb; border-radius: 10px; padding: 16px; text-align: center; } .stat-value { font-size: 28px; font-weight: 700; color: #6C1B1B; } .stat-label { font-size: 12px; color: #6b7280; margin-top: 4px; } /* Progress Card */ .progress-card { background: #eff6ff; border-radius: 12px; padding: 20px; margin-bottom: 24px; } .progress-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px; } .progress-title { font-weight: 600; color: #1e40af; } .progress-percentage { font-weight: 700; color: #1e40af; } .progress-bar-container { background: #dbeafe; border-radius: 10px; height: 10px; overflow: hidden; } .progress-bar-fill { background: linear-gradient(90deg, #3b82f6, #1d4ed8); height: 100%; border-radius: 10px; transition: width 0.5s ease; } .progress-milestones { margin-top: 12px; font-size: 13px; color: #4b5563; } /* Events Card */ .events-card { background: #fefce8; border-radius: 12px; padding: 20px; } .event-item { display: flex; align-items: center; padding: 12px 0; border-bottom: 1px solid #fef08a; } .event-item:last-child { border-bottom: none; } .event-icon { width: 36px; height: 36px; border-radius: 8px; background: white; display: flex; align-items: center; justify-content: center; margin-right: 12px; } .event-icon .material-icons { color: #ca8a04; font-size: 20px; } .event-info { flex: 1; } .event-title { font-weight: 500; color: #1a1a2e; } .event-date { font-size: 12px; color: #6b7280; } .event-badge { font-size: 12px; font-weight: 600; color: #ca8a04; background: white; padding: 4px 10px; border-radius: 12px; } /* Mode Toggle */ .mode-toggle { display: flex; background: #f3f4f6; border-radius: 8px; padding: 4px; margin-bottom: 20px; } .mode-btn { flex: 1; padding: 10px 16px; border: none; background: transparent; border-radius: 6px; font-weight: 500; cursor: pointer; transition: all 0.2s ease; } .mode-btn.active { background: #6C1B1B; color: white; } .mode-btn:not(.active):hover { background: #e5e7eb; } /* Responsive */ @media (max-width: 600px) { .phase-timeline { overflow-x: auto; padding-bottom: 10px; } .stats-grid { grid-template-columns: repeat(2, 1fr); } .suggestion-card { flex-wrap: wrap; } } """ def get_companion_html() -> str: """HTML Template für das Companion Dashboard.""" return """

Was ist jetzt wichtig?

Lädt...
0
Klassen
0
Schüler
0
Lerneinheiten
0
Noten
Fortschritt in dieser Phase 0%
0 von 0 Meilensteinen erreicht
lightbulb Empfohlene Aktionen
""" def get_companion_js() -> str: """JavaScript für das Companion Dashboard.""" return """ // Companion Dashboard JavaScript let companionData = null; let currentMode = 'companion'; async function loadCompanionDashboard() { try { const response = await fetch('/api/state/dashboard?teacher_id=demo-teacher'); companionData = await response.json(); renderDashboard(); } catch (error) { console.error('Error loading dashboard:', error); showError('Dashboard konnte nicht geladen werden'); } } function renderDashboard() { if (!companionData) return; // Phase Badge document.getElementById('phaseBadge').textContent = companionData.context.phase_display_name; // Phase Timeline renderPhaseTimeline(); // Stats document.getElementById('statClasses').textContent = companionData.stats.classes_count || 0; document.getElementById('statStudents').textContent = companionData.stats.students_count || 0; document.getElementById('statUnits').textContent = companionData.stats.learning_units_created || 0; document.getElementById('statGrades').textContent = companionData.stats.grades_entered || 0; // Progress const progress = companionData.progress; document.getElementById('progressPercent').textContent = Math.round(progress.percentage) + '%'; document.getElementById('progressBar').style.width = progress.percentage + '%'; document.getElementById('progressMilestones').textContent = `${progress.completed} von ${progress.total} Meilensteinen erreicht`; // Suggestions renderSuggestions(); // Events renderEvents(); } function renderPhaseTimeline() { const container = document.getElementById('phaseTimeline'); container.innerHTML = ''; companionData.phases.forEach(phase => { const step = document.createElement('div'); step.className = 'phase-step'; step.onclick = () => console.log('Phase clicked:', phase.phase); const dot = document.createElement('div'); dot.className = 'phase-dot'; if (phase.is_completed) { dot.classList.add('completed'); dot.innerHTML = 'check'; } else if (phase.is_current) { dot.classList.add('current'); dot.innerHTML = 'circle'; } const label = document.createElement('div'); label.className = 'phase-label'; if (phase.is_current) label.classList.add('current'); label.textContent = phase.short_name; step.appendChild(dot); step.appendChild(label); container.appendChild(step); }); } function renderSuggestions() { const container = document.getElementById('suggestionsList'); if (!companionData.suggestions || companionData.suggestions.length === 0) { container.innerHTML = `
check_circle

Alles erledigt!

Keine offenen Aufgaben. Gute Arbeit!

`; return; } container.innerHTML = companionData.suggestions.map(s => `
${s.icon}
${s.title}
${s.description}
schedule ca. ${s.estimated_time} Min.
Los arrow_forward
`).join(''); } function renderEvents() { const container = document.getElementById('eventsList'); const card = document.getElementById('eventsCard'); if (!companionData.upcoming_events || companionData.upcoming_events.length === 0) { card.style.display = 'none'; return; } card.style.display = 'block'; const getEventIcon = (type) => { const icons = { 'exam': 'quiz', 'parent_meeting': 'groups', 'deadline': 'alarm', 'default': 'event' }; return icons[type] || icons.default; }; container.innerHTML = companionData.upcoming_events.map(e => `
${getEventIcon(e.type)}
${e.title}
${formatDate(e.date)}
${e.in_days === 0 ? 'Heute' : `In ${e.in_days} Tagen`}
`).join(''); } function formatDate(isoString) { const date = new Date(isoString); return date.toLocaleDateString('de-DE', { weekday: 'short', day: 'numeric', month: 'short' }); } function navigateTo(target) { console.log('Navigate to:', target); // In echter App: window.location.href = target; // Oder: router.push(target); // Für Demo: Zeige Nachricht showToast(`Navigiere zu: ${target}`); } function setMode(mode) { currentMode = mode; document.getElementById('modeCompanion').classList.toggle('active', mode === 'companion'); document.getElementById('modeClassic').classList.toggle('active', mode === 'classic'); if (mode === 'classic') { showToast('Klassischer Modus - Navigation zu Dashboard'); // window.location.href = '/studio'; } } function showToast(message) { // Einfache Toast-Nachricht const toast = document.createElement('div'); toast.style.cssText = ` position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); background: #1a1a2e; color: white; padding: 12px 24px; border-radius: 8px; z-index: 1000; animation: fadeIn 0.3s ease; `; toast.textContent = message; document.body.appendChild(toast); setTimeout(() => { toast.style.opacity = '0'; setTimeout(() => toast.remove(), 300); }, 2000); } function showError(message) { document.getElementById('suggestionsList').innerHTML = `
error

Fehler

${message}

`; } // Milestone abschließen async function completeMilestone(milestone) { try { const response = await fetch('/api/state/milestone?teacher_id=demo-teacher', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ milestone }) }); const result = await response.json(); if (result.success) { showToast(`Meilenstein "${milestone}" abgeschlossen!`); if (result.new_phase) { showToast(`Neue Phase: ${result.new_phase}`); } loadCompanionDashboard(); // Reload } } catch (error) { console.error('Error completing milestone:', error); } } // Initial laden document.addEventListener('DOMContentLoaded', loadCompanionDashboard); """ class CompanionModule: """ Companion Dashboard Module für den Begleiter-Modus. Zeigt: - Aktuelle Phase im Schuljahr - Priorisierte Vorschläge - Fortschritts-Anzeige - Kommende Termine """ def __init__(self): self.name = "companion" self.display_name = "Begleiter" self.icon = "assistant" def get_css(self) -> str: return get_companion_css() def get_html(self) -> str: return get_companion_html() def get_js(self) -> str: return get_companion_js() def render(self) -> dict: """Rendert das komplette Modul.""" return { "css": self.get_css(), "html": self.get_html(), "js": self.get_js(), }