This repository has been archived on 2026-02-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
breakpilot-pwa/backend/frontend/static/js/modules/lightbox.js
Benjamin Admin 21a844cb8a 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>
2026-02-09 09:51:32 +01:00

235 lines
5.4 KiB
JavaScript

/**
* BreakPilot Studio - Lightbox Module
*
* Vollbild-Bildvorschau und Modal-Funktionen:
* - Lightbox für Arbeitsblatt-Vorschauen
* - Keyboard-Navigation (Escape zum Schließen)
* - Click-outside zum Schließen
*
* Refactored: 2026-01-19
*/
// DOM-Referenzen
let lightboxEl = null;
let lightboxImg = null;
let lightboxCaption = null;
let lightboxClose = null;
// Callback für Close-Event
let onCloseCallback = null;
/**
* Initialisiert die Lightbox
* Sucht nach Standard-IDs oder erstellt das DOM
*/
export function initLightbox() {
lightboxEl = document.getElementById('lightbox');
lightboxImg = document.getElementById('lightbox-img');
lightboxCaption = document.getElementById('lightbox-caption');
lightboxClose = document.getElementById('lightbox-close');
// Falls keine Lightbox im DOM, erstelle sie
if (!lightboxEl) {
createLightboxDOM();
}
// Event-Listener
if (lightboxClose) {
lightboxClose.addEventListener('click', closeLightbox);
}
if (lightboxEl) {
lightboxEl.addEventListener('click', (ev) => {
// Schließen bei Klick auf Hintergrund
if (ev.target === lightboxEl) {
closeLightbox();
}
});
}
// Escape-Taste
document.addEventListener('keydown', (ev) => {
if (ev.key === 'Escape' && isLightboxOpen()) {
closeLightbox();
}
});
}
/**
* Erstellt das Lightbox-DOM dynamisch
*/
function createLightboxDOM() {
lightboxEl = document.createElement('div');
lightboxEl.id = 'lightbox';
lightboxEl.className = 'lightbox hidden';
lightboxEl.innerHTML = `
<div class="lightbox-content">
<button class="lightbox-close" id="lightbox-close">Schließen ✕</button>
<img id="lightbox-img" class="lightbox-img" src="" alt="Vorschau">
<div id="lightbox-caption" class="lightbox-caption"></div>
</div>
`;
document.body.appendChild(lightboxEl);
// Referenzen aktualisieren
lightboxImg = document.getElementById('lightbox-img');
lightboxCaption = document.getElementById('lightbox-caption');
lightboxClose = document.getElementById('lightbox-close');
// CSS injizieren falls nicht vorhanden
if (!document.getElementById('lightbox-styles')) {
const style = document.createElement('style');
style.id = 'lightbox-styles';
style.textContent = `
.lightbox {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.9);
z-index: 10000;
display: flex;
align-items: center;
justify-content: center;
opacity: 1;
transition: opacity 0.3s ease;
}
.lightbox.hidden {
display: none;
opacity: 0;
}
.lightbox-content {
position: relative;
max-width: 90%;
max-height: 90%;
}
.lightbox-img {
max-width: 100%;
max-height: 85vh;
object-fit: contain;
border-radius: 8px;
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.5);
}
.lightbox-close {
position: absolute;
top: -40px;
right: 0;
background: transparent;
border: none;
color: white;
font-size: 14px;
cursor: pointer;
padding: 8px 16px;
border-radius: 4px;
transition: background 0.2s;
}
.lightbox-close:hover {
background: rgba(255, 255, 255, 0.1);
}
.lightbox-caption {
color: white;
text-align: center;
margin-top: 12px;
font-size: 14px;
}
`;
document.head.appendChild(style);
}
}
/**
* Öffnet die Lightbox mit einem Bild
* @param {string} src - Bild-URL
* @param {string} [caption] - Optionale Bildunterschrift
*/
export function openLightbox(src, caption = '') {
if (!src) {
console.warn('openLightbox: No image source provided');
return;
}
// Lazy-Init falls noch nicht initialisiert
if (!lightboxEl) {
initLightbox();
}
if (lightboxImg) {
lightboxImg.src = src;
lightboxImg.alt = caption || 'Vorschau';
}
if (lightboxCaption) {
lightboxCaption.textContent = caption;
}
if (lightboxEl) {
lightboxEl.classList.remove('hidden');
// Body-Scroll verhindern
document.body.style.overflow = 'hidden';
}
}
/**
* Schließt die Lightbox
*/
export function closeLightbox() {
if (lightboxEl) {
lightboxEl.classList.add('hidden');
// Body-Scroll wiederherstellen
document.body.style.overflow = '';
}
if (lightboxImg) {
lightboxImg.src = '';
}
// Callback ausführen
if (onCloseCallback) {
onCloseCallback();
}
}
/**
* Prüft ob die Lightbox geöffnet ist
* @returns {boolean}
*/
export function isLightboxOpen() {
return lightboxEl && !lightboxEl.classList.contains('hidden');
}
/**
* Setzt einen Callback für das Close-Event
* @param {function} callback
*/
export function onClose(callback) {
onCloseCallback = callback;
}
/**
* Wechselt das Bild in der offenen Lightbox
* @param {string} src - Neue Bild-URL
* @param {string} [caption] - Neue Bildunterschrift
*/
export function changeLightboxImage(src, caption = '') {
if (lightboxImg) {
lightboxImg.src = src;
lightboxImg.alt = caption || 'Vorschau';
}
if (lightboxCaption) {
lightboxCaption.textContent = caption;
}
}
/**
* Setzt den Text des Close-Buttons
* @param {string} text - Der neue Text
*/
export function setCloseButtonText(text) {
if (lightboxClose) {
lightboxClose.textContent = text;
}
}