fix: Restore all files lost during destructive rebase
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>
This commit is contained in:
189
website/components/lehrer/LehrerLayout.tsx
Normal file
189
website/components/lehrer/LehrerLayout.tsx
Normal file
@@ -0,0 +1,189 @@
|
||||
'use client'
|
||||
|
||||
/**
|
||||
* LehrerLayout - Simplified layout for teacher section
|
||||
* Features: Sidebar navigation, simpler than AdminLayout
|
||||
*/
|
||||
|
||||
import Link from 'next/link'
|
||||
import { usePathname } from 'next/navigation'
|
||||
import { useState } from 'react'
|
||||
|
||||
interface NavItem {
|
||||
name: string
|
||||
href: string
|
||||
icon: React.ReactNode
|
||||
description?: string
|
||||
}
|
||||
|
||||
const navigation: NavItem[] = [
|
||||
{
|
||||
name: 'Dashboard',
|
||||
href: '/lehrer',
|
||||
icon: (
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={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" />
|
||||
</svg>
|
||||
),
|
||||
description: 'Uebersicht',
|
||||
},
|
||||
{
|
||||
name: 'Abitur-Archiv',
|
||||
href: '/lehrer/abitur-archiv',
|
||||
icon: (
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8m-9 4h4" />
|
||||
</svg>
|
||||
),
|
||||
description: 'Zentralabitur-Materialien durchsuchen',
|
||||
},
|
||||
{
|
||||
name: 'Klausur-Korrektur',
|
||||
href: '/lehrer/klausur-korrektur',
|
||||
icon: (
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
),
|
||||
description: 'KI-gestuetzte Abitur-Korrektur',
|
||||
},
|
||||
]
|
||||
|
||||
interface LehrerLayoutProps {
|
||||
children: React.ReactNode
|
||||
title?: string
|
||||
description?: string
|
||||
}
|
||||
|
||||
export default function LehrerLayout({ children, title, description }: LehrerLayoutProps) {
|
||||
const pathname = usePathname()
|
||||
const [sidebarCollapsed, setSidebarCollapsed] = useState(false)
|
||||
|
||||
const isActive = (href: string) => {
|
||||
if (href === '/lehrer') {
|
||||
return pathname === '/lehrer'
|
||||
}
|
||||
return pathname.startsWith(href)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-slate-50 flex">
|
||||
{/* Sidebar */}
|
||||
<aside
|
||||
className={`${
|
||||
sidebarCollapsed ? 'w-16' : 'w-64'
|
||||
} bg-gradient-to-b from-blue-900 to-blue-950 text-white flex flex-col transition-all duration-300 fixed h-full z-20`}
|
||||
>
|
||||
{/* Logo/Header */}
|
||||
<div className="h-16 flex items-center justify-between px-4 border-b border-blue-800">
|
||||
{!sidebarCollapsed && (
|
||||
<Link href="/lehrer" className="font-bold text-lg flex items-center gap-2">
|
||||
<span className="w-8 h-8 bg-white/20 rounded-lg flex items-center justify-center">
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" />
|
||||
</svg>
|
||||
</span>
|
||||
Lehrer-Portal
|
||||
</Link>
|
||||
)}
|
||||
<button
|
||||
onClick={() => setSidebarCollapsed(!sidebarCollapsed)}
|
||||
className="p-2 rounded-lg hover:bg-blue-800 transition-colors"
|
||||
title={sidebarCollapsed ? 'Sidebar erweitern' : 'Sidebar einklappen'}
|
||||
>
|
||||
<svg
|
||||
className={`w-5 h-5 transition-transform ${sidebarCollapsed ? 'rotate-180' : ''}`}
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M11 19l-7-7 7-7m8 14l-7-7 7-7" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Navigation */}
|
||||
<nav className="flex-1 py-4 overflow-y-auto">
|
||||
<ul className="space-y-1 px-2">
|
||||
{navigation.map((item) => (
|
||||
<li key={item.href}>
|
||||
<Link
|
||||
href={item.href}
|
||||
className={`flex items-center gap-3 px-3 py-2.5 rounded-lg transition-colors ${
|
||||
isActive(item.href)
|
||||
? 'bg-white/20 text-white'
|
||||
: 'text-blue-200 hover:bg-white/10 hover:text-white'
|
||||
}`}
|
||||
title={sidebarCollapsed ? item.name : undefined}
|
||||
>
|
||||
<span className="flex-shrink-0">{item.icon}</span>
|
||||
{!sidebarCollapsed && (
|
||||
<div>
|
||||
<span className="block truncate">{item.name}</span>
|
||||
{item.description && (
|
||||
<span className="text-xs text-blue-300 truncate block">{item.description}</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
{/* Footer */}
|
||||
<div className="p-4 border-t border-blue-800 space-y-2">
|
||||
<Link
|
||||
href="/admin"
|
||||
className={`flex items-center gap-3 px-3 py-2 rounded-lg text-blue-300 hover:text-white hover:bg-blue-800 transition-colors ${
|
||||
sidebarCollapsed ? 'justify-center' : ''
|
||||
}`}
|
||||
title="Zur Admin-Ansicht"
|
||||
>
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
</svg>
|
||||
{!sidebarCollapsed && <span>Admin-Ansicht</span>}
|
||||
</Link>
|
||||
<Link
|
||||
href="/"
|
||||
className={`flex items-center gap-3 px-3 py-2 rounded-lg text-blue-300 hover:text-white hover:bg-blue-800 transition-colors ${
|
||||
sidebarCollapsed ? 'justify-center' : ''
|
||||
}`}
|
||||
title="Zur Website"
|
||||
>
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
||||
</svg>
|
||||
{!sidebarCollapsed && <span>Zur Website</span>}
|
||||
</Link>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
{/* Main Content */}
|
||||
<div className={`flex-1 ${sidebarCollapsed ? 'ml-16' : 'ml-64'} transition-all duration-300`}>
|
||||
{/* Top Header */}
|
||||
<header className="h-16 bg-white border-b border-slate-200 flex items-center px-6 sticky top-0 z-10">
|
||||
<div className="flex-1">
|
||||
{title && <h1 className="text-xl font-semibold text-slate-900">{title}</h1>}
|
||||
{description && <p className="text-sm text-slate-500">{description}</p>}
|
||||
</div>
|
||||
|
||||
{/* User/Settings Area */}
|
||||
<div className="flex items-center gap-4">
|
||||
<span className="text-sm text-slate-500">Lehrer</span>
|
||||
<div className="w-8 h-8 rounded-full bg-blue-600 flex items-center justify-center text-white text-sm font-medium">
|
||||
L
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Page Content */}
|
||||
<main className="p-6">
|
||||
{children}
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user