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>
211 lines
5.0 KiB
HTML
211 lines
5.0 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Timeline - BreakPilot H5P</title>
|
|
<style>
|
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
background: #f5f5f5;
|
|
padding: 20px;
|
|
min-height: 100vh;
|
|
}
|
|
.container {
|
|
background: white;
|
|
border-radius: 8px;
|
|
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
|
padding: 30px;
|
|
max-width: 1000px;
|
|
margin: 0 auto;
|
|
}
|
|
h1 {
|
|
color: #333;
|
|
margin-bottom: 12px;
|
|
font-size: 32px;
|
|
}
|
|
.description {
|
|
color: #6b7280;
|
|
margin-bottom: 40px;
|
|
font-size: 16px;
|
|
line-height: 1.6;
|
|
}
|
|
.timeline {
|
|
position: relative;
|
|
padding: 20px 0;
|
|
}
|
|
.timeline::before {
|
|
content: '';
|
|
position: absolute;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
width: 4px;
|
|
height: 100%;
|
|
background: linear-gradient(180deg, #667eea 0%, #764ba2 100%);
|
|
border-radius: 2px;
|
|
}
|
|
.event {
|
|
position: relative;
|
|
margin-bottom: 60px;
|
|
display: flex;
|
|
align-items: center;
|
|
opacity: 0;
|
|
animation: fadeIn 0.6s forwards;
|
|
}
|
|
.event:nth-child(odd) {
|
|
flex-direction: row-reverse;
|
|
}
|
|
@keyframes fadeIn {
|
|
to { opacity: 1; }
|
|
}
|
|
.event-content {
|
|
width: calc(50% - 40px);
|
|
background: #f9fafb;
|
|
border: 2px solid #e5e7eb;
|
|
border-radius: 12px;
|
|
padding: 20px;
|
|
box-shadow: 0 4px 12px rgba(0,0,0,0.08);
|
|
transition: all 0.3s;
|
|
}
|
|
.event-content:hover {
|
|
transform: translateY(-4px);
|
|
box-shadow: 0 8px 20px rgba(0,0,0,0.12);
|
|
border-color: #667eea;
|
|
}
|
|
.event:nth-child(odd) .event-content {
|
|
margin-left: 40px;
|
|
}
|
|
.event:nth-child(even) .event-content {
|
|
margin-right: 40px;
|
|
}
|
|
.event-marker {
|
|
position: absolute;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
width: 24px;
|
|
height: 24px;
|
|
background: white;
|
|
border: 4px solid #667eea;
|
|
border-radius: 50%;
|
|
z-index: 10;
|
|
box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3);
|
|
}
|
|
.event-year {
|
|
position: absolute;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
top: -30px;
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
color: white;
|
|
padding: 6px 16px;
|
|
border-radius: 20px;
|
|
font-weight: 700;
|
|
font-size: 14px;
|
|
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
|
|
white-space: nowrap;
|
|
}
|
|
.event-title {
|
|
color: #1f2937;
|
|
font-size: 20px;
|
|
font-weight: 700;
|
|
margin-bottom: 8px;
|
|
}
|
|
.event-description {
|
|
color: #6b7280;
|
|
line-height: 1.6;
|
|
font-size: 15px;
|
|
}
|
|
.event-icon {
|
|
font-size: 32px;
|
|
margin-bottom: 12px;
|
|
display: block;
|
|
}
|
|
@media (max-width: 768px) {
|
|
.timeline::before {
|
|
left: 20px;
|
|
}
|
|
.event {
|
|
flex-direction: row !important;
|
|
}
|
|
.event-content {
|
|
width: calc(100% - 60px);
|
|
margin-left: 60px !important;
|
|
margin-right: 0 !important;
|
|
}
|
|
.event-marker {
|
|
left: 20px;
|
|
}
|
|
.event-year {
|
|
left: 20px;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<h1 id="title"></h1>
|
|
<p class="description" id="description"></p>
|
|
|
|
<div class="timeline" id="timeline"></div>
|
|
</div>
|
|
|
|
<script>
|
|
let data = null;
|
|
|
|
const icons = ['📍', '🎯', '⭐', '🏆', '💡', '🚀', '🎓', '🏛️', '🎨', '🌟'];
|
|
|
|
function loadContent() {
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
const dataParam = urlParams.get('data');
|
|
|
|
if (dataParam) {
|
|
try {
|
|
data = JSON.parse(decodeURIComponent(dataParam));
|
|
} catch (e) {
|
|
alert('Fehler beim Laden!');
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!data) {
|
|
alert('Keine Daten gefunden!');
|
|
return;
|
|
}
|
|
|
|
document.getElementById('title').textContent = data.title;
|
|
document.getElementById('description').textContent = data.description || '';
|
|
|
|
renderTimeline();
|
|
}
|
|
|
|
function renderTimeline() {
|
|
const timeline = document.getElementById('timeline');
|
|
timeline.innerHTML = '';
|
|
|
|
data.events.forEach((event, index) => {
|
|
const eventEl = document.createElement('div');
|
|
eventEl.className = 'event';
|
|
eventEl.style.animationDelay = `${index * 0.1}s`;
|
|
|
|
const icon = icons[index % icons.length];
|
|
|
|
eventEl.innerHTML = `
|
|
<div class="event-content">
|
|
<span class="event-icon">${icon}</span>
|
|
<div class="event-title">${event.title}</div>
|
|
<div class="event-description">${event.description || ''}</div>
|
|
</div>
|
|
<div class="event-marker"></div>
|
|
<div class="event-year">${event.year}</div>
|
|
`;
|
|
|
|
timeline.appendChild(eventEl);
|
|
});
|
|
}
|
|
|
|
loadContent();
|
|
</script>
|
|
</body>
|
|
</html>
|