A previous `git pull --rebase origin main` dropped 177 local commits,
losing 3400+ files across admin-v2, backend, studio-v2, website,
klausur-service, and many other services. The partial restore attempt
(660295e2) only recovered some files.
This commit restores all missing files from pre-rebase ref 98933f5e
while preserving post-rebase additions (night-scheduler, night-mode UI,
NightModeWidget dashboard integration).
Restored features include:
- AI Module Sidebar (FAB), OCR Labeling, OCR Compare
- GPU Dashboard, RAG Pipeline, Magic Help
- Klausur-Korrektur (8 files), Abitur-Archiv (5+ files)
- Companion, Zeugnisse-Crawler, Screen Flow
- Full backend, studio-v2, website, klausur-service
- All compliance SDKs, agent-core, voice-service
- CI/CD configs, documentation, scripts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
110 lines
4.5 KiB
Python
110 lines
4.5 KiB
Python
"""
|
||
School Management Module - Page Templates.
|
||
|
||
Enthält Template-Funktionen für Schulverwaltungsseiten.
|
||
"""
|
||
|
||
from .school_styles import get_school_base_styles
|
||
|
||
|
||
SCHOOL_NAV_ITEMS = [
|
||
{"id": "dashboard", "label": "Dashboard", "href": "/school"},
|
||
{"id": "attendance", "label": "Anwesenheit", "href": "/school/attendance"},
|
||
{"id": "grades", "label": "Noten", "href": "/school/grades"},
|
||
{"id": "timetable", "label": "Stundenplan", "href": "/school/timetable"},
|
||
{"id": "onboarding", "label": "Eltern", "href": "/school/onboarding"},
|
||
]
|
||
|
||
SCHOOL_ICONS = {
|
||
"home": '<svg class="nav-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"></path></svg>',
|
||
"users": '<svg class="nav-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"></path></svg>',
|
||
"calendar": '<svg class="nav-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path></svg>',
|
||
"chart": '<svg class="nav-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path></svg>',
|
||
"clock": '<svg class="nav-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>',
|
||
"external": '<svg class="nav-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"></path></svg>',
|
||
}
|
||
|
||
|
||
def render_school_sidebar(active_page: str = "dashboard") -> str:
|
||
"""Render the school sidebar navigation."""
|
||
icon_map = {
|
||
"dashboard": "home",
|
||
"attendance": "users",
|
||
"grades": "chart",
|
||
"timetable": "clock",
|
||
"onboarding": "calendar",
|
||
}
|
||
|
||
nav_html = ""
|
||
for item in SCHOOL_NAV_ITEMS:
|
||
active_class = "active" if item["id"] == active_page else ""
|
||
icon = SCHOOL_ICONS.get(icon_map.get(item["id"], "home"), "")
|
||
nav_html += f'''
|
||
<a href="{item['href']}" class="nav-item {active_class}">
|
||
{icon}
|
||
<span>{item['label']}</span>
|
||
</a>
|
||
'''
|
||
|
||
return f'''
|
||
<aside class="sidebar">
|
||
<div class="logo">
|
||
<div class="logo-icon">BP</div>
|
||
<span class="logo-text">Schulverwaltung</span>
|
||
</div>
|
||
|
||
<nav class="nav-section">
|
||
<div class="nav-section-title">Navigation</div>
|
||
{nav_html}
|
||
</nav>
|
||
|
||
<nav class="nav-section" style="margin-top: auto;">
|
||
<div class="nav-section-title">Links</div>
|
||
<a href="/studio" class="nav-item">
|
||
{SCHOOL_ICONS['external']}
|
||
<span>Zurück zum Studio</span>
|
||
</a>
|
||
<a href="/meetings" class="nav-item">
|
||
{SCHOOL_ICONS['users']}
|
||
<span>Meetings</span>
|
||
</a>
|
||
</nav>
|
||
</aside>
|
||
'''
|
||
|
||
|
||
def render_school_base_page(
|
||
title: str,
|
||
content: str,
|
||
active_page: str = "dashboard",
|
||
extra_styles: str = "",
|
||
extra_scripts: str = ""
|
||
) -> str:
|
||
"""Render the base page template for school pages."""
|
||
return f'''
|
||
<!DOCTYPE html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<title>BreakPilot – {title}</title>
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||
<style>
|
||
{get_school_base_styles()}
|
||
{extra_styles}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="app-container">
|
||
{render_school_sidebar(active_page)}
|
||
<main class="main-content">
|
||
{content}
|
||
</main>
|
||
</div>
|
||
<script>
|
||
{extra_scripts}
|
||
</script>
|
||
</body>
|
||
</html>
|
||
'''
|