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:
parent
2571cb8847
commit
24e78444cf
5 changed files with 753 additions and 408 deletions
|
|
@ -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, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
return String(text)
|
||||||
|
.replace(/&/g, '&')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>')
|
||||||
|
.replace(/"/g, '"')
|
||||||
|
.replace(/'/g, ''');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
loginBtn.style.display = 'inline-flex';
|
||||||
|
loginBtn.innerText = '🔑 Anmelden';
|
||||||
|
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 (registerBtn) {
|
if (registerBtn) {
|
||||||
registerBtn.innerText = "Konto erstellen";
|
registerBtn.style.display = 'inline-flex';
|
||||||
registerBtn.onclick = () => window.openAuthModal("register");
|
registerBtn.innerText = '✨ Kostenlos registrieren';
|
||||||
|
registerBtn.style.background = '#0284c7';
|
||||||
|
registerBtn.onclick = () => window.openAuthModal('register', { allowClose: true });
|
||||||
}
|
}
|
||||||
if (teacherLink) teacherLink.style.display = "none";
|
if (heroPrimaryCta) {
|
||||||
if (soloModeBadge) soloModeBadge.style.display = "inline-block";
|
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>→</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 = document.createElement('div');
|
||||||
|
modal.id = 'auth-modal-overlay';
|
||||||
|
modal.className = 'certificate-overlay';
|
||||||
|
modal.style.zIndex = '99999';
|
||||||
|
|
||||||
modal.innerHTML = `
|
modal.innerHTML = `
|
||||||
<div class="certificate-container" style="max-width: 440px; padding: 28px; text-align: left;">
|
<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;">
|
||||||
<h3 id="auth-modal-title" style="margin-top: 0; font-size: 1.35rem; color: var(--text-main);">🔑 Anmelden</h3>
|
${allowClose ? `
|
||||||
<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>
|
<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>
|
||||||
|
` : ''}
|
||||||
|
|
||||||
<!-- 1-Klick Single-User Gast-Modus -->
|
<div style="display: flex; align-items: center; gap: 10px; margin-bottom: 14px;">
|
||||||
<div style="background: #f0fdf4; border: 1px solid #bbf7d0; border-radius: var(--radius-sm); padding: 12px; margin-bottom: 16px; text-align: center;">
|
<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>
|
||||||
<div style="font-weight: 700; color: #166534; font-size: 0.9rem; margin-bottom: 4px;">🚀 Single-User Modus (Sofort starten)</div>
|
<div>
|
||||||
<p style="font-size: 0.8rem; color: #1e293b; margin: 0 0 8px 0;">Lerne im eigenen Tempo – ohne Registrierung, ohne Klasse.</p>
|
<div style="font-size: 1.15rem; font-weight: 800; color: var(--text-main);" id="auth-modal-title">
|
||||||
<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 →</button>
|
${options.title || (initialMode === 'register' ? '✨ Kostenlos registrieren' : '🔑 Anmelden')}
|
||||||
|
</div>
|
||||||
|
<div style="font-size: 0.72rem; color: #64748b; font-weight: 700; text-transform: uppercase; letter-spacing: 0.6px;">IT-PRAXISPORTAL ACCREDITATION</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="text-align: center; color: #94a3b8; font-size: 0.8rem; margin: 12px 0; position: relative;">
|
<p id="auth-modal-desc" style="font-size: 0.88rem; color: var(--text-muted); margin-bottom: 18px; line-height: 1.5;">
|
||||||
<span style="background: white; padding: 0 10px; position: relative; z-index: 1;">ODER MIT KONTO</span>
|
${options.message || 'Erhalte sofortigen Zugriff auf 13 Praxis-Kurse, 216 interaktive Module, die Web-IDE und IHK AP1 & AP2 Prüfungsfragen.'}
|
||||||
<div style="position: absolute; top: 50%; left: 0; right: 0; height: 1px; background: #e2e8f0; z-index: 0;"></div>
|
</p>
|
||||||
|
|
||||||
|
<!-- 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>
|
</div>
|
||||||
|
|
||||||
<form id="auth-form" style="display: flex; flex-direction: column; gap: 12px;">
|
<form id="auth-form" style="display: flex; flex-direction: column; gap: 13px;">
|
||||||
<div id="auth-field-name" style="display: none;">
|
<div id="auth-field-name">
|
||||||
<label style="font-size: 0.82rem; font-weight: 700; color: var(--text-main);">Dein Name:</label>
|
<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: 8px 12px; border: 1px solid var(--border-color); border-radius: var(--radius-sm); font-size: 0.92rem;" placeholder="z.B. Alex Müller">
|
<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>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label style="font-size: 0.82rem; font-weight: 700; color: var(--text-main);">E-Mail-Adresse:</label>
|
<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: 8px 12px; border: 1px solid var(--border-color); border-radius: var(--radius-sm); font-size: 0.92rem;" placeholder="name@beispiel.de">
|
<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>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label style="font-size: 0.82rem; font-weight: 700; color: var(--text-main);">Passwort:</label>
|
<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: 8px 12px; border: 1px solid var(--border-color); border-radius: var(--radius-sm); font-size: 0.92rem;" placeholder="Mindestens 6 Zeichen">
|
<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>
|
||||||
|
|
||||||
<div id="auth-field-role" style="display: none;">
|
<div id="auth-field-role">
|
||||||
<label style="font-size: 0.82rem; font-weight: 700; color: var(--text-main);">Lern-Modus:</label>
|
<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: 8px 12px; border: 1px solid var(--border-color); border-radius: var(--radius-sm); font-size: 0.92rem;">
|
<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 (Eigenes Tempo, keine Klasse nötig)</option>
|
<option value="solo">🎓 Solo-Selbstlerner & Quereinsteiger</option>
|
||||||
<option value="student">🎒 Schüler (Teil einer Schulklasse)</option>
|
<option value="student">💼 Auszubildender Fachinformatiker (FIAE / FISI)</option>
|
||||||
<option value="teacher">👨🏫 Lehrkraft / Dozent (Klassen verwalten)</option>
|
<option value="teacher">👨🏫 Lehrkraft / Dozent / Ausbilder</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="auth-error-msg" style="color: var(--danger); font-size: 0.82rem; display: none;"></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="margin-top: 8px; justify-content: center;">Anmelden</button>
|
<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;">
|
||||||
<button type="button" class="btn btn-secondary" onclick="document.getElementById('auth-modal-overlay').remove();" style="justify-content: center;">Abbrechen</button>
|
Jetzt kostenlos registrieren →
|
||||||
|
</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;">
|
||||||
|
← 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>
|
</form>
|
||||||
|
|
||||||
<div style="margin-top: 14px; text-align: center; font-size: 0.84rem;">
|
<div style="margin-top: 14px; text-align: center; font-size: 0.76rem; color: #94a3b8;">
|
||||||
<a href="#" id="auth-toggle-mode" style="color: var(--primary); text-decoration: none; font-weight: 600;">Noch kein Konto? Jetzt registrieren →</a>
|
🔒 100% DSGVO-konform • Deutsche Server • Keine Kreditkarte erforderlich
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
document.body.appendChild(modal);
|
document.body.appendChild(modal);
|
||||||
}
|
|
||||||
|
|
||||||
const titleEl = document.getElementById("auth-modal-title");
|
let isRegister = (initialMode === 'register');
|
||||||
const nameField = document.getElementById("auth-field-name");
|
const tabReg = document.getElementById('auth-tab-register');
|
||||||
const roleField = document.getElementById("auth-field-role");
|
const tabLog = document.getElementById('auth-tab-login');
|
||||||
const submitBtn = document.getElementById("auth-submit-btn");
|
const nameField = document.getElementById('auth-field-name');
|
||||||
const toggleLink = document.getElementById("auth-toggle-mode");
|
const roleField = document.getElementById('auth-field-role');
|
||||||
const errorMsg = document.getElementById("auth-error-msg");
|
const submitBtn = document.getElementById('auth-submit-btn');
|
||||||
const form = document.getElementById("auth-form");
|
const errorBox = document.getElementById('auth-error-box');
|
||||||
|
const form = document.getElementById('auth-form');
|
||||||
|
|
||||||
let isRegister = mode === "register";
|
function switchMode(reg) {
|
||||||
|
isRegister = reg;
|
||||||
function updateModalMode() {
|
|
||||||
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 →";
|
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 →";
|
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 {
|
} else {
|
||||||
errorMsg.innerText = result.error || "Ein Fehler ist aufgetreten";
|
// Wenn auf der Startseite: UI aktualisieren
|
||||||
errorMsg.style.display = "block";
|
window.AUTH.updateUI();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
errorBox.innerText = result.error || 'Fehler bei der Authentifizierung';
|
||||||
|
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 });
|
||||||
|
}
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,7 @@
|
||||||
function initSidebar() {
|
function initSidebar() {
|
||||||
const rootPrefix = getRootPrefix();
|
const rootPrefix = getRootPrefix();
|
||||||
|
|
||||||
|
function proceed() {
|
||||||
if (!window.COURSES_MANIFEST) {
|
if (!window.COURSES_MANIFEST) {
|
||||||
const manifestScript = document.createElement('script');
|
const manifestScript = document.createElement('script');
|
||||||
manifestScript.src = `${rootPrefix}assets/courses_manifest.js`;
|
manifestScript.src = `${rootPrefix}assets/courses_manifest.js`;
|
||||||
|
|
@ -101,9 +102,29 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
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');
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
487
index.html
487
index.html
|
|
@ -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 & Software-Entwicklung</title>
|
<title>IT-Praxisportal | Die interaktive Lern- & 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 & IT-Ausbildung. 216+ Module, Monaco Web-IDE und IHK AP1 & AP2 Prüfungsvorbereitung im Browser.">
|
<meta name="description" content="IT-Praxisportal: Die interaktive Lernplattform für Fachinformatiker & IT-Entwickler. 216+ Module in 13 Schlüssel-Technologien, Monaco Web-IDE und IHK AP1 & 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++ & 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 & 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 & 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 & 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 & 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>↓</span>
|
</button>
|
||||||
|
<a href="#katalog" class="portal-btn-secondary">
|
||||||
|
<span>📚 Curriculum & Inhalte ansehen ↓</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 & AP2)</span>
|
<span>🎓 IHK AP1 & 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 & 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 & 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 & 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 & 90-Min Timer</div>
|
<div class="portal-stat-desc">AP1 & 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 & 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 & Tracks</h2>
|
<h2 style="font-size: 1.8rem; font-weight: 900; margin: 0 0 6px 0; color: #0f172a;">📚 Lehrplan & 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 & Sysadmin (2)</button>
|
<button type="button" class="portal-tab-pill" onclick="filterCourses('devops', this)">🐧 DevOps & Linux (2)</button>
|
||||||
<button type="button" class="portal-tab-pill" onclick="filterCourses('coding', this)">💻 Software & Coding (6)</button>
|
<button type="button" class="portal-tab-pill" onclick="filterCourses('coding', this)">💻 Backend & Systems (6)</button>
|
||||||
<button type="button" class="portal-tab-pill" onclick="filterCourses('data', this)">🗄️ Daten & Web (2)</button>
|
<button type="button" class="portal-tab-pill" onclick="filterCourses('data', this)">🗄️ Daten & 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 & Basissysteme</h3>
|
<h3 class="portal-card-title">IHK AP1: IT-Arbeitsplatz & 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 & 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 & 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 • 100 Pkt.</span>
|
<span class="portal-card-meta">⏱️ 12 Module • 100 Pkt.</span>
|
||||||
<a href="courses/ihk_ap1/01_lf1_unternehmen_und_arbeitsplatz/index.html" class="portal-card-btn">📘 AP1 Starten →</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 & 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 & 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 & 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 • 3 Simulationen</span>
|
<span class="portal-card-meta">⏱️ 9 Module • 3 Simulationen</span>
|
||||||
<a href="courses/ihk_ap2_fisi/01_lf9_netzwerke_und_dienste/index.html" class="portal-card-btn">📕 AP2 FISI Starten →</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 & Coding</span>
|
<span class="portal-card-badge badge-code">Software & 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 & 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 & 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 & Klassen</span>
|
<span class="portal-card-tag">OOP & 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 • 4 Lehrpfade</span>
|
<span class="portal-card-meta">⏱️ 35 Module • 4 Lehrpfade</span>
|
||||||
<a href="workspace.html?course=python&chapter=01_erste_schritte_taschenrechner" class="portal-card-btn">🐍 In Web-IDE →</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 & Sysadmin</span>
|
<span class="portal-card-badge badge-devops">DevOps & Cloud</span>
|
||||||
</div>
|
</div>
|
||||||
<h3 class="portal-card-title">Linux Bash, Shell Scripting & Cloud DevOps</h3>
|
<h3 class="portal-card-title">Linux Bash, Shell Scripting & Cloud DevOps</h3>
|
||||||
<p class="portal-card-desc">Praxisnahe Automatisierung: Streams & Redirection, awk/sed/jq Text Mining, Job-Control, Multithreading mit xargs/parallel, Systemd Services, Docker & 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 & BATS Unittests.</p>
|
||||||
<div class="portal-card-tags">
|
<div class="portal-card-tags">
|
||||||
<span class="portal-card-tag">Pipes & Streams</span>
|
<span class="portal-card-tag">I/O Redirection</span>
|
||||||
<span class="portal-card-tag">jq & 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 • 4 Lehrpfade</span>
|
<span class="portal-card-meta">⏱️ 16 Module • 4 Lehrpfade</span>
|
||||||
<a href="workspace.html?course=bash&chapter=01_navigation_dateien_und_globbing" class="portal-card-btn">🐧 In Web-IDE →</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 & Sysadmin</span>
|
<span class="portal-card-badge badge-devops">DevOps & Cloud</span>
|
||||||
</div>
|
</div>
|
||||||
<h3 class="portal-card-title">Modern PowerShell 7+ Core & 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 & Cloud Engine.</p>
|
<p class="portal-card-desc">Modernes Microsoft & Multi-Platform Scripting: Die Objekt-Pipeline, Custom PSCustomObjects, REST-APIs, moderne Parallelisierung mit <code>ForEach-Object -Parallel</code> & 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 • 4 Lehrpfade</span>
|
<span class="portal-card-meta">⏱️ 16 Module • 4 Lehrpfade</span>
|
||||||
<a href="workspace.html?course=powershell&chapter=01_powershell_konsole_und_cmdlet_architektur" class="portal-card-btn">🔷 In Web-IDE →</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 & Web</span>
|
<span class="portal-card-badge badge-data">Daten & Web</span>
|
||||||
</div>
|
</div>
|
||||||
<h3 class="portal-card-title">SQL & Data Analytics Master</h3>
|
<h3 class="portal-card-title">SQL & 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) & 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 & 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 & CTEs</span>
|
<span class="portal-card-tag">JOINs & 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 • 4 Lehrpfade</span>
|
<span class="portal-card-meta">⏱️ 16 Module • 4 Lehrpfade</span>
|
||||||
<a href="workspace.html?course=sql&chapter=01_tabellen_und_select" class="portal-card-btn">🗄️ In Web-IDE →</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 & Modernes TypeScript</h3>
|
<h3 class="portal-card-title">JavaScript & Modernes TypeScript</h3>
|
||||||
<p class="portal-card-desc">Moderne Web-Entwicklung: ES6+ Syntax, Klassen & OOP, Async/Await & 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 & OOP, Async/Await & 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+ & 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 • 4 Lehrpfade</span>
|
<span class="portal-card-meta">⏱️ 16 Module • 4 Lehrpfade</span>
|
||||||
<a href="workspace.html?course=javascript&chapter=01_erste_schritte_variablen" class="portal-card-btn">🌐 In Web-IDE →</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 • 4 Lehrpfade</span>
|
<span class="portal-card-meta">⏱️ 16 Module • 4 Lehrpfade</span>
|
||||||
<a href="workspace.html?course=java&chapter=01_java_syntax_und_primitive_typen" class="portal-card-btn">☕ In Web-IDE →</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 & Safety</h3>
|
<h3 class="portal-card-title">Rust Modern Systems & Safety</h3>
|
||||||
<p class="portal-card-desc">Zero-Cost Abstractions: Ownership & Borrowing, Lifetimes, Enums mit Option/Result, Traits, Smart Pointer (Box, Arc, Mutex), Fearless Concurrency & LRU-Cache Masterprojekt.</p>
|
<p class="portal-card-desc">Zero-Cost Abstractions: Ownership & Borrowing, Lifetimes, Enums mit Option/Result, Traits, Smart Pointer (Box, Arc, Mutex), Fearless Concurrency & 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<Mutex></span>
|
<span class="portal-card-tag">Arc<Mutex></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 • 4 Lehrpfade</span>
|
<span class="portal-card-meta">⏱️ 16 Module • 4 Lehrpfade</span>
|
||||||
<a href="workspace.html?course=rust&chapter=01_variablen_mutabilitaet_und_typen" class="portal-card-btn">🦀 In Web-IDE →</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 & Coding</span>
|
||||||
|
</div>
|
||||||
|
<h3 class="portal-card-title">Go Cloud Microservices & Concurrency</h3>
|
||||||
|
<p class="portal-card-desc">Entwickle hochskalierbare Cloud-Services mit Google Go: Goroutines, Channel-Pipelines, Mutex Synchronisation, Standard-HTTP-Server, Middleware & REST Microservice Master.</p>
|
||||||
|
<div class="portal-card-tags">
|
||||||
|
<span class="portal-card-tag">Goroutines</span>
|
||||||
|
<span class="portal-card-tag">Channels & 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 • 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 & Coding</span>
|
<span class="portal-card-badge badge-code">Software & Coding</span>
|
||||||
</div>
|
</div>
|
||||||
<h3 class="portal-card-title">C# 12 & Modernes .NET 8 Enterprise</h3>
|
<h3 class="portal-card-title">C# 12 & 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 & 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 & 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 • 4 Lehrpfade</span>
|
<span class="portal-card-meta">⏱️ 16 Module • 4 Lehrpfade</span>
|
||||||
<a href="workspace.html?course=csharp&chapter=01_syntax_datentypen_und_top_level_statements" class="portal-card-btn">💜 In Web-IDE →</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 & dynamischer Speicher, RAII, Klassen & Rule of Five, Templates, Smart Pointer (unique_ptr, shared_ptr), STL & GoogleTest.</p>
|
<p class="portal-card-desc">Das Fundament der Systemprogrammierung: Pointer & dynamischer Speicher, RAII, Klassen & Rule of Five, Templates, Smart Pointer (unique_ptr, shared_ptr), STL & GoogleTest.</p>
|
||||||
<div class="portal-card-tags">
|
<div class="portal-card-tags">
|
||||||
<span class="portal-card-tag">Pointer & Heap</span>
|
<span class="portal-card-tag">Pointer & 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 • 4 Lehrpfade</span>
|
<span class="portal-card-meta">⏱️ 16 Module • 4 Lehrpfade</span>
|
||||||
<a href="workspace.html?course=cpp&chapter=01_c_syntax_datentypen_und_io" class="portal-card-btn">⚙️ In Web-IDE →</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 & 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 & Dark Mode.</p>
|
||||||
<div class="portal-card-tags">
|
<div class="portal-card-tags">
|
||||||
<span class="portal-card-tag">Semantik & A11y</span>
|
<span class="portal-card-tag">Semantik & A11y</span>
|
||||||
<span class="portal-card-tag">Flexbox & Grid</span>
|
<span class="portal-card-tag">Flexbox & 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 • 4 Lehrpfade</span>
|
<span class="portal-card-meta">⏱️ 16 Module • 4 Lehrpfade</span>
|
||||||
<a href="workspace.html?course=html_css&chapter=01_semantisches_html_und_struktur" class="portal-card-btn">🎨 In Web-IDE →</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 & AP2 FISI)</h2>
|
<h3 style="margin: 8px 0 6px 0; font-size: 1.6rem; color: #1e3a8a; font-weight: 900;">🎓 IHK Prüfungstrainer AP1 & 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 & 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 & 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 →</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 & Routing, Active Directory, RAID & SAN-Speicher, Virtualisierung, WiSo und 40h-Projektleitfaden.</p>
|
<p style="font-size: 0.86rem; color: #64748b; margin: 0 0 14px 0;">Fachrichtungsspezifisch: VLANs & Routing, Active Directory GPO, RAID & SAN-Speicher, Virtualisierung, WiSo-Kompaktfragen & 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 →</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 →</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 & Web-IDE starten →</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 & Zertifikate</h4>
|
<h4>Gamification & 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 & Klassen-Dashboard</h4>
|
<h4>100% DSGVO & 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 & 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>
|
|
||||||
<button type="button" class="btn" style="background: #7c3aed;" onclick="if(window.openCertificate) window.openCertificate('master');">👑 Grandmaster-Zertifikat</button>
|
|
||||||
</div>
|
</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;">Umschüler & 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 & 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>
|
||||||
|
</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 →</span>
|
||||||
|
</button>
|
||||||
</section>
|
</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 • Entwickelt für echte IT-Praxis</div>
|
<div style="font-size: 0.75rem; color: #64748b;">Version 1.0 Alpha • 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 & Offline-Modus)
|
🔒 100% DSGVO-konform • 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>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue