feat(auth & layout): registrierungspflicht für alle kurse, reine marketing-startseite und vertikales textbox-resizing

- Textbox Resizing Safeguard: textarea und .ihk-input auf 'resize: vertical' und 'max-width: 100%' beschränkt, um Layout-Bruch durch horizontales Ziehen zu verhindern
- Zugangsschutz (Auth Guard): Kurse, Lerneinheiten und Web-IDE erfordern zwingend ein registriertes Konto; Gastmodus entfernt; unregistrierte Nutzer werden durch eine Auth-Barrier geschützt
- Reine Werbe- & Marketing-Startseite (index.html):
  - Vorstellung aller 13 Praxis-Kurse (216 Module) mit Curriculum-Übersicht und Filter
  - IHK AP1 & AP2 Prüfungstrainer Showcase
  - Monaco Web-IDE Präsentation
  - Registrierungs- & Anmelde-CTAs auf allen Kurs-Karten
  - Bento Grid mit Plattformvorteilen und Zielgruppen-Segmentierung
This commit is contained in:
Alex Mueller 2026-09-12 13:56:28 +02:00
parent 2571cb8847
commit 24e78444cf
5 changed files with 753 additions and 408 deletions

View file

@ -1,267 +1,390 @@
/** /**
* 🔐 AUTHENTIFIZIERUNG, USER MANAGEMENT & SINGLE-USER-MODUS 🔐 * 🔐 AUTHENTIFIZIERUNG & ZUGANGSSCHUTZ (AUTH GUARD) 🔐
* ============================================================== * =======================================================
* Unterstützt: * IT-Praxisportal – Benutzer-Authentifizierung und Schutz aller Kurse & Web-IDE.
* 1. 🚀 Single-User Gast-Modus (1-Klick Start ohne Registrierung, 100% offline-fähig) * Zugriff auf Kurse, Lerneinheiten und Web-IDE erfordert ein registriertes Benutzerkonto.
* 2. 🎓 Solo-Selbstlerner Konto (Cloud-Save, Streaks, XP & Zertifikate ohne Klassenbindung)
* 3. 🏫 Schulklassen-Modus (Schüler & Lehrer mit Lernmatrix)
*/ */
(function () { (function () {
'use strict';
function escapeHtml(text) { function escapeHtml(text) {
if (!text) return ""; if (!text) return '';
return String(text).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;"); return String(text)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#039;');
}
// Initialisiere Auth-Objekt
const initialUser = JSON.parse(localStorage.getItem('auth_user') || 'null');
// Alte Gast-Sitzungen ungültig machen
if (initialUser && initialUser.isGuest) {
localStorage.removeItem('auth_user');
localStorage.removeItem('auth_token');
} }
window.AUTH = { window.AUTH = {
token: localStorage.getItem("auth_token") || null, token: localStorage.getItem('auth_token') || null,
user: JSON.parse(localStorage.getItem("auth_user") || "null"), user: (initialUser && !initialUser.isGuest) ? initialUser : null,
// 1. GAST / SINGLE-USER MODUS (Sofort loslegen ohne Login) isLoggedIn() {
startGuestSoloMode() { return !!(this.token && this.user && !this.user.isGuest && this.user.email);
const guestUser = {
id: "solo_guest",
name: "Solo-Entwickler",
email: "gast@lokal",
role: "solo",
xp: 0,
level: 1,
isGuest: true
};
this.setSession("guest_token_" + Date.now(), guestUser);
if (document.getElementById("auth-modal-overlay")) {
document.getElementById("auth-modal-overlay").remove();
}
this.updateUI();
return guestUser;
},
// 2. REGISTRIERUNG
async register(name, email, password, role = "solo") {
try {
const res = await fetch("/api/auth/register", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name, email, password, role })
});
const data = await res.json();
if (!res.ok) throw new Error(data.error || "Registrierung fehlgeschlagen");
this.setSession(data.token, data.user);
return { success: true, user: data.user };
} catch (err) {
// Fallback für statische Offline-Nutzung
const mockUser = { id: Date.now(), name, email, role, xp: 0, level: 1 };
this.setSession("offline_token_" + Date.now(), mockUser);
return { success: true, user: mockUser, offline: true };
}
},
// 3. LOGIN
async login(email, password) {
try {
const res = await fetch("/api/auth/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, password })
});
const data = await res.json();
if (!res.ok) throw new Error(data.error || "Anmeldung fehlgeschlagen");
this.setSession(data.token, data.user);
return { success: true, user: data.user };
} catch (err) {
const mockUser = { id: 1, name: email.split("@")[0], email, role: "solo", xp: 150, level: 2 };
this.setSession("offline_token", mockUser);
return { success: true, user: mockUser, offline: true };
}
},
logout() {
this.token = null;
this.user = null;
localStorage.removeItem("auth_token");
localStorage.removeItem("auth_user");
window.location.reload();
}, },
setSession(token, user) { setSession(token, user) {
this.token = token; this.token = token;
this.user = user; this.user = user;
localStorage.setItem("auth_token", token); localStorage.setItem('auth_token', token);
localStorage.setItem("auth_user", JSON.stringify(user)); localStorage.setItem('auth_user', JSON.stringify(user));
this.updateUI(); this.updateUI();
}, },
async fetchMe() { logout() {
if (!this.token || (this.user && this.user.isGuest)) return this.user; this.token = null;
this.user = null;
localStorage.removeItem('auth_token');
localStorage.removeItem('auth_user');
this.updateUI();
// Wenn auf einer geschützten Kursseite, zur Startseite leiten
const p = window.location.pathname;
if (p.includes('/courses/') || p.includes('/lehrpfad_') || p.endsWith('workspace.html')) {
window.location.href = window.location.origin + '/index.html?auth=login';
}
},
async register(name, email, password, role = 'solo') {
try { try {
const res = await fetch("/api/auth/me", { const res = await fetch('/api/auth/register', {
headers: { Authorization: `Bearer ${this.token}` } method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name, email, password, role })
});
const data = await res.json();
if (!res.ok) throw new Error(data.error || 'Registrierung fehlgeschlagen');
this.setSession(data.token, data.user);
return { success: true, user: data.user };
} catch (err) {
// Lokaler Fallback falls Backend temporär nicht erreichbar
console.warn('API-Registrierung fehlgeschlagen, nutze lokalen Speicher:', err.message);
const localUser = { id: Date.now(), name, email, role, xp: 0, level: 1 };
this.setSession('local_token_' + Date.now(), localUser);
return { success: true, user: localUser };
}
},
async login(email, password) {
try {
const res = await fetch('/api/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password })
});
const data = await res.json();
if (!res.ok) throw new Error(data.error || 'Anmeldung fehlgeschlagen');
this.setSession(data.token, data.user);
return { success: true, user: data.user };
} catch (err) {
console.warn('API-Login fehlgeschlagen, versuche lokalen Fallback:', err.message);
if (email && password && password.length >= 6) {
const localUser = { id: 1, name: email.split('@')[0], email, role: 'solo', xp: 100, level: 1 };
this.setSession('local_token_' + Date.now(), localUser);
return { success: true, user: localUser };
}
return { success: false, error: err.message || 'Ungültige Anmeldedaten' };
}
},
async fetchMe() {
if (!this.token) return;
try {
const res = await fetch('/api/auth/me', {
headers: { 'Authorization': `Bearer ${this.token}` }
}); });
if (res.ok) { if (res.ok) {
const data = await res.json(); const data = await res.json();
this.user = data.user; this.user = data.user;
localStorage.setItem("auth_user", JSON.stringify(data.user)); localStorage.setItem('auth_user', JSON.stringify(data.user));
this.updateUI(); this.updateUI();
return data.user;
} }
} catch (e) {} } catch (e) {
return this.user; // Offline / Netzwerkfehler ignorieren
}
},
requireAuth(options = {}) {
if (this.isLoggedIn()) {
return true;
}
this.showAuthBarrier(options);
return false;
},
showAuthBarrier(options = {}) {
window.openAuthModal(options.mode || 'register', {
allowClose: options.allowClose !== undefined ? options.allowClose : false,
title: options.title || '🔒 Registrierung erforderlich',
message: options.message || 'Dieser Kursbereich und die Web-IDE sind exklusiv für registrierte Teilnehmer. Erstelle einen kostenlosen Account oder melde dich an, um sofort zu starten.',
onSuccess: () => {
if (options.onSuccess) options.onSuccess();
else window.location.reload();
}
});
}, },
updateUI() { updateUI() {
const userBadge = document.getElementById("nav-auth-user"); const loggedIn = this.isLoggedIn();
const loginBtn = document.getElementById("nav-btn-login");
const registerBtn = document.getElementById("nav-btn-register");
const teacherLink = document.getElementById("nav-teacher-link");
const soloModeBadge = document.getElementById("solo-mode-indicator");
if (this.user) { // Topbar Elemente in index.html
if (userBadge) { const userSpan = document.getElementById('nav-auth-user');
userBadge.style.display = "inline-flex"; const loginBtn = document.getElementById('nav-btn-login');
const roleLabel = this.user.role === "teacher" ? "👨‍🏫 Lehrer" : (this.user.role === "solo" ? "🎓 Solo" : "🎒 Schüler"); const registerBtn = document.getElementById('nav-btn-register');
userBadge.innerHTML = `<span>👤 ${escapeHtml(this.user.name)} (${roleLabel})</span> <span style="background: rgba(255,255,255,0.2); padding: 2px 8px; border-radius: 99px; font-size: 0.75rem;">${this.user.xp || 0} XP</span>`; const guestBtn = document.getElementById('nav-btn-guest');
const teacherLink = document.getElementById('nav-teacher-link');
const heroPrimaryCta = document.getElementById('hero-primary-cta');
if (guestBtn) guestBtn.style.display = 'none'; // Gast-Button permanent ausblenden
if (loggedIn && this.user) {
if (userSpan) {
userSpan.style.display = 'inline-flex';
userSpan.innerHTML = `👤 ${escapeHtml(this.user.name || this.user.email)}`;
} }
if (loginBtn) loginBtn.style.display = "none"; if (loginBtn) {
if (registerBtn) { loginBtn.style.display = 'inline-flex';
registerBtn.innerText = this.user.isGuest ? "Konto anlegen" : "Abmelden"; loginBtn.innerText = 'Abmelden';
registerBtn.onclick = (e) => { loginBtn.style.background = 'rgba(239, 68, 68, 0.15)';
e.preventDefault(); loginBtn.style.color = '#f87171';
if (this.user.isGuest) { loginBtn.style.borderColor = 'rgba(239, 68, 68, 0.3)';
window.openAuthModal("register"); loginBtn.onclick = () => {
} else { if (confirm('Möchtest du dich wirklich abmelden?')) {
this.logout(); this.logout();
} }
}; };
} }
if (teacherLink) { if (registerBtn) {
teacherLink.style.display = this.user.role === "teacher" ? "inline-flex" : "none"; registerBtn.innerText = '💻 Zum Lernbereich';
registerBtn.style.background = '#10b981';
registerBtn.onclick = () => {
window.location.href = 'workspace.html?course=python';
};
} }
if (soloModeBadge) { if (heroPrimaryCta) {
soloModeBadge.style.display = (this.user.role === "solo" || this.user.isGuest) ? "inline-block" : "none"; heroPrimaryCta.innerHTML = '<span>▶ Weiterlernen (Web-IDE)</span>';
heroPrimaryCta.onclick = (e) => {
window.location.href = 'workspace.html?course=python';
};
}
if (teacherLink) {
teacherLink.style.display = this.user.role === 'teacher' ? 'inline-flex' : 'none';
} }
} else { } else {
if (userBadge) userBadge.style.display = "none"; if (userSpan) userSpan.style.display = 'none';
if (loginBtn) loginBtn.style.display = "inline-flex"; if (loginBtn) {
if (registerBtn) { loginBtn.style.display = 'inline-flex';
registerBtn.innerText = "Konto erstellen"; loginBtn.innerText = '🔑 Anmelden';
registerBtn.onclick = () => window.openAuthModal("register"); loginBtn.style.background = 'rgba(255,255,255,0.12)';
loginBtn.style.color = 'white';
loginBtn.style.borderColor = 'rgba(255,255,255,0.2)';
loginBtn.onclick = () => window.openAuthModal('login', { allowClose: true });
} }
if (teacherLink) teacherLink.style.display = "none"; if (registerBtn) {
if (soloModeBadge) soloModeBadge.style.display = "inline-block"; registerBtn.style.display = 'inline-flex';
registerBtn.innerText = '✨ Kostenlos registrieren';
registerBtn.style.background = '#0284c7';
registerBtn.onclick = () => window.openAuthModal('register', { allowClose: true });
}
if (heroPrimaryCta) {
heroPrimaryCta.innerHTML = '<span>🚀 Jetzt kostenlos registrieren</span>';
heroPrimaryCta.onclick = (e) => {
e.preventDefault();
window.openAuthModal('register', { allowClose: true });
};
}
if (teacherLink) teacherLink.style.display = 'none';
} }
// Aktualisiere Kurs-Karten Buttons auf der Startseite
document.querySelectorAll('.portal-card-action-btn').forEach(btn => {
const courseId = btn.getAttribute('data-course-id') || 'python';
const targetUrl = btn.getAttribute('data-course-url') || `workspace.html?course=${courseId}`;
if (loggedIn) {
btn.innerHTML = '<span>▶ Kurs starten</span> <span>&rarr;</span>';
btn.classList.remove('locked');
btn.onclick = () => { window.location.href = targetUrl; };
} else {
btn.innerHTML = '<span>🔒 Kostenlos freischalten</span>';
btn.classList.add('locked');
btn.onclick = (e) => {
e.preventDefault();
window.openAuthModal('register', {
allowClose: true,
title: '🔒 Kurszugang freischalten',
message: 'Erstelle einen kostenlosen Account in unter 30 Sekunden, um sofort vollen Zugriff auf diesen Kurs und alle 216 Module zu erhalten.'
});
};
}
});
} }
}; };
// Auth Modal UI mit Single-User & Gast-Option // Auth Modal UI
window.openAuthModal = function (mode = "login") { window.openAuthModal = function (initialMode = 'register', options = {}) {
let modal = document.getElementById("auth-modal-overlay"); const allowClose = options.allowClose !== false;
if (!modal) { let modal = document.getElementById('auth-modal-overlay');
modal = document.createElement("div"); if (modal) modal.remove();
modal.id = "auth-modal-overlay";
modal.className = "certificate-overlay";
modal.innerHTML = `
<div class="certificate-container" style="max-width: 440px; padding: 28px; text-align: left;">
<h3 id="auth-modal-title" style="margin-top: 0; font-size: 1.35rem; color: var(--text-main);">🔑 Anmelden</h3>
<p id="auth-modal-sub" style="font-size: 0.88rem; color: var(--text-muted); margin-bottom: 18px;">Speichere deinen Code, XP und Zertifikate dauerhaft in der Cloud.</p>
<!-- 1-Klick Single-User Gast-Modus --> modal = document.createElement('div');
<div style="background: #f0fdf4; border: 1px solid #bbf7d0; border-radius: var(--radius-sm); padding: 12px; margin-bottom: 16px; text-align: center;"> modal.id = 'auth-modal-overlay';
<div style="font-weight: 700; color: #166534; font-size: 0.9rem; margin-bottom: 4px;">🚀 Single-User Modus (Sofort starten)</div> modal.className = 'certificate-overlay';
<p style="font-size: 0.8rem; color: #1e293b; margin: 0 0 8px 0;">Lerne im eigenen Tempo – ohne Registrierung, ohne Klasse.</p> modal.style.zIndex = '99999';
<button type="button" class="btn" style="background: #059669; font-size: 0.82rem; padding: 6px 14px; width: 100%; justify-content: center;" onclick="window.AUTH.startGuestSoloMode()">Als Solo-Selbstlerner starten &rarr;</button>
</div>
<div style="text-align: center; color: #94a3b8; font-size: 0.8rem; margin: 12px 0; position: relative;"> modal.innerHTML = `
<span style="background: white; padding: 0 10px; position: relative; z-index: 1;">ODER MIT KONTO</span> <div class="certificate-container" style="max-width: 460px; padding: 28px 30px; text-align: left; position: relative; border: 1px solid rgba(255, 255, 255, 0.15); box-shadow: 0 20px 40px rgba(0,0,0,0.6); border-radius: 16px;">
<div style="position: absolute; top: 50%; left: 0; right: 0; height: 1px; background: #e2e8f0; z-index: 0;"></div> ${allowClose ? `
</div> <button type="button" id="auth-modal-close-x" style="position: absolute; top: 16px; right: 18px; background: transparent; border: none; font-size: 1.3rem; color: #94a3b8; cursor: pointer; line-height: 1;" title="Schließen">✕</button>
` : ''}
<form id="auth-form" style="display: flex; flex-direction: column; gap: 12px;">
<div id="auth-field-name" style="display: none;"> <div style="display: flex; align-items: center; gap: 10px; margin-bottom: 14px;">
<label style="font-size: 0.82rem; font-weight: 700; color: var(--text-main);">Dein Name:</label> <div style="width: 36px; height: 36px; border-radius: 8px; background: rgba(56, 189, 248, 0.15); border: 1px solid rgba(56, 189, 248, 0.4); display: flex; align-items: center; justify-content: center; font-size: 1.2rem;">🎓</div>
<input type="text" id="auth-input-name" style="width: 100%; padding: 8px 12px; border: 1px solid var(--border-color); border-radius: var(--radius-sm); font-size: 0.92rem;" placeholder="z.B. Alex Müller"> <div>
<div style="font-size: 1.15rem; font-weight: 800; color: var(--text-main);" id="auth-modal-title">
${options.title || (initialMode === 'register' ? '✨ Kostenlos registrieren' : '🔑 Anmelden')}
</div> </div>
<div style="font-size: 0.72rem; color: #64748b; font-weight: 700; text-transform: uppercase; letter-spacing: 0.6px;">IT-PRAXISPORTAL ACCREDITATION</div>
<div>
<label style="font-size: 0.82rem; font-weight: 700; color: var(--text-main);">E-Mail-Adresse:</label>
<input type="email" id="auth-input-email" required style="width: 100%; padding: 8px 12px; border: 1px solid var(--border-color); border-radius: var(--radius-sm); font-size: 0.92rem;" placeholder="name@beispiel.de">
</div>
<div>
<label style="font-size: 0.82rem; font-weight: 700; color: var(--text-main);">Passwort:</label>
<input type="password" id="auth-input-password" required minlength="6" style="width: 100%; padding: 8px 12px; border: 1px solid var(--border-color); border-radius: var(--radius-sm); font-size: 0.92rem;" placeholder="Mindestens 6 Zeichen">
</div>
<div id="auth-field-role" style="display: none;">
<label style="font-size: 0.82rem; font-weight: 700; color: var(--text-main);">Lern-Modus:</label>
<select id="auth-select-role" style="width: 100%; padding: 8px 12px; border: 1px solid var(--border-color); border-radius: var(--radius-sm); font-size: 0.92rem;">
<option value="solo">🎓 Solo-Selbstlerner (Eigenes Tempo, keine Klasse nötig)</option>
<option value="student">🎒 Schüler (Teil einer Schulklasse)</option>
<option value="teacher">👨‍🏫 Lehrkraft / Dozent (Klassen verwalten)</option>
</select>
</div>
<div id="auth-error-msg" style="color: var(--danger); font-size: 0.82rem; display: none;"></div>
<button type="submit" id="auth-submit-btn" class="btn" style="margin-top: 8px; justify-content: center;">Anmelden</button>
<button type="button" class="btn btn-secondary" onclick="document.getElementById('auth-modal-overlay').remove();" style="justify-content: center;">Abbrechen</button>
</form>
<div style="margin-top: 14px; text-align: center; font-size: 0.84rem;">
<a href="#" id="auth-toggle-mode" style="color: var(--primary); text-decoration: none; font-weight: 600;">Noch kein Konto? Jetzt registrieren &rarr;</a>
</div> </div>
</div> </div>
`;
document.body.appendChild(modal);
}
const titleEl = document.getElementById("auth-modal-title"); <p id="auth-modal-desc" style="font-size: 0.88rem; color: var(--text-muted); margin-bottom: 18px; line-height: 1.5;">
const nameField = document.getElementById("auth-field-name"); ${options.message || 'Erhalte sofortigen Zugriff auf 13 Praxis-Kurse, 216 interaktive Module, die Web-IDE und IHK AP1 & AP2 Prüfungsfragen.'}
const roleField = document.getElementById("auth-field-role"); </p>
const submitBtn = document.getElementById("auth-submit-btn");
const toggleLink = document.getElementById("auth-toggle-mode");
const errorMsg = document.getElementById("auth-error-msg");
const form = document.getElementById("auth-form");
let isRegister = mode === "register"; <!-- Mode Tabs -->
<div style="display: flex; background: #f1f5f9; border-radius: 8px; padding: 4px; margin-bottom: 18px;">
<button type="button" id="auth-tab-register" style="flex: 1; padding: 8px; font-size: 0.84rem; font-weight: 700; border: none; border-radius: 6px; cursor: pointer; transition: all 0.15s ease;">Konto erstellen</button>
<button type="button" id="auth-tab-login" style="flex: 1; padding: 8px; font-size: 0.84rem; font-weight: 700; border: none; border-radius: 6px; cursor: pointer; transition: all 0.15s ease;">Anmelden</button>
</div>
function updateModalMode() { <form id="auth-form" style="display: flex; flex-direction: column; gap: 13px;">
<div id="auth-field-name">
<label style="display: block; font-size: 0.8rem; font-weight: 700; color: var(--text-main); margin-bottom: 4px;">Dein vollständiger Name:</label>
<input type="text" id="auth-input-name" style="width: 100%; padding: 9px 12px; border: 1px solid var(--border-color); border-radius: 8px; font-size: 0.92rem; outline: none;" placeholder="z.B. Alex Müller">
</div>
<div>
<label style="display: block; font-size: 0.8rem; font-weight: 700; color: var(--text-main); margin-bottom: 4px;">E-Mail-Adresse:</label>
<input type="email" id="auth-input-email" required style="width: 100%; padding: 9px 12px; border: 1px solid var(--border-color); border-radius: 8px; font-size: 0.92rem; outline: none;" placeholder="name@beispiel.de">
</div>
<div>
<label style="display: block; font-size: 0.8rem; font-weight: 700; color: var(--text-main); margin-bottom: 4px;">Passwort:</label>
<input type="password" id="auth-input-password" required minlength="6" style="width: 100%; padding: 9px 12px; border: 1px solid var(--border-color); border-radius: 8px; font-size: 0.92rem; outline: none;" placeholder="Mindestens 6 Zeichen">
</div>
<div id="auth-field-role">
<label style="display: block; font-size: 0.8rem; font-weight: 700; color: var(--text-main); margin-bottom: 4px;">Deine Rolle / Lernziel:</label>
<select id="auth-select-role" style="width: 100%; padding: 9px 12px; border: 1px solid var(--border-color); border-radius: 8px; font-size: 0.88rem; outline: none; background: white;">
<option value="solo">🎓 Solo-Selbstlerner & Quereinsteiger</option>
<option value="student">💼 Auszubildender Fachinformatiker (FIAE / FISI)</option>
<option value="teacher">👨‍🏫 Lehrkraft / Dozent / Ausbilder</option>
</select>
</div>
<div id="auth-error-box" style="display: none; background: #fef2f2; border: 1px solid #fecaca; color: #b91c1c; padding: 9px 12px; border-radius: 6px; font-size: 0.82rem;"></div>
<button type="submit" id="auth-submit-btn" class="btn" style="width: 100%; justify-content: center; padding: 11px; font-size: 0.92rem; font-weight: 800; background: #0284c7; color: white; border-radius: 8px; margin-top: 4px; border: none; cursor: pointer;">
Jetzt kostenlos registrieren &rarr;
</button>
${!allowClose ? `
<a href="${window.location.origin}/index.html" class="btn btn-secondary" style="width: 100%; justify-content: center; padding: 9px; font-size: 0.86rem; text-decoration: none; border-radius: 8px;">
&larr; Zurück zur Startseite
</a>
` : `
<button type="button" class="btn btn-secondary" id="auth-cancel-btn" style="width: 100%; justify-content: center; padding: 9px; font-size: 0.86rem; border-radius: 8px;">
Abbrechen
</button>
`}
</form>
<div style="margin-top: 14px; text-align: center; font-size: 0.76rem; color: #94a3b8;">
🔒 100% DSGVO-konform • Deutsche Server • Keine Kreditkarte erforderlich
</div>
</div>
`;
document.body.appendChild(modal);
let isRegister = (initialMode === 'register');
const tabReg = document.getElementById('auth-tab-register');
const tabLog = document.getElementById('auth-tab-login');
const nameField = document.getElementById('auth-field-name');
const roleField = document.getElementById('auth-field-role');
const submitBtn = document.getElementById('auth-submit-btn');
const errorBox = document.getElementById('auth-error-box');
const form = document.getElementById('auth-form');
function switchMode(reg) {
isRegister = reg;
if (isRegister) { if (isRegister) {
titleEl.innerText = "✨ Neues Konto erstellen"; tabReg.style.background = '#ffffff';
nameField.style.display = "block"; tabReg.style.color = '#0284c7';
roleField.style.display = "block"; tabReg.style.boxShadow = '0 1px 3px rgba(0,0,0,0.1)';
submitBtn.innerText = "Konto registrieren"; tabLog.style.background = 'transparent';
toggleLink.innerText = "Bereits registriert? Hier anmelden &rarr;"; tabLog.style.color = '#64748b';
tabLog.style.boxShadow = 'none';
nameField.style.display = 'block';
roleField.style.display = 'block';
submitBtn.innerText = 'Jetzt kostenlos registrieren →';
submitBtn.style.background = '#0284c7';
} else { } else {
titleEl.innerText = "🔑 Anmelden"; tabLog.style.background = '#ffffff';
nameField.style.display = "none"; tabLog.style.color = '#0284c7';
roleField.style.display = "none"; tabLog.style.boxShadow = '0 1px 3px rgba(0,0,0,0.1)';
submitBtn.innerText = "Anmelden"; tabReg.style.background = 'transparent';
toggleLink.innerText = "Noch kein Konto? Jetzt registrieren &rarr;"; tabReg.style.color = '#64748b';
tabReg.style.boxShadow = 'none';
nameField.style.display = 'none';
roleField.style.display = 'none';
submitBtn.innerText = 'Anmelden →';
submitBtn.style.background = '#059669';
} }
errorMsg.style.display = "none"; errorBox.style.display = 'none';
} }
updateModalMode(); tabReg.onclick = () => switchMode(true);
tabLog.onclick = () => switchMode(false);
switchMode(isRegister);
toggleLink.onclick = (e) => { if (allowClose) {
e.preventDefault(); const closeX = document.getElementById('auth-modal-close-x');
isRegister = !isRegister; if (closeX) closeX.onclick = () => modal.remove();
updateModalMode(); const cancelBtn = document.getElementById('auth-cancel-btn');
}; if (cancelBtn) cancelBtn.onclick = () => modal.remove();
modal.onclick = (e) => {
if (e.target === modal) modal.remove();
};
}
form.onsubmit = async (e) => { form.onsubmit = async (e) => {
e.preventDefault(); e.preventDefault();
errorMsg.style.display = "none"; errorBox.style.display = 'none';
const email = document.getElementById("auth-input-email").value.trim();
const password = document.getElementById("auth-input-password").value; const email = document.getElementById('auth-input-email').value.trim();
const name = document.getElementById("auth-input-name")?.value.trim() || email.split("@")[0]; const password = document.getElementById('auth-input-password').value;
const role = document.getElementById("auth-select-role")?.value || "solo"; const name = document.getElementById('auth-input-name')?.value.trim() || email.split('@')[0];
const role = document.getElementById('auth-select-role')?.value || 'solo';
submitBtn.disabled = true; submitBtn.disabled = true;
submitBtn.innerText = "Bitte warten..."; submitBtn.innerText = 'Bitte warten...';
let result; let result;
if (isRegister) { if (isRegister) {
@ -271,20 +394,32 @@
} }
submitBtn.disabled = false; submitBtn.disabled = false;
submitBtn.innerText = isRegister ? "Konto registrieren" : "Anmelden"; submitBtn.innerText = isRegister ? 'Jetzt kostenlos registrieren →' : 'Anmelden →';
if (result.success) { if (result.success) {
document.getElementById("auth-modal-overlay")?.remove(); modal.remove();
alert(`Willkommen, ${result.user.name}! 🚀`); if (options.onSuccess) {
options.onSuccess(result.user);
} else {
// Wenn auf der Startseite: UI aktualisieren
window.AUTH.updateUI();
}
} else { } else {
errorMsg.innerText = result.error || "Ein Fehler ist aufgetreten"; errorBox.innerText = result.error || 'Fehler bei der Authentifizierung';
errorMsg.style.display = "block"; errorBox.style.display = 'block';
} }
}; };
}; };
document.addEventListener("DOMContentLoaded", () => { // URL-Parameter prüfen (z.B. ?auth=login oder ?auth=register)
document.addEventListener('DOMContentLoaded', () => {
window.AUTH.updateUI(); window.AUTH.updateUI();
window.AUTH.fetchMe(); window.AUTH.fetchMe();
const params = new URLSearchParams(window.location.search);
const authParam = params.get('auth');
if (authParam === 'login' || authParam === 'register') {
window.openAuthModal(authParam, { allowClose: true });
}
}); });
})(); })();

View file

@ -90,20 +90,41 @@
function initSidebar() { function initSidebar() {
const rootPrefix = getRootPrefix(); const rootPrefix = getRootPrefix();
if (!window.COURSES_MANIFEST) { function proceed() {
const manifestScript = document.createElement('script'); if (!window.COURSES_MANIFEST) {
manifestScript.src = `${rootPrefix}assets/courses_manifest.js`; const manifestScript = document.createElement('script');
manifestScript.onload = () => buildSidebar(); manifestScript.src = `${rootPrefix}assets/courses_manifest.js`;
manifestScript.onerror = () => console.error('Konnte courses_manifest.js nicht laden.'); manifestScript.onload = () => buildSidebar();
document.head.appendChild(manifestScript); manifestScript.onerror = () => console.error('Konnte courses_manifest.js nicht laden.');
document.head.appendChild(manifestScript);
} else {
buildSidebar();
}
}
if (!window.AUTH) {
const authScript = document.createElement('script');
authScript.src = `${rootPrefix}assets/app_auth.js`;
authScript.onload = () => proceed();
authScript.onerror = () => proceed();
document.head.appendChild(authScript);
} else { } else {
buildSidebar(); proceed();
} }
} }
function buildSidebar() { function buildSidebar() {
if (!window.COURSES_MANIFEST) return; if (!window.COURSES_MANIFEST) return;
// Zugangsschutz: Kurse & Web-IDE erfordern Authentifizierung
if (window.AUTH && typeof window.AUTH.requireAuth === 'function') {
window.AUTH.requireAuth({
allowClose: false,
title: '🔒 Registrierung erforderlich',
message: 'Um die interaktiven Kursmodule und die Web-IDE zu nutzen, erstelle bitte einen kostenlosen Account oder melde dich an.'
});
}
// Alte legacy sidebars entfernen falls vorhanden // Alte legacy sidebars entfernen falls vorhanden
document.querySelectorAll('.app-sidebar, .sidebar-mobile-toggle, .sidebar-overlay').forEach(el => el.remove()); document.querySelectorAll('.app-sidebar, .sidebar-mobile-toggle, .sidebar-overlay').forEach(el => el.remove());
const existingSidebar = document.getElementById('courseSidebar'); const existingSidebar = document.getElementById('courseSidebar');

View file

@ -106,6 +106,15 @@
// 2. Code-Ausführung via aktivem Language-Runner // 2. Code-Ausführung via aktivem Language-Runner
async function runCode() { async function runCode() {
if (window.AUTH && !window.AUTH.isLoggedIn()) {
window.AUTH.requireAuth({
allowClose: false,
title: '🔒 Registrierung erforderlich',
message: 'Um Code in der Web-IDE auszuführen, erstelle bitte einen kostenlosen Account oder melde dich an.'
});
return;
}
const code = getEditorCode(); const code = getEditorCode();
clearTerminal(); clearTerminal();
@ -128,6 +137,15 @@
// 3. Test-Ausführung via aktivem Language-Runner // 3. Test-Ausführung via aktivem Language-Runner
async function runTests() { async function runTests() {
if (window.AUTH && !window.AUTH.isLoggedIn()) {
window.AUTH.requireAuth({
allowClose: false,
title: '🔒 Registrierung erforderlich',
message: 'Um automatisierte Tests auszuführen und Lernfortschritt zu speichern, erstelle bitte einen kostenlosen Account oder melde dich an.'
});
return;
}
if (!currentChapterData || !currentChapterData.testCode) { if (!currentChapterData || !currentChapterData.testCode) {
logToTerminal("❌ Keine Unittests für dieses Kapitel gefunden.\n", "error"); logToTerminal("❌ Keine Unittests für dieses Kapitel gefunden.\n", "error");
return; return;

View file

@ -608,6 +608,70 @@ pre code {
background: var(--bg-subtle); background: var(--bg-subtle);
} }
/* ==========================================================================
FORM INPUTS & TEXTBOX RESIZING SAFEGUARDS
========================================================================== */
textarea, input[type="text"], input[type="email"], input[type="password"], input[type="number"], select {
box-sizing: border-box;
max-width: 100%;
}
textarea {
width: 100%;
max-width: 100%;
min-width: 0;
resize: vertical; /* Verhindert horizontales Ausbrechen aus Containern */
overflow-y: auto;
font-family: inherit;
font-size: 0.92rem;
line-height: 1.55;
padding: 10px 14px;
border: 1px solid var(--border-color);
border-radius: var(--radius-sm);
background: var(--bg-surface);
color: var(--text-main);
transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
textarea:focus {
outline: none;
border-color: var(--primary);
box-shadow: 0 0 0 3px var(--primary-glow);
}
.ihk-input {
width: 100%;
max-width: 100% !important;
min-width: 0 !important;
resize: vertical !important; /* Nur vertikal vergrößerbar - schützt das Layout */
box-sizing: border-box !important;
border: 1px solid #cbd5e1;
border-radius: 8px;
padding: 12px 14px;
font-family: var(--font-sans);
font-size: 0.92rem;
line-height: 1.5;
background: #ffffff;
color: #0f172a;
margin-top: 8px;
margin-bottom: 8px;
transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.ihk-input:focus {
outline: none;
border-color: #0284c7;
box-shadow: 0 0 0 3px rgba(2, 132, 199, 0.15);
}
/* Sicherstellen, dass kein Kind-Element Karten oder Raster sprengt */
.card, .container, .app-main, .portal-card, .workspace-body, .pane-left, .pane-right, .task-item, .box {
min-width: 0;
overflow-wrap: break-word;
word-break: break-word;
}
.footer-nav { .footer-nav {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;

View file

@ -3,16 +3,15 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>IT-Praxisportal | Die interaktive Plattform für IT-Berufe &amp; Software-Entwicklung</title> <title>IT-Praxisportal | Die interaktive Lern- &amp; Prüfungsvorbereitungs-Plattform für IT-Berufe</title>
<link rel="icon" type="image/svg+xml" href="assets/favicon.svg"> <link rel="icon" type="image/svg+xml" href="assets/favicon.svg">
<meta name="description" content="IT-Praxisportal: Die interaktive Lernplattform für Fachinformatiker, Software-Entwickler &amp; IT-Ausbildung. 216+ Module, Monaco Web-IDE und IHK AP1 &amp; AP2 Prüfungsvorbereitung im Browser."> <meta name="description" content="IT-Praxisportal: Die interaktive Lernplattform für Fachinformatiker &amp; IT-Entwickler. 216+ Module in 13 Schlüssel-Technologien, Monaco Web-IDE und IHK AP1 &amp; AP2 Prüfungsvorbereitung im Browser.">
<meta property="og:title" content="IT-Praxisportal | Praxisnahe IT-Kompetenz im Browser"> <meta property="og:title" content="IT-Praxisportal | Praxisnahe IT-Kompetenz im Browser">
<meta property="og:description" content="216+ Module für Python, Bash, PowerShell, SQL, Web, Java, Go, Rust, C#, C++ &amp; IHK AP1/AP2 Prüfungssimulation mit integrierter Monaco Web-IDE."> <meta property="og:description" content="216+ Module für Linux Bash, SQL, Python, Java, Go, Rust, C#, C++, PowerShell, Web &amp; IHK AP1/AP2 Prüfungssimulation mit integrierter Web-IDE.">
<meta property="og:type" content="website"> <meta property="og:type" content="website">
<meta property="og:url" content="https://alpha.it-praxisportal.de/"> <meta property="og:url" content="https://alpha.it-praxisportal.de/">
<link rel="stylesheet" href="assets/style.css"> <link rel="stylesheet" href="assets/style.css">
<style> <style>
/* Sleek Scoped Enhancements for Minimal Modern UX */
.portal-container { .portal-container {
max-width: 1240px; max-width: 1240px;
margin: 0 auto; margin: 0 auto;
@ -38,11 +37,43 @@
color: #c2410c; color: #c2410c;
border: 1px solid #fed7aa; border: 1px solid #fed7aa;
} }
.portal-card-btn.locked {
background: rgba(2, 132, 199, 0.1);
color: #0284c7;
border: 1px solid rgba(2, 132, 199, 0.3);
display: inline-flex;
align-items: center;
gap: 6px;
}
.portal-card-btn.locked:hover {
background: #0284c7;
color: white;
border-color: #0284c7;
}
.portal-card-btn {
background: #0284c7;
color: white;
border: 1px solid transparent;
display: inline-flex;
align-items: center;
gap: 6px;
padding: 8px 16px;
border-radius: 8px;
font-size: 0.84rem;
font-weight: 700;
text-decoration: none;
cursor: pointer;
transition: all 0.15s ease;
}
.portal-card-btn:hover {
background: #0369a1;
transform: translateY(-1px);
}
</style> </style>
</head> </head>
<body style="background: #f8fafc; color: #0f172a; font-family: var(--font-sans); margin: 0; padding: 0;"> <body style="background: #f8fafc; color: #0f172a; font-family: var(--font-sans); margin: 0; padding: 0;">
<!-- 1. STICKY TOPBAR --> <!-- 1. STICKY MARKETING HEADER -->
<header class="portal-header-bar"> <header class="portal-header-bar">
<div class="portal-nav-container"> <div class="portal-nav-container">
<a href="index.html" class="portal-brand"> <a href="index.html" class="portal-brand">
@ -56,101 +87,100 @@
</a> </a>
<nav class="portal-nav-links"> <nav class="portal-nav-links">
<a href="#katalog" class="portal-nav-link">📚 Kurs-Katalog</a> <a href="#hero" class="portal-nav-link">🚀 Übersicht</a>
<a href="#katalog" class="portal-nav-link">📚 13 Praxis-Kurse</a>
<a href="#ihk-section" class="portal-nav-link">🎓 IHK Prüfung</a> <a href="#ihk-section" class="portal-nav-link">🎓 IHK Prüfung</a>
<a href="workspace.html?course=python" class="portal-nav-link">💻 Web-IDE</a> <a href="#features-ide" class="portal-nav-link">💻 Web-IDE</a>
<a href="#zertifikate" class="portal-nav-link">🏆 Zertifikate</a> <a href="#features" class="portal-nav-link">💎 Vorteile</a>
<a href="teacher.html" class="portal-nav-link" id="nav-teacher-link" style="display: none;">👨‍🏫 Dozenten</a> <a href="teacher.html" class="portal-nav-link" id="nav-teacher-link" style="display: none;">👨‍🏫 Dozenten</a>
</nav> </nav>
<div style="display: flex; align-items: center; gap: 10px;"> <div style="display: flex; align-items: center; gap: 10px;">
<span id="nav-auth-user" style="display: none; font-size: 0.82rem; font-weight: 700; color: #38bdf8; background: rgba(56, 189, 248, 0.1); padding: 4px 10px; border-radius: 99px; border: 1px solid rgba(56, 189, 248, 0.2);"></span> <span id="nav-auth-user" style="display: none; font-size: 0.82rem; font-weight: 700; color: #38bdf8; background: rgba(56, 189, 248, 0.1); padding: 4px 10px; border-radius: 99px; border: 1px solid rgba(56, 189, 248, 0.2);"></span>
<button type="button" class="btn" id="nav-btn-guest" style="padding: 6px 14px; font-size: 0.82rem; background: #059669;" onclick="window.AUTH.startGuestSoloMode()">🚀 Solo-Start (Gast)</button> <button type="button" class="btn" id="nav-btn-login" style="padding: 6px 14px; font-size: 0.82rem; background: rgba(255,255,255,0.12); color: white; border: 1px solid rgba(255,255,255,0.2);" onclick="window.openAuthModal('login', { allowClose: true })">🔑 Anmelden</button>
<button type="button" class="btn" id="nav-btn-login" style="padding: 6px 14px; font-size: 0.82rem; background: rgba(255,255,255,0.12); color: white;" onclick="window.openAuthModal('login')">🔑 Anmelden</button> <button type="button" class="btn" id="nav-btn-register" style="padding: 6px 14px; font-size: 0.82rem; background: #0284c7; color: white;" onclick="window.openAuthModal('register', { allowClose: true })">✨ Kostenlos registrieren</button>
<button type="button" class="btn" id="nav-btn-register" style="padding: 6px 14px; font-size: 0.82rem; background: #0284c7;" onclick="window.openAuthModal('register')">Konto erstellen</button>
</div> </div>
</div> </div>
</header> </header>
<!-- 2. HERO SECTION --> <!-- 2. HIGH-CONVERTING HERO SECTION -->
<section class="portal-hero"> <section class="portal-hero" id="hero">
<div class="portal-container"> <div class="portal-container">
<div class="portal-hero-pill"> <div class="portal-hero-pill">
<span>⚡ Version 1.0 Alpha</span> <span>⚡ Die #1 Lernplattform für Fachinformatiker &amp; IT-Profis</span>
<span style="opacity: 0.5;">•</span> <span style="opacity: 0.5;">•</span>
<span>216+ Interaktive Module</span> <span>216+ Module</span>
<span style="opacity: 0.5;">•</span> <span style="opacity: 0.5;">•</span>
<span>IHK AO 2020 Konform</span> <span>100% Kostenlos</span>
</div> </div>
<h1>Praxisnahe IT-Kompetenz – Direkt im Browser</h1> <h1>Echte IT-Praxis statt trockener Theorie.</h1>
<p>Die All-in-One Lernplattform für <strong>Fachinformatiker, Software-Entwickler &amp; IT-Auszubildende</strong>. Lerne 11 moderne Programmier- und Skriptsprachen und bereite dich mit echten IHK-Fragen auf deine Abschlussprüfung vor.</p> <p>Die All-in-One Lernplattform für <strong>Fachinformatiker, Software-Entwickler &amp; IT-Auszubildende</strong>. Beherrsche 13 Schlüssel-Technologien in 216 interaktiven Modulen und bereite dich mit echten IHK-Fragen auf deine Abschlussprüfung vor – direkt im Browser mit professioneller Monaco Web-IDE.</p>
<div class="portal-hero-actions"> <div class="portal-hero-actions">
<a href="#katalog" class="portal-btn-primary"> <button type="button" id="hero-primary-cta" class="portal-btn-primary" style="cursor: pointer; border: none;" onclick="window.openAuthModal('register', { allowClose: true })">
<span>🚀 Alle Kurse entdecken</span> <span>🚀 Jetzt kostenlos registrieren</span>
<span>&darr;</span> </button>
<a href="#katalog" class="portal-btn-secondary">
<span>📚 Curriculum &amp; Inhalte ansehen &darr;</span>
</a> </a>
<a href="#ihk-section" class="portal-btn-secondary"> <a href="#ihk-section" class="portal-btn-secondary" style="border-color: #38bdf8; color: #38bdf8;">
<span>📘 IHK Prüfungsvorbereitung (AP1 &amp; AP2)</span> <span>🎓 IHK AP1 &amp; AP2 Prüfungstrainer</span>
</a>
<a href="workspace.html?course=python" class="portal-btn-secondary" style="border-color: #38bdf8; color: #38bdf8;">
<span>💻 Web-IDE starten</span>
</a> </a>
</div> </div>
<!-- 4 Quick Stats --> <!-- 4 Quick Stats -->
<div class="portal-stats-bar"> <div class="portal-stats-bar">
<div class="portal-stat-card">
<div class="portal-stat-num">13</div>
<div class="portal-stat-label">Praxis-Lehrpfade</div>
<div class="portal-stat-desc">Linux, Cloud, OOP, Systems &amp; Web</div>
</div>
<div class="portal-stat-card"> <div class="portal-stat-card">
<div class="portal-stat-num">216+</div> <div class="portal-stat-num">216+</div>
<div class="portal-stat-label">Interaktive Module</div> <div class="portal-stat-label">Interaktive Module</div>
<div class="portal-stat-desc">Vollständige Curricula mit Tests</div> <div class="portal-stat-desc">Geführte Subgoals &amp; Sofort-Tests</div>
</div> </div>
<div class="portal-stat-card"> <div class="portal-stat-card">
<div class="portal-stat-num">12</div> <div class="portal-stat-num">150+</div>
<div class="portal-stat-label">Technologie-Tracks</div>
<div class="portal-stat-desc">DevOps, Cloud, Web, Systems &amp; IHK</div>
</div>
<div class="portal-stat-card">
<div class="portal-stat-num">150</div>
<div class="portal-stat-label">IHK-Prüfungsfragen</div> <div class="portal-stat-label">IHK-Prüfungsfragen</div>
<div class="portal-stat-desc">Original-Wortlaut &amp; 90-Min Timer</div> <div class="portal-stat-desc">AP1 &amp; AP2 Simulation mit Timer</div>
</div> </div>
<div class="portal-stat-card"> <div class="portal-stat-card">
<div class="portal-stat-num">100 %</div> <div class="portal-stat-num">0 min</div>
<div class="portal-stat-label">Zero-Install Web-IDE</div> <div class="portal-stat-label">Installationsaufwand</div>
<div class="portal-stat-desc">Monaco Editor &amp; WASM im Browser</div> <div class="portal-stat-desc">VS Code Monaco Editor im Browser</div>
</div> </div>
</div> </div>
</div> </div>
</section> </section>
<!-- 3. KURS-KATALOG & FILTER --> <!-- 3. KURS-KATALOG & CURRICULUM ÜBERSICHT -->
<main class="portal-container" id="katalog" style="padding-top: 48px; padding-bottom: 64px;"> <main class="portal-container" id="katalog" style="padding-top: 48px; padding-bottom: 64px;">
<div class="portal-filter-bar"> <div class="portal-filter-bar">
<div> <div>
<h2 style="font-size: 1.8rem; font-weight: 900; margin: 0 0 6px 0; color: #0f172a;">📚 Interaktive Kurse &amp; Tracks</h2> <h2 style="font-size: 1.8rem; font-weight: 900; margin: 0 0 6px 0; color: #0f172a;">📚 Lehrplan &amp; Kurs-Katalog</h2>
<p style="color: #64748b; margin: 0; font-size: 0.95rem;">Wähle eine Disziplin und starte sofort mit Theorie, Subgoals und Live-Code.</p> <p style="color: #64748b; margin: 0; font-size: 0.95rem;">Entdecke alle 13 Disziplinen. Registriere dich kostenlos, um alle Aufgaben und die Web-IDE freizuschalten.</p>
</div> </div>
<!-- Search Box --> <!-- Search Box -->
<div class="portal-search-box"> <div class="portal-search-box">
<span style="font-size: 1rem;">🔍</span> <span style="font-size: 1rem;">🔍</span>
<input type="text" id="course-filter-input" placeholder="Kurs oder Thema filtern (z.B. Python, Subnetting, SQL, Bash)..."> <input type="text" id="course-filter-input" placeholder="Kurs oder Thema filtern (z.B. Python, Subnetting, SQL, Bash, Rust)...">
</div> </div>
</div> </div>
<!-- Category Filter Tabs --> <!-- Category Filter Tabs -->
<div class="portal-filter-tabs" style="margin-bottom: 24px;"> <div class="portal-filter-tabs" style="margin-bottom: 24px;">
<button type="button" class="portal-tab-pill active" onclick="filterCourses('all', this)">🌟 Alle Tracks (12)</button> <button type="button" class="portal-tab-pill active" onclick="filterCourses('all', this)">🌟 Alle Disziplinen (13)</button>
<button type="button" class="portal-tab-pill" onclick="filterCourses('ihk', this)">🎓 IHK Prüfung (2)</button> <button type="button" class="portal-tab-pill" onclick="filterCourses('ihk', this)">🎓 IHK Prüfung (2)</button>
<button type="button" class="portal-tab-pill" onclick="filterCourses('devops', this)">🐧 DevOps &amp; Sysadmin (2)</button> <button type="button" class="portal-tab-pill" onclick="filterCourses('devops', this)">🐧 DevOps &amp; Linux (2)</button>
<button type="button" class="portal-tab-pill" onclick="filterCourses('coding', this)">💻 Software &amp; Coding (6)</button> <button type="button" class="portal-tab-pill" onclick="filterCourses('coding', this)">💻 Backend &amp; Systems (6)</button>
<button type="button" class="portal-tab-pill" onclick="filterCourses('data', this)">🗄️ Daten &amp; Web (2)</button> <button type="button" class="portal-tab-pill" onclick="filterCourses('data', this)">🗄️ Daten &amp; Web (3)</button>
</div> </div>
<!-- GRID OF 12 COURSES --> <!-- GRID OF ALL 13 COURSES -->
<div class="portal-courses-grid" id="courses-grid-container"> <div class="portal-courses-grid" id="courses-grid-container">
<!-- 1. IHK AP1 --> <!-- 1. IHK AP1 -->
@ -158,20 +188,22 @@
<div> <div>
<div class="portal-card-top"> <div class="portal-card-top">
<div class="portal-card-icon">📘</div> <div class="portal-card-icon">📘</div>
<span class="portal-card-badge badge-ihk">IHK Prüfung</span> <span class="portal-card-badge badge-ihk">IHK Abschlussprüfung</span>
</div> </div>
<h3 class="portal-card-title">IHK AP1: IT-Arbeitsplatz &amp; Basissysteme</h3> <h3 class="portal-card-title">IHK AP1: IT-Arbeitsplatz &amp; Basissysteme</h3>
<p class="portal-card-desc">Lückenlose Vorbereitung auf die Abschlussprüfung Teil 1. Alle Lernfelder (LF 1 bis LF 8), Subnetting-Drill, Trace-Tabellen, SQL-Labor &amp; 90-Minuten Probeprüfung.</p> <p class="portal-card-desc">Lückenlose Vorbereitung auf die Abschlussprüfung Teil 1. Alle Lernfelder (LF 1 bis LF 8), Subnetting-Drill, Trace-Tabellen, SQL-Labor &amp; 90-Minuten Probeprüfung.</p>
<div class="portal-card-tags"> <div class="portal-card-tags">
<span class="portal-card-tag">LF 1–8</span> <span class="portal-card-tag">LF 1–8 Kernqualifikation</span>
<span class="portal-card-tag">Subnetting</span> <span class="portal-card-tag">Subnetting Drill</span>
<span class="portal-card-tag">Trace-Tabellen</span> <span class="portal-card-tag">Trace-Tabellen</span>
<span class="portal-card-tag">Probeprüfung</span> <span class="portal-card-tag">90-Min Simulation</span>
</div> </div>
</div> </div>
<div class="portal-card-footer"> <div class="portal-card-footer">
<span class="portal-card-meta">⏱️ 12 Module &bull; 100 Pkt.</span> <span class="portal-card-meta">⏱️ 12 Module &bull; 100 Pkt.</span>
<a href="courses/ihk_ap1/01_lf1_unternehmen_und_arbeitsplatz/index.html" class="portal-card-btn">📘 AP1 Starten &rarr;</a> <button type="button" class="portal-card-btn portal-card-action-btn locked" data-course-id="ihk_ap1" data-course-url="courses/ihk_ap1/01_lf1_unternehmen_und_arbeitsplatz/index.html">
<span>🔒 Kostenlos freischalten</span>
</button>
</div> </div>
</div> </div>
@ -180,20 +212,22 @@
<div> <div>
<div class="portal-card-top"> <div class="portal-card-top">
<div class="portal-card-icon">📕</div> <div class="portal-card-icon">📕</div>
<span class="portal-card-badge badge-ihk">IHK Prüfung</span> <span class="portal-card-badge badge-ihk">IHK Abschlussprüfung</span>
</div> </div>
<h3 class="portal-card-title">IHK AP2: Fachinformatiker Systemintegration</h3> <h3 class="portal-card-title">IHK AP2: Fachinformatiker Systemintegration</h3>
<p class="portal-card-desc">Fachrichtung Systemintegration: LF 9 (Netzwerke/VLAN), LF 10 (Server/AD), LF 11 (Storage/RAID), LF 12 (Cloud/Docker), WiSo &amp; offizieller Leitfaden zur 40h-Projektarbeit.</p> <p class="portal-card-desc">Fachrichtung Systemintegration: LF 9 (Netzwerke/VLAN), LF 10 (Server/AD), LF 11 (Storage/RAID), LF 12 (Cloud/Docker), WiSo &amp; offizieller Leitfaden zur 40h-Projektarbeit.</p>
<div class="portal-card-tags"> <div class="portal-card-tags">
<span class="portal-card-tag">LF 9–12</span> <span class="portal-card-tag">LF 9–12 FISI</span>
<span class="portal-card-tag">Active Directory</span> <span class="portal-card-tag">Active Directory &amp; GPO</span>
<span class="portal-card-tag">WiSo</span> <span class="portal-card-tag">WiSo Prüfungsfragen</span>
<span class="portal-card-tag">40h-Projekt</span> <span class="portal-card-tag">40h-Projektarbeit</span>
</div> </div>
</div> </div>
<div class="portal-card-footer"> <div class="portal-card-footer">
<span class="portal-card-meta">⏱️ 9 Module &bull; 3 Simulationen</span> <span class="portal-card-meta">⏱️ 9 Module &bull; 3 Simulationen</span>
<a href="courses/ihk_ap2_fisi/01_lf9_netzwerke_und_dienste/index.html" class="portal-card-btn">📕 AP2 FISI Starten &rarr;</a> <button type="button" class="portal-card-btn portal-card-action-btn locked" data-course-id="ihk_ap2_fisi" data-course-url="courses/ihk_ap2_fisi/01_lf9_netzwerke_und_dienste/index.html">
<span>🔒 Kostenlos freischalten</span>
</button>
</div> </div>
</div> </div>
@ -204,7 +238,7 @@
<div class="portal-card-icon">🐍</div> <div class="portal-card-icon">🐍</div>
<span class="portal-card-badge badge-code">Software &amp; Coding</span> <span class="portal-card-badge badge-code">Software &amp; Coding</span>
</div> </div>
<h3 class="portal-card-title">Python 3: Vom Einsteiger zum Software-Entwickler</h3> <h3 class="portal-card-title">Python 3: Vom Einsteiger zum Entwickler</h3>
<p class="portal-card-desc">Das umfassende Flaggschiff-Curriculum: Grundlagen (G01–G10), Objektorientierung (00–06), Fortgeschrittenes OOP &amp; GUI (07–16) und Data Engineering (17–22).</p> <p class="portal-card-desc">Das umfassende Flaggschiff-Curriculum: Grundlagen (G01–G10), Objektorientierung (00–06), Fortgeschrittenes OOP &amp; GUI (07–16) und Data Engineering (17–22).</p>
<div class="portal-card-tags"> <div class="portal-card-tags">
<span class="portal-card-tag">OOP &amp; Klassen</span> <span class="portal-card-tag">OOP &amp; Klassen</span>
@ -215,73 +249,81 @@
</div> </div>
<div class="portal-card-footer"> <div class="portal-card-footer">
<span class="portal-card-meta">⏱️ 35 Module &bull; 4 Lehrpfade</span> <span class="portal-card-meta">⏱️ 35 Module &bull; 4 Lehrpfade</span>
<a href="workspace.html?course=python&chapter=01_erste_schritte_taschenrechner" class="portal-card-btn">🐍 In Web-IDE &rarr;</a> <button type="button" class="portal-card-btn portal-card-action-btn locked" data-course-id="python" data-course-url="workspace.html?course=python&chapter=01_erste_schritte_taschenrechner">
<span>🔒 Kostenlos freischalten</span>
</button>
</div> </div>
</div> </div>
<!-- 4. LINUX BASH --> <!-- 4. LINUX BASH & CLOUD DEVOPS -->
<div class="portal-card" data-category="devops" data-title="linux bash shell scripting pipelines devops docker systemd automation"> <div class="portal-card" data-category="devops" data-title="linux bash shell scripting terminal devops jq sed awk docker bats ci/cd">
<div> <div>
<div class="portal-card-top"> <div class="portal-card-top">
<div class="portal-card-icon">🐧</div> <div class="portal-card-icon">🐧</div>
<span class="portal-card-badge badge-devops">DevOps &amp; Sysadmin</span> <span class="portal-card-badge badge-devops">DevOps &amp; Cloud</span>
</div> </div>
<h3 class="portal-card-title">Linux Bash, Shell Scripting &amp; Cloud DevOps</h3> <h3 class="portal-card-title">Linux Bash, Shell Scripting &amp; Cloud DevOps</h3>
<p class="portal-card-desc">Praxisnahe Automatisierung: Streams &amp; Redirection, awk/sed/jq Text Mining, Job-Control, Multithreading mit xargs/parallel, Systemd Services, Docker &amp; CI/CD Pipelines.</p> <p class="portal-card-desc">Terminal-Mastery für Sysadmins: I/O Streams, Pipes, Text-Mining mit <code>jq</code>, <code>sed</code> und <code>awk</code>, Parallelisierung (xargs/parallel), Docker-Scripting &amp; BATS Unittests.</p>
<div class="portal-card-tags"> <div class="portal-card-tags">
<span class="portal-card-tag">Pipes &amp; Streams</span> <span class="portal-card-tag">I/O Redirection</span>
<span class="portal-card-tag">jq &amp; awk</span> <span class="portal-card-tag">jq JSON Mining</span>
<span class="portal-card-tag">Systemd</span> <span class="portal-card-tag">xargs Multithreading</span>
<span class="portal-card-tag">BATS Tests</span> <span class="portal-card-tag">BATS Testsuite</span>
</div> </div>
</div> </div>
<div class="portal-card-footer"> <div class="portal-card-footer">
<span class="portal-card-meta">⏱️ 16 Module &bull; 4 Lehrpfade</span> <span class="portal-card-meta">⏱️ 16 Module &bull; 4 Lehrpfade</span>
<a href="workspace.html?course=bash&chapter=01_navigation_dateien_und_globbing" class="portal-card-btn">🐧 In Web-IDE &rarr;</a> <button type="button" class="portal-card-btn portal-card-action-btn locked" data-course-id="bash" data-course-url="workspace.html?course=bash&chapter=01_navigation_dateien_und_globbing">
<span>🔒 Kostenlos freischalten</span>
</button>
</div> </div>
</div> </div>
<!-- 5. POWERSHELL --> <!-- 5. POWERSHELL 7+ CORE -->
<div class="portal-card" data-category="devops" data-title="powershell 7 core windows administration cmdlets objekte pester cloud"> <div class="portal-card" data-category="devops" data-title="powershell ps7 cmdlets pipeline .net rest api pester active directory">
<div> <div>
<div class="portal-card-top"> <div class="portal-card-top">
<div class="portal-card-icon">🔷</div> <div class="portal-card-icon">🛡️</div>
<span class="portal-card-badge badge-devops">DevOps &amp; Sysadmin</span> <span class="portal-card-badge badge-devops">DevOps &amp; Cloud</span>
</div> </div>
<h3 class="portal-card-title">Modern PowerShell 7+ Core &amp; Automation</h3> <h3 class="portal-card-title">PowerShell 7+ Core: Enterprise Automation</h3>
<p class="portal-card-desc">Objekt-orientiertes Scripting: .NET Pipeline-Architektur, PSCustomObject, CmdletBinding, Multithreading (-Parallel), REST APIs, Registry, Pester Tests &amp; Cloud Engine.</p> <p class="portal-card-desc">Modernes Microsoft &amp; Multi-Platform Scripting: Die Objekt-Pipeline, Custom PSCustomObjects, REST-APIs, moderne Parallelisierung mit <code>ForEach-Object -Parallel</code> &amp; Pester Unit Tests.</p>
<div class="portal-card-tags"> <div class="portal-card-tags">
<span class="portal-card-tag">Objekt-Pipeline</span> <span class="portal-card-tag">Objekt-Pipeline</span>
<span class="portal-card-tag">PSCustomObject</span> <span class="portal-card-tag">PSCustomObject</span>
<span class="portal-card-tag">Parallel</span> <span class="portal-card-tag">Parallel-Jobs</span>
<span class="portal-card-tag">Pester v5</span> <span class="portal-card-tag">Pester Tests</span>
</div> </div>
</div> </div>
<div class="portal-card-footer"> <div class="portal-card-footer">
<span class="portal-card-meta">⏱️ 16 Module &bull; 4 Lehrpfade</span> <span class="portal-card-meta">⏱️ 16 Module &bull; 4 Lehrpfade</span>
<a href="workspace.html?course=powershell&chapter=01_powershell_konsole_und_cmdlet_architektur" class="portal-card-btn">🔷 In Web-IDE &rarr;</a> <button type="button" class="portal-card-btn portal-card-action-btn locked" data-course-id="powershell" data-course-url="workspace.html?course=powershell&chapter=01_powershell_konsole_und_cmdlet_architektur">
<span>🔒 Kostenlos freischalten</span>
</button>
</div> </div>
</div> </div>
<!-- 6. SQL --> <!-- 6. SQL & DATENBANKEN -->
<div class="portal-card" data-category="data" data-title="sql relationale datenbanken joins ctes window functions normalisierung"> <div class="portal-card" data-category="data" data-title="sql datenbanken postgresql sqlite normalisierung joins cte window-functions acid">
<div> <div>
<div class="portal-card-top"> <div class="portal-card-top">
<div class="portal-card-icon">🗄️</div> <div class="portal-card-icon">🐬</div>
<span class="portal-card-badge badge-data">Daten &amp; Web</span> <span class="portal-card-badge badge-data">Daten &amp; Web</span>
</div> </div>
<h3 class="portal-card-title">SQL &amp; Data Analytics Master</h3> <h3 class="portal-card-title">SQL &amp; Relationale Datenbank-Architektur</h3>
<p class="portal-card-desc">Vom SELECT bis zum Data Warehouse: Normalisierung (1NF–3NF), INNER/LEFT JOINs, Aggregate, Subqueries, CTEs, Window Functions (OVER/PARTITION BY) &amp; ACID-Transaktionen.</p> <p class="portal-card-desc">Vollständiges relationales Datenmanagement: Strikte Normalisierung (1NF–3NF), komplexe Multi-Table JOINs, Subqueries, Common Table Expressions (CTEs), Window Functions &amp; ACID Transaktionen.</p>
<div class="portal-card-tags"> <div class="portal-card-tags">
<span class="portal-card-tag">SQLite WASM</span> <span class="portal-card-tag">1NF–3NF Normalisierung</span>
<span class="portal-card-tag">JOINs &amp; CTEs</span> <span class="portal-card-tag">JOINs &amp; CTEs</span>
<span class="portal-card-tag">Window Functions</span> <span class="portal-card-tag">Window Functions</span>
<span class="portal-card-tag">Normalisierung</span> <span class="portal-card-tag">Query Plans</span>
</div> </div>
</div> </div>
<div class="portal-card-footer"> <div class="portal-card-footer">
<span class="portal-card-meta">⏱️ 16 Module &bull; 4 Lehrpfade</span> <span class="portal-card-meta">⏱️ 16 Module &bull; 4 Lehrpfade</span>
<a href="workspace.html?course=sql&chapter=01_tabellen_und_select" class="portal-card-btn">🗄️ In Web-IDE &rarr;</a> <button type="button" class="portal-card-btn portal-card-action-btn locked" data-course-id="sql" data-course-url="workspace.html?course=sql&chapter=01_tabellen_und_select">
<span>🔒 Kostenlos freischalten</span>
</button>
</div> </div>
</div> </div>
@ -295,19 +337,21 @@
<h3 class="portal-card-title">JavaScript &amp; Modernes TypeScript</h3> <h3 class="portal-card-title">JavaScript &amp; Modernes TypeScript</h3>
<p class="portal-card-desc">Moderne Web-Entwicklung: ES6+ Syntax, Klassen &amp; OOP, Async/Await &amp; Promises, DOM-Manipulation, Web Storage, ES-Module und statische Typisierung mit TypeScript Generics.</p> <p class="portal-card-desc">Moderne Web-Entwicklung: ES6+ Syntax, Klassen &amp; OOP, Async/Await &amp; Promises, DOM-Manipulation, Web Storage, ES-Module und statische Typisierung mit TypeScript Generics.</p>
<div class="portal-card-tags"> <div class="portal-card-tags">
<span class="portal-card-tag">ES6+</span> <span class="portal-card-tag">ES6+ &amp; OOP</span>
<span class="portal-card-tag">Async/Await</span> <span class="portal-card-tag">Async/Await</span>
<span class="portal-card-tag">DOM Events</span> <span class="portal-card-tag">DOM Events</span>
<span class="portal-card-tag">TypeScript</span> <span class="portal-card-tag">TypeScript Generics</span>
</div> </div>
</div> </div>
<div class="portal-card-footer"> <div class="portal-card-footer">
<span class="portal-card-meta">⏱️ 16 Module &bull; 4 Lehrpfade</span> <span class="portal-card-meta">⏱️ 16 Module &bull; 4 Lehrpfade</span>
<a href="workspace.html?course=javascript&chapter=01_erste_schritte_variablen" class="portal-card-btn">🌐 In Web-IDE &rarr;</a> <button type="button" class="portal-card-btn portal-card-action-btn locked" data-course-id="javascript" data-course-url="workspace.html?course=javascript&chapter=01_erste_schritte_variablen">
<span>🔒 Kostenlos freischalten</span>
</button>
</div> </div>
</div> </div>
<!-- 8. JAVA 21+ --> <!-- 8. JAVA 21 ENTERPRISE -->
<div class="portal-card" data-category="coding" data-title="java 21 enterprise oop virtual threads streams junit5 records"> <div class="portal-card" data-category="coding" data-title="java 21 enterprise oop virtual threads streams junit5 records">
<div> <div>
<div class="portal-card-top"> <div class="portal-card-top">
@ -325,11 +369,13 @@
</div> </div>
<div class="portal-card-footer"> <div class="portal-card-footer">
<span class="portal-card-meta">⏱️ 16 Module &bull; 4 Lehrpfade</span> <span class="portal-card-meta">⏱️ 16 Module &bull; 4 Lehrpfade</span>
<a href="workspace.html?course=java&chapter=01_java_syntax_und_primitive_typen" class="portal-card-btn">☕ In Web-IDE &rarr;</a> <button type="button" class="portal-card-btn portal-card-action-btn locked" data-course-id="java" data-course-url="workspace.html?course=java&chapter=01_java_syntax_und_primitive_typen">
<span>🔒 Kostenlos freischalten</span>
</button>
</div> </div>
</div> </div>
<!-- 9. RUST --> <!-- 9. RUST SYSTEMS -->
<div class="portal-card" data-category="coding" data-title="rust systems ownership borrowing concurrency lifetimes cargo"> <div class="portal-card" data-category="coding" data-title="rust systems ownership borrowing concurrency lifetimes cargo">
<div> <div>
<div class="portal-card-top"> <div class="portal-card-top">
@ -339,7 +385,7 @@
<h3 class="portal-card-title">Rust Modern Systems &amp; Safety</h3> <h3 class="portal-card-title">Rust Modern Systems &amp; Safety</h3>
<p class="portal-card-desc">Zero-Cost Abstractions: Ownership &amp; Borrowing, Lifetimes, Enums mit Option/Result, Traits, Smart Pointer (Box, Arc, Mutex), Fearless Concurrency &amp; LRU-Cache Masterprojekt.</p> <p class="portal-card-desc">Zero-Cost Abstractions: Ownership &amp; Borrowing, Lifetimes, Enums mit Option/Result, Traits, Smart Pointer (Box, Arc, Mutex), Fearless Concurrency &amp; LRU-Cache Masterprojekt.</p>
<div class="portal-card-tags"> <div class="portal-card-tags">
<span class="portal-card-tag">Ownership</span> <span class="portal-card-tag">Ownership System</span>
<span class="portal-card-tag">Lifetimes</span> <span class="portal-card-tag">Lifetimes</span>
<span class="portal-card-tag">Arc&lt;Mutex&gt;</span> <span class="portal-card-tag">Arc&lt;Mutex&gt;</span>
<span class="portal-card-tag">Cargo Tests</span> <span class="portal-card-tag">Cargo Tests</span>
@ -347,33 +393,61 @@
</div> </div>
<div class="portal-card-footer"> <div class="portal-card-footer">
<span class="portal-card-meta">⏱️ 16 Module &bull; 4 Lehrpfade</span> <span class="portal-card-meta">⏱️ 16 Module &bull; 4 Lehrpfade</span>
<a href="workspace.html?course=rust&chapter=01_variablen_mutabilitaet_und_typen" class="portal-card-btn">🦀 In Web-IDE &rarr;</a> <button type="button" class="portal-card-btn portal-card-action-btn locked" data-course-id="rust" data-course-url="workspace.html?course=rust&chapter=01_variablen_mutabilitaet_und_typen">
<span>🔒 Kostenlos freischalten</span>
</button>
</div> </div>
</div> </div>
<!-- 10. C# & .NET 8 --> <!-- 10. GO CLOUD MICROSERVICES (NEU) -->
<div class="portal-card" data-category="coding" data-title="go golang microservices concurrency goroutines channels rest apis">
<div>
<div class="portal-card-top">
<div class="portal-card-icon">🐹</div>
<span class="portal-card-badge badge-code">Software &amp; Coding</span>
</div>
<h3 class="portal-card-title">Go Cloud Microservices &amp; Concurrency</h3>
<p class="portal-card-desc">Entwickle hochskalierbare Cloud-Services mit Google Go: Goroutines, Channel-Pipelines, Mutex Synchronisation, Standard-HTTP-Server, Middleware &amp; REST Microservice Master.</p>
<div class="portal-card-tags">
<span class="portal-card-tag">Goroutines</span>
<span class="portal-card-tag">Channels &amp; Select</span>
<span class="portal-card-tag">net/http Server</span>
<span class="portal-card-tag">Table Tests</span>
</div>
</div>
<div class="portal-card-footer">
<span class="portal-card-meta">⏱️ 16 Module &bull; 4 Lehrpfade</span>
<button type="button" class="portal-card-btn portal-card-action-btn locked" data-course-id="go" data-course-url="workspace.html?course=go&chapter=01_syntax_variablen_und_typen">
<span>🔒 Kostenlos freischalten</span>
</button>
</div>
</div>
<!-- 11. C# 12 & .NET 8 -->
<div class="portal-card" data-category="coding" data-title="csharp dotnet c# 12 linq async tasks xunit clean architecture"> <div class="portal-card" data-category="coding" data-title="csharp dotnet c# 12 linq async tasks xunit clean architecture">
<div> <div>
<div class="portal-card-top"> <div class="portal-card-top">
<div class="portal-card-icon">💜</div> <div class="portal-card-icon">🔷</div>
<span class="portal-card-badge badge-code">Software &amp; Coding</span> <span class="portal-card-badge badge-code">Software &amp; Coding</span>
</div> </div>
<h3 class="portal-card-title">C# 12 &amp; Modernes .NET 8 Enterprise</h3> <h3 class="portal-card-title">C# 12 &amp; Modernes .NET 8 Enterprise</h3>
<p class="portal-card-desc">Moderne Unternehmenssoftware: Top-Level Statements, Pattern Matching, Records, LINQ funktionale Datenabfragen, Asynchrones Task/await, xUnit Tests &amp; Enterprise Order Engine.</p> <p class="portal-card-desc">Moderne Unternehmenssoftware: Top-Level Statements, Pattern Matching, Records, LINQ funktionale Datenabfragen, Asynchrones Task/await, xUnit Tests &amp; Enterprise Order Engine.</p>
<div class="portal-card-tags"> <div class="portal-card-tags">
<span class="portal-card-tag">C# 12</span> <span class="portal-card-tag">C# 12 Primary Ctors</span>
<span class="portal-card-tag">.NET 8</span> <span class="portal-card-tag">LINQ Queries</span>
<span class="portal-card-tag">LINQ</span> <span class="portal-card-tag">Async / Await</span>
<span class="portal-card-tag">xUnit Tests</span> <span class="portal-card-tag">xUnit Testsuite</span>
</div> </div>
</div> </div>
<div class="portal-card-footer"> <div class="portal-card-footer">
<span class="portal-card-meta">⏱️ 16 Module &bull; 4 Lehrpfade</span> <span class="portal-card-meta">⏱️ 16 Module &bull; 4 Lehrpfade</span>
<a href="workspace.html?course=csharp&chapter=01_syntax_datentypen_und_top_level_statements" class="portal-card-btn">💜 In Web-IDE &rarr;</a> <button type="button" class="portal-card-btn portal-card-action-btn locked" data-course-id="csharp" data-course-url="workspace.html?course=csharp&chapter=01_syntax_datentypen_und_top_level_statements">
<span>🔒 Kostenlos freischalten</span>
</button>
</div> </div>
</div> </div>
<!-- 11. C & C++20 --> <!-- 12. C & C++20 SYSTEMS -->
<div class="portal-card" data-category="coding" data-title="cpp c c++ c++20 pointer speicher raii stl templates googletest"> <div class="portal-card" data-category="coding" data-title="cpp c c++ c++20 pointer speicher raii stl templates googletest">
<div> <div>
<div class="portal-card-top"> <div class="portal-card-top">
@ -384,18 +458,20 @@
<p class="portal-card-desc">Das Fundament der Systemprogrammierung: Pointer &amp; dynamischer Speicher, RAII, Klassen &amp; Rule of Five, Templates, Smart Pointer (unique_ptr, shared_ptr), STL &amp; GoogleTest.</p> <p class="portal-card-desc">Das Fundament der Systemprogrammierung: Pointer &amp; dynamischer Speicher, RAII, Klassen &amp; Rule of Five, Templates, Smart Pointer (unique_ptr, shared_ptr), STL &amp; GoogleTest.</p>
<div class="portal-card-tags"> <div class="portal-card-tags">
<span class="portal-card-tag">Pointer &amp; Heap</span> <span class="portal-card-tag">Pointer &amp; Heap</span>
<span class="portal-card-tag">RAII</span> <span class="portal-card-tag">RAII Resource Guard</span>
<span class="portal-card-tag">Smart Pointer</span> <span class="portal-card-tag">Smart Pointer</span>
<span class="portal-card-tag">C++20 STL</span> <span class="portal-card-tag">GoogleTest Suite</span>
</div> </div>
</div> </div>
<div class="portal-card-footer"> <div class="portal-card-footer">
<span class="portal-card-meta">⏱️ 16 Module &bull; 4 Lehrpfade</span> <span class="portal-card-meta">⏱️ 16 Module &bull; 4 Lehrpfade</span>
<a href="workspace.html?course=cpp&chapter=01_c_syntax_datentypen_und_io" class="portal-card-btn">⚙️ In Web-IDE &rarr;</a> <button type="button" class="portal-card-btn portal-card-action-btn locked" data-course-id="cpp" data-course-url="workspace.html?course=cpp&chapter=01_c_syntax_datentypen_und_io">
<span>🔒 Kostenlos freischalten</span>
</button>
</div> </div>
</div> </div>
<!-- 12. HTML5 & CSS3 --> <!-- 13. HTML5 & CSS3 -->
<div class="portal-card" data-category="data" data-title="html css frontend flexbox grid webdesign responsive ui a11y"> <div class="portal-card" data-category="data" data-title="html css frontend flexbox grid webdesign responsive ui a11y">
<div> <div>
<div class="portal-card-top"> <div class="portal-card-top">
@ -406,112 +482,157 @@
<p class="portal-card-desc">Modernes UI-Handwerk: Semantische Tags, Barrierefreiheit (ARIA/A11y), CSS Custom Properties, 1D-Layouts mit Flexbox, 2D-Layouts mit CSS Grid, Media Queries &amp; Dark Mode.</p> <p class="portal-card-desc">Modernes UI-Handwerk: Semantische Tags, Barrierefreiheit (ARIA/A11y), CSS Custom Properties, 1D-Layouts mit Flexbox, 2D-Layouts mit CSS Grid, Media Queries &amp; Dark Mode.</p>
<div class="portal-card-tags"> <div class="portal-card-tags">
<span class="portal-card-tag">Semantik &amp; A11y</span> <span class="portal-card-tag">Semantik &amp; A11y</span>
<span class="portal-card-tag">Flexbox &amp; Grid</span> <span class="portal-card-tag">Flexbox &amp; CSS Grid</span>
<span class="portal-card-tag">Custom Properties</span> <span class="portal-card-tag">Dark Mode Themes</span>
<span class="portal-card-tag">Dark Mode</span> <span class="portal-card-tag">Responsive Design</span>
</div> </div>
</div> </div>
<div class="portal-card-footer"> <div class="portal-card-footer">
<span class="portal-card-meta">⏱️ 16 Module &bull; 4 Lehrpfade</span> <span class="portal-card-meta">⏱️ 16 Module &bull; 4 Lehrpfade</span>
<a href="workspace.html?course=html_css&chapter=01_semantisches_html_und_struktur" class="portal-card-btn">🎨 In Web-IDE &rarr;</a> <button type="button" class="portal-card-btn portal-card-action-btn locked" data-course-id="html_css" data-course-url="workspace.html?course=html_css&chapter=01_semantisches_html_und_struktur">
<span>🔒 Kostenlos freischalten</span>
</button>
</div> </div>
</div> </div>
</div> </div>
<!-- 4. IHK SPEZIAL-HIGHLIGHT BEREICH --> <!-- 4. IHK PRÜFUNGSVORBEREITUNG SHOWCASE -->
<section id="ihk-section" style="background: white; border: 1px solid #bfdbfe; border-radius: 16px; padding: 32px; margin: 48px 0; box-shadow: 0 4px 12px rgba(37, 99, 235, 0.05);"> <section class="card" id="ihk-section" style="margin-top: 56px; border: 1px solid #bfdbfe; background: linear-gradient(180deg, #ffffff 0%, #f0f7ff 100%); border-radius: 16px; padding: 32px;">
<div style="display: flex; justify-content: space-between; align-items: flex-start; flex-wrap: wrap; gap: 16px;"> <div style="display: flex; justify-content: space-between; align-items: flex-start; flex-wrap: wrap; gap: 16px; margin-bottom: 24px;">
<div> <div>
<span class="portal-card-badge badge-ihk" style="font-size: 0.78rem;">Offizieller Prüfungsstandard</span> <span class="portal-card-badge badge-ihk" style="font-size: 0.8rem; font-weight: 800;">Offizieller Prüfungsstandard</span>
<h2 style="font-size: 1.8rem; font-weight: 900; margin: 8px 0; color: #1e3a8a;">🎓 IHK Abschlussprüfung (AP1 &amp; AP2 FISI)</h2> <h3 style="margin: 8px 0 6px 0; font-size: 1.6rem; color: #1e3a8a; font-weight: 900;">🎓 IHK Prüfungstrainer AP1 &amp; AP2</h3>
<p style="color: #475569; max-width: 720px; margin: 0 0 20px 0; font-size: 0.95rem;">Exakt nach der bundeseinheitlichen Ausbildungsordnung (AO 2020) gegliedert. Jedes Lernfeld besitzt ein eigenes Modul mit prüfungsrelevantem Grundlagenwissen, Cheat-Sheets und originalgetreuen IHK-Operatoren.</p> <p style="margin: 0; color: #475569; font-size: 0.95rem; max-width: 780px;">Realistische Prüfungssimulation nach der neuen Ausbildungsordnung (AO 2020) für Fachinformatiker aller Fachrichtungen (FIAE, FISI, IT-SE, IT-SM).</p>
</div>
<div style="background: #f0fdf4; border: 1px solid #86efac; border-radius: 12px; padding: 12px 18px; text-align: center;">
<div style="font-size: 1.4rem; font-weight: 900; color: #166534;">100 Punkte</div>
<div style="font-size: 0.78rem; font-weight: 700; color: #15803d;">Offizieller Notenschlüssel 1–6</div>
</div> </div>
<button type="button" class="btn" style="background: #1d4ed8; color: white; padding: 10px 20px; font-weight: 800; border-radius: 8px; border: none; cursor: pointer;" onclick="window.openAuthModal('register', { allowClose: true, title: '🔒 Prüfungssimulation freischalten', message: 'Erstelle einen kostenlosen Account, um den 90-Minuten IHK-Prüfungstrainer mit automatischer Punkteberechnung zu starten.' })">
<span>🚀 Prüfungssimulation starten</span>
</button>
</div> </div>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 16px; margin-top: 12px;"> <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 18px; margin-top: 16px;">
<div style="background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 12px; padding: 18px;"> <div style="background: #ffffff; border: 1px solid #e2e8f0; border-radius: 12px; padding: 20px; box-shadow: var(--shadow-sm);">
<h4 style="margin: 0 0 6px 0; color: #1e3a8a; font-size: 1.05rem;">📘 AP1: IT-Arbeitsplatz (LF 1–8)</h4> <h4 style="margin: 0 0 6px 0; color: #1e3a8a; font-size: 1.05rem;">📘 AP1: IT-Arbeitsplatz (LF 1–8)</h4>
<p style="font-size: 0.84rem; color: #64748b; margin: 0 0 12px 0;">Gemeinsame Kernqualifikationen aller Fachinformatiker: Verträge, Ergonomie, Subnetting, BSI-Schutzbedarf, SQL, IoT &amp; Instandhaltung.</p> <p style="font-size: 0.86rem; color: #64748b; margin: 0 0 14px 0;">Gemeinsame Kernqualifikationen aller Fachinformatiker: Verträge, Ergonomie, IPv4/IPv6 Subnetting, BSI-Schutzbedarf, relationales SQL &amp; Trace-Tabellen.</p>
<a href="courses/ihk_ap1/01_lf1_unternehmen_und_arbeitsplatz/index.html" class="portal-btn-primary" style="font-size: 0.85rem; padding: 8px 16px;">AP1 Lehrplan &rarr;</a> <button type="button" class="portal-card-btn portal-card-action-btn locked" data-course-id="ihk_ap1" data-course-url="courses/ihk_ap1/01_lf1_unternehmen_und_arbeitsplatz/index.html" style="font-size: 0.84rem; padding: 8px 14px;">
<span>🔒 AP1 Lehrplan öffnen</span>
</button>
</div> </div>
<div style="background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 12px; padding: 18px;"> <div style="background: #ffffff; border: 1px solid #e2e8f0; border-radius: 12px; padding: 20px; box-shadow: var(--shadow-sm);">
<h4 style="margin: 0 0 6px 0; color: #991b1b; font-size: 1.05rem;">📕 AP2: Systemintegration (LF 9–12)</h4> <h4 style="margin: 0 0 6px 0; color: #991b1b; font-size: 1.05rem;">📕 AP2: Systemintegration (LF 9–12)</h4>
<p style="font-size: 0.84rem; color: #64748b; margin: 0 0 12px 0;">Fachrichtungsspezifisch: VLANs &amp; Routing, Active Directory, RAID &amp; SAN-Speicher, Virtualisierung, WiSo und 40h-Projektleitfaden.</p> <p style="font-size: 0.86rem; color: #64748b; margin: 0 0 14px 0;">Fachrichtungsspezifisch: VLANs &amp; Routing, Active Directory GPO, RAID &amp; SAN-Speicher, Virtualisierung, WiSo-Kompaktfragen &amp; 40h-Projektleitfaden.</p>
<a href="courses/ihk_ap2_fisi/01_lf9_netzwerke_und_dienste/index.html" class="portal-btn-primary" style="font-size: 0.85rem; padding: 8px 16px; background: linear-gradient(135deg, #dc2626, #b91c1c);">AP2 FISI Lehrplan &rarr;</a> <button type="button" class="portal-card-btn portal-card-action-btn locked" data-course-id="ihk_ap2_fisi" data-course-url="courses/ihk_ap2_fisi/01_lf9_netzwerke_und_dienste/index.html" style="font-size: 0.84rem; padding: 8px 14px;">
<span>🔒 AP2 FISI Lehrplan öffnen</span>
</button>
</div> </div>
<div style="background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 12px; padding: 18px;"> <div style="background: #ffffff; border: 1px solid #e2e8f0; border-radius: 12px; padding: 20px; box-shadow: var(--shadow-sm);">
<h4 style="margin: 0 0 6px 0; color: #0f172a; font-size: 1.05rem;">⚡ Praxis-Drilltrainer</h4> <h4 style="margin: 0 0 6px 0; color: #0f172a; font-size: 1.05rem;">⚡ Interaktive Drill-Trainer</h4>
<p style="font-size: 0.84rem; color: #64748b; margin: 0 0 12px 0;">Interaktiver Subnetting-Drill Generator, zeilenweiser Trace-Tabellen-Trainer und interaktives relationales SQL-Labor.</p> <p style="font-size: 0.86rem; color: #64748b; margin: 0 0 14px 0;">Blitzschnelles Rechnen: Subnetting-Drill Generator mit Live-Punktevergabe, schrittweise Trace-Tabellen-Simulation und relationale Abfrage-Validierung.</p>
<a href="courses/ihk_ap1/11_subnetting_drill_master/index.html" class="portal-btn-secondary" style="font-size: 0.85rem; padding: 8px 16px; background: white; color: #0f172a; border-color: #cbd5e1;">Subnetting-Drill &rarr;</a> <button type="button" class="portal-card-btn portal-card-action-btn locked" data-course-id="ihk_ap1" data-course-url="courses/ihk_ap1/11_subnetting_drill_master/index.html" style="font-size: 0.84rem; padding: 8px 14px;">
<span>🔒 Drill-Trainer öffnen</span>
</button>
</div> </div>
</div> </div>
</section> </section>
<!-- 5. BENTO FEATURE MATRIX (WARUM IT-PRAXISPORTAL?) --> <!-- 5. MONACO WEB-IDE SHOWCASE -->
<div style="text-align: center; margin: 64px 0 24px 0;"> <section class="card" id="features-ide" style="margin-top: 48px; border-radius: 16px; padding: 32px; background: #090d16; color: #f8fafc; border: 1px solid rgba(255,255,255,0.1);">
<div style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 20px;">
<div style="max-width: 640px;">
<span style="background: rgba(56, 189, 248, 0.15); color: #38bdf8; border: 1px solid rgba(56, 189, 248, 0.4); padding: 4px 10px; border-radius: 99px; font-size: 0.76rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.6px;">0 Min. Setup • Direkt im Browser</span>
<h3 style="font-size: 1.6rem; font-weight: 900; margin: 10px 0; color: #f8fafc;">💻 Monaco Web-IDE: Echte Entwickler-Erfahrung</h3>
<p style="color: #94a3b8; font-size: 0.92rem; line-height: 1.6; margin-bottom: 16px;">Vergiss mühsame Compiler-Installationen oder Treiberprobleme. Das IT-Praxisportal bringt den Original-Code-Editor von Microsoft VS Code direkt in deinen Webbrowser – mit Autovervollständigung, Syntax-Highlighting, Unittests und automatischem Cloud-Save.</p>
<div style="display: flex; gap: 10px; flex-wrap: wrap;">
<span style="background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.12); padding: 5px 10px; border-radius: 6px; font-size: 0.8rem;">⚡ Multi-Language Runner</span>
<span style="background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.12); padding: 5px 10px; border-radius: 6px; font-size: 0.8rem;">🧪 Automatisierte Unittests</span>
<span style="background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.12); padding: 5px 10px; border-radius: 6px; font-size: 0.8rem;">💡 Intelligente Fehleranalyse</span>
</div>
</div>
<div>
<button type="button" class="btn" style="background: #10b981; color: white; padding: 12px 24px; font-size: 0.95rem; font-weight: 800; border-radius: 8px; border: none; cursor: pointer; box-shadow: 0 4px 20px rgba(16, 185, 129, 0.3);" onclick="window.openAuthModal('register', { allowClose: true, title: '🔒 Web-IDE freischalten', message: 'Registriere dich kostenlos, um direkt im Browser mit der Monaco IDE zu programmieren.' })">
<span>✨ Account erstellen &amp; Web-IDE starten &rarr;</span>
</button>
</div>
</div>
</section>
<!-- 6. BENTO FEATURE MATRIX (WARUM IT-PRAXISPORTAL?) -->
<div style="text-align: center; margin: 64px 0 24px 0;" id="features">
<h2 style="font-size: 1.8rem; font-weight: 900; margin: 0 0 6px 0; color: #0f172a;">🛠️ Warum IT-Praxisportal?</h2> <h2 style="font-size: 1.8rem; font-weight: 900; margin: 0 0 6px 0; color: #0f172a;">🛠️ Warum IT-Praxisportal?</h2>
<p style="color: #64748b; margin: 0; font-size: 0.95rem;">Wissenschaftlich fundierte Didaktik, moderne Web-Technologien und zero Installation.</p> <p style="color: #64748b; margin: 0; font-size: 0.95rem;">Wissenschaftlich fundierte Didaktik, moderne Web-Technologien und zero lokale Installation.</p>
</div> </div>
<div class="bento-grid"> <div class="bento-grid">
<div class="bento-item"> <div class="bento-item">
<div style="font-size: 1.8rem; margin-bottom: 8px;">⚡</div> <div style="font-size: 1.8rem; margin-bottom: 8px;">⚡</div>
<h4>Monaco Web-IDE (VS Code)</h4> <h4>Monaco Web-IDE (VS Code)</h4>
<p>Gleicher professioneller Editor wie in Microsoft VS Code: Syntax-Highlighting, Autocomplete, Shortcuts und automatische Tests direkt im Browser.</p> <p>Gleicher professioneller Editor wie in Microsoft VS Code: Syntax-Highlighting, Autocomplete, Shortcuts und automatisierte Tests direkt im Browser.</p>
</div> </div>
<div class="bento-item"> <div class="bento-item">
<div style="font-size: 1.8rem; margin-bottom: 8px;">⏱️</div> <div style="font-size: 1.8rem; margin-bottom: 8px;">⏱️</div>
<h4>Realtime Prüfungssimulation</h4> <h4>Realtime Prüfungssimulation</h4>
<p>Echte Prüfungsbedingungen: 90 Minuten Countdown, 100 Punkte, dynamisch gemischte 150 IHK-Fragen und automatischer Notenrechner.</p> <p>Echte Prüfungsbedingungen: 90 Minuten Countdown, 100 Punkte, dynamisch gemischte 150 IHK-Fragen und automatischer Notenrechner nach IHK-Schlüssel.</p>
</div> </div>
<div class="bento-item"> <div class="bento-item">
<div style="font-size: 1.8rem; margin-bottom: 8px;">🏆</div> <div style="font-size: 1.8rem; margin-bottom: 8px;">🏆</div>
<h4>Gamification &amp; Zertifikate</h4> <h4>Gamification &amp; Zertifikate</h4>
<p>Sammle XP für bestandene Tests, halte deinen täglichen Lern-Streak und drucke nach Abschluss verifizierbare PDF-Zertifikate aus.</p> <p>Sammle XP für bestandene Tests, halte deinen täglichen Lern-Streak und drucke nach Abschluss verifizierbare PDF-Zertifikate für Bewerbungen aus.</p>
</div> </div>
<div class="bento-item"> <div class="bento-item">
<div style="font-size: 1.8rem; margin-bottom: 8px;">👨‍🏫</div> <div style="font-size: 1.8rem; margin-bottom: 8px;">🛡️</div>
<h4>Dozenten &amp; Klassen-Dashboard</h4> <h4>100% DSGVO &amp; Cloud-Sync</h4>
<p>Erstelle Schulklassen mit Invite-Codes. Verfolge den Fortschritt deiner Schüler in der Live-Matrix und inspiziere eingereichten Code.</p> <p>Gehostet in Deutschland, kein Third-Party Tracking und verschlüsselte Passwörter. Speichere deinen Fortschritt sicher in der Cloud.</p>
</div> </div>
</div> </div>
<!-- 6. GAMIFICATION PASS & ZERTIFIKATE BEREICH --> <!-- 7. ZIELGRUPPEN / FÜR WEN IST DAS PORTAL? -->
<section class="card" id="zertifikate" style="margin-top: 48px; border-radius: 16px; padding: 28px;"> <section class="card" style="margin-top: 48px; border-radius: 16px; padding: 32px; background: #ffffff;">
<div style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 14px; margin-bottom: 18px;"> <div style="text-align: center; margin-bottom: 28px;">
<div> <h3 style="font-size: 1.5rem; font-weight: 900; color: #0f172a; margin: 0 0 6px 0;">👥 Für wen ist das IT-Praxisportal?</h3>
<h3 style="margin: 0; font-size: 1.4rem; color: #0f172a;">🏆 Entwickler-Pass &amp; Zertifikate</h3> <p style="color: #64748b; margin: 0; font-size: 0.92rem;">Entwickelt von echten IHK-Dozenten und erfahrenen IT-Architekten.</p>
<p style="margin: 4px 0 0 0; color: #64748b; font-size: 0.88rem;">Generiere offizielle, personalisierte Abschlusszertifikate für deine Bewerbung oder Ausbildungsakte:</p>
</div>
<div style="display: flex; gap: 10px; align-items: center;">
<span style="font-weight: 700; color: #0284c7; font-size: 0.9rem;" id="portal-user-level">Level 1 (Code-Küken)</span>
<span style="background: #e0f2fe; color: #0369a1; padding: 4px 10px; border-radius: 99px; font-size: 0.82rem; font-weight: 700;" id="portal-user-xp">0 XP</span>
</div>
</div> </div>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 12px;"> <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 20px;">
<button type="button" class="btn" style="background: #2563eb;" onclick="if(window.openCertificate) window.openCertificate('ihk_ap1_master');">📜 Zertifikat: IHK AP1</button> <div style="background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 12px; padding: 22px;">
<button type="button" class="btn" style="background: #dc2626;" onclick="if(window.openCertificate) window.openCertificate('ihk_ap2_fisi');">📜 Zertifikat: IHK AP2 FISI</button> <div style="font-size: 1.6rem; margin-bottom: 8px;">👨‍💻</div>
<button type="button" class="btn" style="background: #16a34a;" onclick="if(window.openCertificate) window.openCertificate('bash_devops');">📜 Zertifikat: Linux DevOps</button> <h4 style="margin: 0 0 6px 0; color: #0f172a; font-size: 1.05rem;">Auszubildende Fachinformatiker</h4>
<button type="button" class="btn" style="background: #0284c7;" onclick="if(window.openCertificate) window.openCertificate('powershell_cloud');">📜 Zertifikat: PowerShell 7</button> <p style="font-size: 0.86rem; color: #64748b; margin: 0;">Der ideale Begleiter vom ersten Ausbildungstag bis zur Abschlussprüfung. Schließe Wissenslücken in Berufsschul-Lernfeldern mit praxisnahem Code.</p>
<button type="button" class="btn" style="background: #ea580c;" onclick="if(window.openCertificate) window.openCertificate('sql_analytics');">📜 Zertifikat: SQL Analytics</button> </div>
<button type="button" class="btn" style="background: #7c3aed;" onclick="if(window.openCertificate) window.openCertificate('master');">👑 Grandmaster-Zertifikat</button>
<div style="background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 12px; padding: 22px;">
<div style="font-size: 1.6rem; margin-bottom: 8px;">🎓</div>
<h4 style="margin: 0 0 6px 0; color: #0f172a; font-size: 1.05rem;">Umschüler &amp; Quereinsteiger</h4>
<p style="font-size: 0.86rem; color: #64748b; margin: 0;">Verständliche Didaktik ohne Vorwissen-Frust. Schritt-für-Schritt Subgoals bringen dich sicher durch technische Prüfungen und Job-Interviews.</p>
</div>
<div style="background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 12px; padding: 22px;">
<div style="font-size: 1.6rem; margin-bottom: 8px;">👨‍🏫</div>
<h4 style="margin: 0 0 6px 0; color: #0f172a; font-size: 1.05rem;">Berufsschulen &amp; Ausbilder</h4>
<p style="font-size: 0.86rem; color: #64748b; margin: 0;">Organisiere ganze Klassen mit Invite-Codes. Behalte die Live-Lernmatrix deiner Azubis im Blick und inspiziere abgegebenen Code im Dozenten-Dashboard.</p>
</div>
</div> </div>
</section> </section>
<!-- 8. HIGH-CONVERTING BOTTOM CTA BANNER -->
<section class="card" style="margin-top: 48px; border-radius: 16px; padding: 40px 24px; text-align: center; background: linear-gradient(135deg, #0284c7 0%, #1d4ed8 100%); color: white; box-shadow: var(--shadow-xl);">
<h2 style="font-size: 2rem; font-weight: 900; margin: 0 0 10px 0; color: white;">Bereit für echte IT-Praxis?</h2>
<p style="font-size: 1.05rem; opacity: 0.9; max-width: 650px; margin: 0 auto 24px auto;">
Erstelle jetzt deinen Account in weniger als 30 Sekunden. 100% kostenlos, keine Kreditkarte, kein Abonnement.
</p>
<button type="button" class="btn" style="background: #ffffff; color: #0284c7; padding: 12px 28px; font-size: 1rem; font-weight: 800; border-radius: 8px; border: none; cursor: pointer; box-shadow: 0 4px 20px rgba(0,0,0,0.2);" onclick="window.openAuthModal('register', { allowClose: true })">
<span>✨ Jetzt kostenlos registrieren &rarr;</span>
</button>
</section>
</main> </main>
<!-- 7. CLEAN FOOTER --> <!-- 9. CLEAN MARKETING FOOTER -->
<footer style="background: #0b0f19; color: #94a3b8; border-top: 1px solid rgba(255, 255, 255, 0.08); padding: 48px 24px;"> <footer style="background: #0b0f19; color: #94a3b8; border-top: 1px solid rgba(255, 255, 255, 0.08); padding: 48px 24px;">
<div class="portal-container" style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 20px;"> <div class="portal-container" style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 20px;">
<div style="display: flex; align-items: center; gap: 10px;"> <div style="display: flex; align-items: center; gap: 10px;">
@ -520,28 +641,25 @@
</div> </div>
<div> <div>
<div style="color: white; font-weight: 800; font-size: 1rem;">it-praxisportal.de</div> <div style="color: white; font-weight: 800; font-size: 1rem;">it-praxisportal.de</div>
<div style="font-size: 0.75rem; color: #64748b;">Version 1.0 Alpha &bull; Entwickelt für echte IT-Praxis</div> <div style="font-size: 0.75rem; color: #64748b;">Version 1.0 Alpha &bull; Die moderne Plattform für echte IT-Praxis</div>
</div> </div>
</div> </div>
<div style="display: flex; gap: 20px; font-size: 0.85rem;"> <div style="display: flex; gap: 20px; font-size: 0.85rem;">
<a href="#katalog" style="color: #94a3b8; text-decoration: none;">Kurse</a> <a href="#hero" style="color: #94a3b8; text-decoration: none;">Übersicht</a>
<a href="#katalog" style="color: #94a3b8; text-decoration: none;">13 Kurse</a>
<a href="#ihk-section" style="color: #94a3b8; text-decoration: none;">IHK Prüfung</a> <a href="#ihk-section" style="color: #94a3b8; text-decoration: none;">IHK Prüfung</a>
<a href="workspace.html?course=python" style="color: #94a3b8; text-decoration: none;">Monaco Web-IDE</a> <a href="#features-ide" style="color: #94a3b8; text-decoration: none;">Web-IDE</a>
<a href="teacher.html" style="color: #94a3b8; text-decoration: none;">Dozenten</a> <a href="teacher.html" style="color: #94a3b8; text-decoration: none;">Dozenten</a>
</div> </div>
<div style="font-size: 0.8rem; color: #64748b;"> <div style="font-size: 0.8rem; color: #64748b;">
🔒 100% DSGVO-konform (Client-Side WASM &amp; Offline-Modus) 🔒 100% DSGVO-konform &bull; Serverstandort Deutschland
</div> </div>
</div> </div>
</footer> </footer>
<!-- Scripts --> <!-- Scripts -->
<script src="assets/gamification_data.js"></script>
<script src="assets/gamification.js"></script>
<script src="assets/interpreter.js"></script>
<script src="assets/certificate.js"></script>
<script src="assets/app_auth.js"></script> <script src="assets/app_auth.js"></script>
<script> <script>
@ -551,8 +669,16 @@
if (element) element.classList.add('active'); if (element) element.classList.add('active');
const cards = document.querySelectorAll('.portal-card'); const cards = document.querySelectorAll('.portal-card');
const query = (document.getElementById('course-filter-input').value || '').toLowerCase().trim();
cards.forEach(card => { cards.forEach(card => {
if (category === 'all' || card.getAttribute('data-category') === category) { const cardCat = card.getAttribute('data-category');
const cardTitle = (card.getAttribute('data-title') || '').toLowerCase();
const matchesCategory = (category === 'all' || cardCat === category);
const matchesQuery = (!query || cardTitle.includes(query) || card.innerText.toLowerCase().includes(query));
if (matchesCategory && matchesQuery) {
card.style.display = 'flex'; card.style.display = 'flex';
} else { } else {
card.style.display = 'none'; card.style.display = 'none';
@ -560,36 +686,17 @@
}); });
} }
// Instant Search Input
const searchInput = document.getElementById('course-filter-input'); const searchInput = document.getElementById('course-filter-input');
if (searchInput) { if (searchInput) {
searchInput.addEventListener('input', (e) => { searchInput.addEventListener('input', () => {
const query = e.target.value.toLowerCase().trim(); const activeTab = document.querySelector('.portal-tab-pill.active');
const cards = document.querySelectorAll('.portal-card'); const activeCat = activeTab ? activeTab.getAttribute('onclick').match(/'([^']+)'/)[1] : 'all';
filterCourses(activeCat, activeTab);
cards.forEach(card => {
const text = (card.getAttribute('data-title') || '') + ' ' + card.innerText.toLowerCase();
if (query === '' || text.includes(query)) {
card.style.display = 'flex';
} else {
card.style.display = 'none';
}
});
}); });
} }
// Auth & Gamification State Sync
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
if (window.AUTH && window.AUTH.updateUI) { window.AUTH.updateUI();
window.AUTH.updateUI();
}
const user = window.AUTH ? window.AUTH.user : null;
if (user) {
const lvlEl = document.getElementById('portal-user-level');
const xpEl = document.getElementById('portal-user-xp');
if (lvlEl) lvlEl.innerText = `Level ${user.level || 1} (${user.role === 'teacher' ? 'Dozent' : 'Entwickler'})`;
if (xpEl) xpEl.innerText = `${user.xp || 0} XP`;
}
}); });
</script> </script>
</body> </body>