feat(ui): WCAG text contrast improvements and modern course & lesson navigation button system

This commit is contained in:
Alex Mueller 2026-09-13 12:16:42 +02:00
parent ec6fc53c81
commit dd43e98748
3 changed files with 790 additions and 22 deletions

View file

@ -7,6 +7,16 @@
(function () {
'use strict';
function escapeHtml(str) {
if (!str) return '';
return String(str)
.replace(/&/g, '&')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#039;');
}
function getRootPrefix() {
const scripts = document.querySelectorAll('script[src*="course_sidebar.js"]');
if (scripts.length > 0) {
@ -104,7 +114,7 @@
if (!window.AUTH) {
const authScript = document.createElement('script');
authScript.src = `${rootPrefix}assets/app_auth.js?v=2.1.0`;
authScript.src = `${rootPrefix}assets/app_auth.js?v=2.2.3`;
authScript.onload = () => proceed();
authScript.onerror = () => proceed();
document.head.appendChild(authScript);
@ -365,26 +375,425 @@
document.body.appendChild(mobileBtn);
}
// Workspace: Topbar "☰ Kapitel" Button einbinden
if (context.isWorkspace) {
// ==========================================================================
// 🧭 KURS- & MODUL-NAVIGATIONSSYSTEM (Keine langweiligen Hyperlinks!)
// ==========================================================================
const ORDERED_COURSE_KEYS = [
'python',
'bash',
'powershell',
'active_directory',
'git',
'dns_records',
'sql',
'html_css',
'javascript',
'java',
'csharp',
'cpp',
'go',
'rust',
'ihk_ap1',
'ihk_ap2_fisi'
];
const courseIdx = ORDERED_COURSE_KEYS.indexOf(context.courseId);
const prevCourseKey = courseIdx > 0 ? ORDERED_COURSE_KEYS[courseIdx - 1] : null;
const nextCourseKey = (courseIdx >= 0 && courseIdx < ORDERED_COURSE_KEYS.length - 1) ? ORDERED_COURSE_KEYS[courseIdx + 1] : null;
const prevCourse = prevCourseKey ? manifest[prevCourseKey] : null;
const nextCourse = nextCourseKey ? manifest[nextCourseKey] : null;
const allChapters = [];
(currentCourse.tracks || []).forEach(tr => {
(tr.chapters || []).forEach(ch => {
allChapters.push({
trackId: tr.id,
folder: ch.folder,
title: ch.title,
taskFile: ch.taskFile,
testFile: ch.testFile
});
});
});
const currentChapIdx = allChapters.findIndex(ch => ch.folder === context.chapterFolder);
const prevChapter = currentChapIdx > 0 ? allChapters[currentChapIdx - 1] : null;
const nextChapter = (currentChapIdx >= 0 && currentChapIdx < allChapters.length - 1) ? allChapters[currentChapIdx + 1] : null;
function buildTheoryUrl(cid, tid, folder) {
if (cid === 'python') {
return `${rootPrefix}${tid || 'lehrpfad_1_grundlagen'}/${folder}/index.html`;
}
return `${rootPrefix}courses/${cid}/${folder}/index.html`;
}
function buildFirstLessonTheoryUrl(cid, courseObj) {
if (!courseObj || !courseObj.tracks || !courseObj.tracks.length) return `${rootPrefix}dashboard.html`;
const t = courseObj.tracks[0];
const f = t.chapters && t.chapters.length ? t.chapters[0].folder : '';
if (!f) return `${rootPrefix}dashboard.html`;
return buildTheoryUrl(cid, t.id, f);
}
function buildWorkspaceUrl(cid, tid, folder) {
return `${rootPrefix}workspace.html?course=${encodeURIComponent(cid)}&track=${encodeURIComponent(tid || '')}&chapter=${encodeURIComponent(folder)}`;
}
function buildFirstLessonWorkspaceUrl(cid, courseObj) {
if (!courseObj || !courseObj.tracks || !courseObj.tracks.length) return `${rootPrefix}workspace.html`;
const t = courseObj.tracks[0];
const f = t.chapters && t.chapters.length ? t.chapters[0].folder : '';
return buildWorkspaceUrl(cid, t.id, f);
}
// 1. THEORIE-SEITEN: Prominente Navigationsleiste am Ende der Lerneinheit
function renderTheoryNavigator() {
const mainEl = document.querySelector('main.container') || document.querySelector('main') || document.querySelector('.container');
if (!mainEl) return;
const existingNav = document.getElementById('courseModuleNavigator');
if (existingNav) existingNav.remove();
// Legacy-Buttons ausblenden
const legacyActionDivs = mainEl.querySelectorAll('.card > div[style*="flex"]:last-child, main > div[style*="flex"]:last-child');
legacyActionDivs.forEach(div => {
if (div.querySelector('a[href*="workspace.html"]') || div.querySelector('a[href*="index.html"]')) {
div.style.display = 'none';
}
});
const nav = document.createElement('nav');
nav.className = 'course-module-navigator';
nav.id = 'courseModuleNavigator';
nav.setAttribute('aria-label', 'Kurs- und Modulnavigation');
// Linker Button (Vorheriges Modul oder Vorheriger Kurs)
let leftBtnHtml = '';
if (prevChapter) {
const prevUrl = buildTheoryUrl(context.courseId, prevChapter.trackId, prevChapter.folder);
leftBtnHtml = `
<a href="${prevUrl}" class="lesson-nav-btn lesson-nav-prev" title="Vorheriges Modul: ${escapeHtml(prevChapter.title)}">
<span class="nav-arrow">◀</span>
<span class="nav-text">
<span class="nav-subtitle">VORHERIGES MODUL</span>
<span class="nav-title">${escapeHtml(prevChapter.title)}</span>
</span>
</a>
`;
} else if (prevCourse) {
const prevCourseUrl = buildFirstLessonTheoryUrl(prevCourseKey, prevCourse);
leftBtnHtml = `
<a href="${prevCourseUrl}" class="lesson-nav-btn lesson-nav-course-prev" title="Vorheriger Kurs: ${escapeHtml(prevCourse.title)}">
<span class="nav-arrow">⏮</span>
<span class="nav-text">
<span class="nav-subtitle">VORHERIGER KURS</span>
<span class="nav-title">${escapeHtml(prevCourse.icon || '📚')} ${escapeHtml(prevCourse.title)}</span>
</span>
</a>
`;
} else {
leftBtnHtml = `
<a href="${rootPrefix}dashboard.html" class="lesson-nav-btn" style="opacity: 0.85;" title="Zurück zum Lern-Dashboard">
<span class="nav-arrow">🏠</span>
<span class="nav-text">
<span class="nav-subtitle">START</span>
<span class="nav-title">Zum Dashboard</span>
</span>
</a>
`;
}
// Mittlere Buttons (Dashboard & Web-IDE)
const ideUrl = buildWorkspaceUrl(context.courseId, currentTrackId, context.chapterFolder);
const centerHtml = `
<div class="lesson-nav-center">
<a href="${rootPrefix}dashboard.html" class="lesson-nav-btn lesson-nav-dashboard" title="Zurück zur Übersicht aller Kurse">
<span>🏠</span>
<span>Dashboard</span>
</a>
<a href="${ideUrl}" class="lesson-nav-btn lesson-nav-ide" title="Aufgabe interaktiv in der Web-IDE lösen">
<span>💻</span>
<span>In Web-IDE lösen →</span>
</a>
</div>
`;
// Rechter Button (Nächstes Modul oder Nächster Kurs)
let rightBtnHtml = '';
if (nextChapter) {
const nextUrl = buildTheoryUrl(context.courseId, nextChapter.trackId, nextChapter.folder);
rightBtnHtml = `
<a href="${nextUrl}" class="lesson-nav-btn lesson-nav-next" title="Nächstes Modul: ${escapeHtml(nextChapter.title)}">
<span class="nav-text">
<span class="nav-subtitle">NÄCHSTES MODUL</span>
<span class="nav-title">${escapeHtml(nextChapter.title)}</span>
</span>
<span class="nav-arrow">▶</span>
</a>
`;
} else if (nextCourse) {
const nextCourseUrl = buildFirstLessonTheoryUrl(nextCourseKey, nextCourse);
rightBtnHtml = `
<a href="${nextCourseUrl}" class="lesson-nav-btn lesson-nav-course-next" title="Nächster Kurs: ${escapeHtml(nextCourse.title)}">
<span class="nav-text">
<span class="nav-subtitle">NÄCHSTER KURS</span>
<span class="nav-title">${escapeHtml(nextCourse.icon || '🚀')} ${escapeHtml(nextCourse.title)}</span>
</span>
<span class="nav-arrow">⏭</span>
</a>
`;
} else {
rightBtnHtml = `
<a href="${rootPrefix}dashboard.html" class="lesson-nav-btn lesson-nav-course-next" title="Alle Kurse gemeistert!">
<span class="nav-text">
<span class="nav-subtitle">ABSCHLUSS</span>
<span class="nav-title">🎉 Kurs gemeistert!</span>
</span>
<span class="nav-arrow">🏆</span>
</a>
`;
}
nav.innerHTML = leftBtnHtml + centerHtml + rightBtnHtml;
mainEl.appendChild(nav);
}
// 2. WORKSPACE-PANE: Navigationsbuttons innerhalb des Theorie-Tabs der Web-IDE
function renderWorkspaceTheoryInlineNavigator() {
const theoriePane = document.getElementById('tab-content-theorie');
if (!theoriePane) return;
const existingPaneNav = theoriePane.querySelector('.course-module-navigator');
if (existingPaneNav) existingPaneNav.remove();
const legacyActionDivs = theoriePane.querySelectorAll('.card > div[style*="flex"]:last-child, div[style*="flex"]:last-child');
legacyActionDivs.forEach(div => {
if (div.querySelector('a[href*="workspace.html"]') || div.querySelector('a[href*="index.html"]')) {
div.style.display = 'none';
}
});
const paneNav = document.createElement('nav');
paneNav.className = 'course-module-navigator';
paneNav.style.marginTop = '28px';
paneNav.setAttribute('aria-label', 'Modulnavigation');
// Left
let leftHtml = '';
if (prevChapter) {
const prevWsUrl = buildWorkspaceUrl(context.courseId, prevChapter.trackId, prevChapter.folder);
leftHtml = `
<a href="${prevWsUrl}" class="lesson-nav-btn lesson-nav-prev" title="Vorheriges Modul: ${escapeHtml(prevChapter.title)}">
<span class="nav-arrow">◀</span>
<span class="nav-text">
<span class="nav-subtitle">VORHERIGES MODUL</span>
<span class="nav-title">${escapeHtml(prevChapter.title)}</span>
</span>
</a>
`;
} else if (prevCourse) {
const prevCourseWsUrl = buildFirstLessonWorkspaceUrl(prevCourseKey, prevCourse);
leftHtml = `
<a href="${prevCourseWsUrl}" class="lesson-nav-btn lesson-nav-course-prev" title="Vorheriger Kurs: ${escapeHtml(prevCourse.title)}">
<span class="nav-arrow">⏮</span>
<span class="nav-text">
<span class="nav-subtitle">VORHERIGER KURS</span>
<span class="nav-title">${escapeHtml(prevCourse.icon || '📚')} ${escapeHtml(prevCourse.title)}</span>
</span>
</a>
`;
} else {
leftHtml = `
<a href="${rootPrefix}dashboard.html" class="lesson-nav-btn" title="Zurück zum Lern-Dashboard">
<span class="nav-arrow">🏠</span>
<span class="nav-text">
<span class="nav-subtitle">START</span>
<span class="nav-title">Dashboard</span>
</span>
</a>
`;
}
// Center
const theoryFullUrl = buildTheoryUrl(context.courseId, currentTrackId, context.chapterFolder);
const centerHtml = `
<div class="lesson-nav-center">
<a href="${theoryFullUrl}" target="_blank" rel="noopener noreferrer" class="lesson-nav-btn lesson-nav-dashboard" title="Theorie in voller Seite lesen">
<span>📖</span>
<span>Vollbild-Theorie ↗</span>
</a>
</div>
`;
// Right
let rightHtml = '';
if (nextChapter) {
const nextWsUrl = buildWorkspaceUrl(context.courseId, nextChapter.trackId, nextChapter.folder);
rightHtml = `
<a href="${nextWsUrl}" class="lesson-nav-btn lesson-nav-next" title="Nächstes Modul: ${escapeHtml(nextChapter.title)}">
<span class="nav-text">
<span class="nav-subtitle">NÄCHSTES MODUL</span>
<span class="nav-title">${escapeHtml(nextChapter.title)}</span>
</span>
<span class="nav-arrow">▶</span>
</a>
`;
} else if (nextCourse) {
const nextCourseWsUrl = buildFirstLessonWorkspaceUrl(nextCourseKey, nextCourse);
rightHtml = `
<a href="${nextCourseWsUrl}" class="lesson-nav-btn lesson-nav-course-next" title="Nächster Kurs: ${escapeHtml(nextCourse.title)}">
<span class="nav-text">
<span class="nav-subtitle">NÄCHSTER KURS</span>
<span class="nav-title">${escapeHtml(nextCourse.icon || '🚀')} ${escapeHtml(nextCourse.title)}</span>
</span>
<span class="nav-arrow">⏭</span>
</a>
`;
} else {
rightHtml = `
<a href="${rootPrefix}dashboard.html" class="lesson-nav-btn lesson-nav-course-next" title="Alle Kurse gemeistert!">
<span class="nav-text">
<span class="nav-subtitle">ABSCHLUSS</span>
<span class="nav-title">🎉 Kurs gemeistert!</span>
</span>
<span class="nav-arrow">🏆</span>
</a>
`;
}
paneNav.innerHTML = leftHtml + centerHtml + rightHtml;
theoriePane.appendChild(paneNav);
}
// Global für dynamisches Nachladen in workspace.html bereitstellen
window.renderWorkspaceTheoryNavigator = renderWorkspaceTheoryInlineNavigator;
// 3. WORKSPACE: Topbar-Steuerleiste verdrahten
function renderWorkspaceNavigation() {
const topbarTitle = document.querySelector('.workspace-title');
if (topbarTitle && !document.getElementById('btn-toggle-chapter-drawer')) {
const toggleBtn = document.createElement('button');
if (!topbarTitle) return;
// 1. Drawer Button "☰ Kapitel"
let toggleBtn = document.getElementById('btn-toggle-chapter-drawer');
if (!toggleBtn) {
toggleBtn = document.createElement('button');
toggleBtn.type = 'button';
toggleBtn.id = 'btn-toggle-chapter-drawer';
toggleBtn.className = 'btn btn-secondary';
toggleBtn.style.cssText = 'font-size: 0.8rem; padding: 4px 10px; margin-right: 10px; display: inline-flex; align-items: center; gap: 6px; border: 1px solid rgba(255,255,255,0.18); background: rgba(255,255,255,0.08); color: #f8fafc; font-weight: 700; cursor: pointer; border-radius: 6px;';
toggleBtn.className = 'workspace-topbar-btn';
toggleBtn.innerHTML = '<span>☰</span> <span>Kapitel</span>';
toggleBtn.title = 'Kapitel-Drawer aufklappen';
toggleBtn.addEventListener('click', () => {
if (sidebar.classList.contains('open')) {
closeSidebar();
} else {
openSidebar();
}
});
toggleBtn.title = 'Kapitel-Übersicht aufklappen';
topbarTitle.insertBefore(toggleBtn, topbarTitle.firstChild);
}
toggleBtn.onclick = () => {
if (sidebar.classList.contains('open')) {
closeSidebar();
} else {
openSidebar();
}
};
// 2. Dashboard Button
let dashBtn = document.getElementById('btn-topbar-dashboard');
if (!dashBtn) {
dashBtn = document.createElement('a');
dashBtn.href = `${rootPrefix}dashboard.html`;
dashBtn.id = 'btn-topbar-dashboard';
dashBtn.className = 'workspace-topbar-btn';
dashBtn.innerHTML = '<span>🏠</span> <span>Dashboard</span>';
dashBtn.title = 'Zurück zum Lern-Dashboard';
toggleBtn.insertAdjacentElement('afterend', dashBtn);
}
// 3. Navigation Cluster
let navCluster = document.getElementById('workspace-nav-cluster');
if (!navCluster) {
navCluster = document.createElement('div');
navCluster.id = 'workspace-nav-cluster';
navCluster.className = 'workspace-nav-cluster';
navCluster.innerHTML = `
<button type="button" class="workspace-topbar-btn" id="btn-topbar-prev-course" title="Vorheriger Kurs">⏮ Kurs</button>
<button type="button" class="workspace-topbar-btn" id="btn-topbar-prev-chapter" title="Vorheriges Modul">◀ Zurück</button>
<span class="workspace-chapter-badge" id="workspace-chapter-badge">Modul - / -</span>
<button type="button" class="workspace-topbar-btn primary" id="btn-topbar-next-chapter" title="Nächstes Modul">Weiter ▶</button>
<button type="button" class="workspace-topbar-btn" id="btn-topbar-next-course" title="Nächster Kurs">Kurs ⏭</button>
`;
dashBtn.insertAdjacentElement('afterend', navCluster);
}
// Update Badge
const badge = document.getElementById('workspace-chapter-badge');
if (badge) {
const modNumber = currentChapIdx >= 0 ? currentChapIdx + 1 : 1;
badge.innerText = `MODUL ${modNumber} / ${allChapters.length || 16}`;
}
const btnPrevCourse = document.getElementById('btn-topbar-prev-course');
if (btnPrevCourse) {
if (prevCourseKey && prevCourse) {
btnPrevCourse.classList.remove('disabled');
btnPrevCourse.disabled = false;
btnPrevCourse.title = `Zum vorherigen Kurs: ${prevCourse.title}`;
btnPrevCourse.onclick = () => {
window.location.href = buildFirstLessonWorkspaceUrl(prevCourseKey, prevCourse);
};
} else {
btnPrevCourse.classList.add('disabled');
btnPrevCourse.disabled = true;
}
}
const btnPrevChap = document.getElementById('btn-topbar-prev-chapter');
if (btnPrevChap) {
if (prevChapter) {
btnPrevChap.classList.remove('disabled');
btnPrevChap.disabled = false;
btnPrevChap.title = `Vorheriges Modul: ${prevChapter.title}`;
btnPrevChap.onclick = () => {
window.location.href = buildWorkspaceUrl(context.courseId, prevChapter.trackId, prevChapter.folder);
};
} else {
btnPrevChap.classList.add('disabled');
btnPrevChap.disabled = true;
}
}
const btnNextChap = document.getElementById('btn-topbar-next-chapter');
if (btnNextChap) {
if (nextChapter) {
btnNextChap.classList.remove('disabled');
btnNextChap.disabled = false;
btnNextChap.title = `Nächstes Modul: ${nextChapter.title}`;
btnNextChap.onclick = () => {
window.location.href = buildWorkspaceUrl(context.courseId, nextChapter.trackId, nextChapter.folder);
};
} else {
btnNextChap.classList.add('disabled');
btnNextChap.disabled = true;
}
}
const btnNextCourse = document.getElementById('btn-topbar-next-course');
if (btnNextCourse) {
if (nextCourseKey && nextCourse) {
btnNextCourse.classList.remove('disabled');
btnNextCourse.disabled = false;
btnNextCourse.title = `Zum nächsten Kurs: ${nextCourse.title}`;
btnNextCourse.onclick = () => {
window.location.href = buildFirstLessonWorkspaceUrl(nextCourseKey, nextCourse);
};
} else {
btnNextCourse.classList.add('disabled');
btnNextCourse.disabled = true;
}
}
renderWorkspaceTheoryInlineNavigator();
}
if (context.isWorkspace) {
renderWorkspaceNavigation();
} else {
renderTheoryNavigator();
}
// Aktives Kapitel automatisch mittig in der Sidebar sichtbar scrollen

View file

@ -37,8 +37,8 @@
/* Typography */
--text-main: #0f172a;
--text-body: #334155;
--text-muted: #64748b;
--text-body: #1e293b;
--text-muted: #475569;
--text-inverse: #f8fafc;
--font-sans: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
@ -77,6 +77,17 @@ body {
padding: 0;
}
a {
color: #0284c7;
text-decoration: none;
font-weight: 600;
transition: color 0.15s ease, opacity 0.15s ease;
}
a:hover {
color: #0369a1;
}
/* ==========================================================================
APP LAYOUT (FLEX CONTAINER)
========================================================================== */
@ -276,7 +287,7 @@ header h1 {
header p {
font-size: 1.05rem;
color: #94a3b8;
color: #e2e8f0;
line-height: 1.55;
}
@ -2540,3 +2551,337 @@ body.workspace-page.has-course-sidebar {
}
}
/* ==========================================================================
📊 HIGH-CONTRAST TABLES & CHEATSHEETS
========================================================================== */
table {
width: 100%;
border-collapse: collapse;
font-size: 0.92rem;
margin: 16px 0;
text-align: left;
border: 1px solid var(--border-color);
border-radius: var(--radius-sm);
overflow: hidden;
background: var(--bg-surface);
}
thead {
background: var(--bg-subtle);
border-bottom: 2px solid var(--border-color);
}
th {
padding: 12px 16px;
font-weight: 800;
color: var(--text-main);
letter-spacing: 0.3px;
font-size: 0.88rem;
}
td {
padding: 12px 16px;
border-bottom: 1px solid var(--border-color);
color: var(--text-body);
line-height: 1.5;
vertical-align: middle;
}
tbody tr:last-child td {
border-bottom: none;
}
tbody tr:hover {
background: rgba(241, 245, 249, 0.6);
}
/* ==========================================================================
🎯 CHECKLISTS & TASK ITEMS
========================================================================== */
.task-item {
display: flex;
align-items: flex-start;
gap: 12px;
padding: 10px 14px;
margin-bottom: 8px;
background: #f8fafc;
border: 1px solid #e2e8f0;
border-radius: var(--radius-sm);
transition: background 0.15s ease, border-color 0.15s ease;
}
.task-item:hover {
background: #f1f5f9;
border-color: #cbd5e1;
}
.task-checkbox {
margin-top: 4px;
width: 18px;
height: 18px;
accent-color: var(--primary);
cursor: pointer;
flex-shrink: 0;
}
.task-label {
font-size: 0.94rem;
color: var(--text-main);
line-height: 1.5;
cursor: pointer;
flex: 1;
}
/* ==========================================================================
🧭 PREMIUM COURSE & LESSON NAVIGATOR COMPONENT
========================================================================== */
.course-module-navigator {
margin-top: 36px;
margin-bottom: 20px;
padding: 22px;
background: linear-gradient(180deg, #ffffff 0%, #f8fafc 100%);
border: 1px solid #cbd5e1;
border-radius: 16px;
box-shadow: 0 4px 20px -2px rgba(0, 0, 0, 0.06);
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 14px;
}
.lesson-nav-btn {
display: inline-flex;
align-items: center;
gap: 10px;
padding: 10px 18px;
border-radius: 10px;
font-weight: 700;
text-decoration: none !important;
font-size: 0.92rem;
transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
box-shadow: var(--shadow-sm);
cursor: pointer;
user-select: none;
}
.lesson-nav-btn:hover {
transform: translateY(-2px);
}
/* Vorheriger Schritt (Secondary Button Card) */
.lesson-nav-prev {
background: #ffffff;
color: #0f172a !important;
border: 1px solid #cbd5e1;
}
.lesson-nav-prev:hover {
background: #f1f5f9;
border-color: #94a3b8;
box-shadow: var(--shadow-md);
color: #0284c7 !important;
}
/* Nächster Schritt (Primary Glowing Button Card) */
.lesson-nav-next {
background: linear-gradient(135deg, #0284c7 0%, #1d4ed8 100%);
color: #ffffff !important;
border: 1px solid #0284c7;
box-shadow: 0 4px 14px rgba(2, 132, 199, 0.35);
}
.lesson-nav-next:hover {
background: linear-gradient(135deg, #0369a1 0%, #1e40af 100%);
box-shadow: 0 6px 20px rgba(2, 132, 199, 0.5);
color: #ffffff !important;
}
/* Kurs-Sprung Vorheriger Kurs */
.lesson-nav-course-prev {
background: #f8fafc;
color: #334155 !important;
border: 1px solid #cbd5e1;
}
.lesson-nav-course-prev:hover {
background: #e2e8f0;
border-color: #94a3b8;
color: #0f172a !important;
}
/* Kurs-Sprung Nächster Kurs (Emerald Accent) */
.lesson-nav-course-next {
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
color: #ffffff !important;
border: 1px solid #10b981;
box-shadow: 0 4px 14px rgba(16, 185, 129, 0.35);
}
.lesson-nav-course-next:hover {
background: linear-gradient(135deg, #059669 0%, #047857 100%);
box-shadow: 0 6px 20px rgba(16, 185, 129, 0.5);
color: #ffffff !important;
}
.lesson-nav-center {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: wrap;
}
.lesson-nav-dashboard {
background: #f1f5f9;
color: #334155 !important;
border: 1px solid #cbd5e1;
padding: 10px 16px;
font-size: 0.88rem;
}
.lesson-nav-dashboard:hover {
background: #e2e8f0;
color: #0f172a !important;
}
.lesson-nav-ide {
background: #10b981;
color: #ffffff !important;
border: 1px solid #059669;
padding: 10px 18px;
font-size: 0.88rem;
box-shadow: 0 4px 12px rgba(16, 185, 129, 0.3);
}
.lesson-nav-ide:hover {
background: #059669;
box-shadow: 0 6px 18px rgba(16, 185, 129, 0.45);
color: #ffffff !important;
}
.nav-text {
display: flex;
flex-direction: column;
text-align: left;
}
.nav-subtitle,
.nav-sub {
font-size: 0.72rem;
text-transform: uppercase;
letter-spacing: 0.5px;
opacity: 0.85;
}
.nav-title {
font-size: 0.9rem;
font-weight: 800;
white-space: nowrap;
max-width: 210px;
overflow: hidden;
text-overflow: ellipsis;
}
.lesson-nav-next .nav-text,
.lesson-nav-course-next .nav-text {
text-align: right;
}
.nav-arrow {
font-size: 1.15rem;
line-height: 1;
}
/* ==========================================================================
💻 WORKSPACE TOPBAR & NAVIGATION BUTTON CLUSTER
========================================================================== */
.workspace-nav-cluster {
display: inline-flex;
align-items: center;
gap: 6px;
margin-left: 8px;
}
.workspace-topbar-btn {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 5px 11px;
border-radius: 6px;
font-size: 0.82rem;
font-weight: 700;
color: #f1f5f9 !important;
background: rgba(255, 255, 255, 0.08);
border: 1px solid rgba(255, 255, 255, 0.18);
cursor: pointer;
text-decoration: none !important;
transition: all 0.15s ease;
white-space: nowrap;
}
.workspace-topbar-btn:hover {
background: rgba(255, 255, 255, 0.18);
color: #ffffff !important;
border-color: rgba(255, 255, 255, 0.35);
}
.workspace-topbar-btn.primary {
background: #0284c7;
border-color: #38bdf8;
color: #ffffff !important;
}
.workspace-topbar-btn.primary:hover {
background: #0369a1;
}
.workspace-topbar-btn.success {
background: #10b981;
border-color: #34d399;
color: #ffffff !important;
}
.workspace-topbar-btn.success:hover {
background: #059669;
}
.workspace-topbar-btn.disabled {
opacity: 0.35;
cursor: not-allowed;
pointer-events: none;
}
.workspace-chapter-badge {
display: inline-flex;
align-items: center;
padding: 2px 7px;
border-radius: 4px;
background: rgba(56, 189, 248, 0.18);
border: 1px solid rgba(56, 189, 248, 0.35);
color: #38bdf8;
font-size: 0.72rem;
font-weight: 800;
letter-spacing: 0.4px;
text-transform: uppercase;
}
@media (max-width: 900px) {
.course-module-navigator {
flex-direction: column;
align-items: stretch;
}
.lesson-nav-btn {
justify-content: center;
width: 100%;
box-sizing: border-box;
}
.lesson-nav-center {
justify-content: center;
width: 100%;
}
.lesson-nav-center .lesson-nav-btn {
flex: 1;
}
.nav-title {
max-width: 100%;
}
.workspace-nav-cluster #btn-topbar-prev-course,
.workspace-nav-cluster #btn-topbar-next-course {
display: none;
}
}

View file

@ -223,10 +223,21 @@
<!-- Topbar -->
<div class="workspace-topbar">
<div class="workspace-title">
<a href="dashboard.html" style="color: #94a3b8; text-decoration: none; font-size: 0.88rem;">🏠 Dashboard</a>
<span style="color: #64748b;">/</span>
<span id="workspace-chapter-name">Lerneinheit...</span>
<span id="editor-save-indicator" style="font-size: 0.75rem; color: #10b981; opacity: 0.5; margin-left: 10px;">💾 Gespeichert</span>
<button type="button" id="btn-toggle-chapter-drawer" class="workspace-topbar-btn" title="Kapitel-Übersicht öffnen">
<span>☰</span> <span>Kapitel</span>
</button>
<a href="dashboard.html" id="btn-topbar-dashboard" class="workspace-topbar-btn" title="Zurück zum Lern-Dashboard">
<span>🏠</span> <span>Dashboard</span>
</a>
<div class="workspace-nav-cluster" id="workspace-nav-cluster">
<button type="button" class="workspace-topbar-btn" id="btn-topbar-prev-course" title="Vorheriger Kurs">⏮ Kurs</button>
<button type="button" class="workspace-topbar-btn" id="btn-topbar-prev-chapter" title="Vorheriges Modul">◀ Zurück</button>
<span class="workspace-chapter-badge" id="workspace-chapter-badge">Modul - / -</span>
<button type="button" class="workspace-topbar-btn primary" id="btn-topbar-next-chapter" title="Nächstes Modul">Weiter ▶</button>
<button type="button" class="workspace-topbar-btn" id="btn-topbar-next-course" title="Nächster Kurs">Kurs ⏭</button>
</div>
<span id="workspace-chapter-name" style="font-size: 0.84rem; font-weight: 700; color: #f8fafc; margin-left: 6px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 260px;">Lerneinheit...</span>
<span id="editor-save-indicator" style="font-size: 0.75rem; color: #10b981; opacity: 0.7; margin-left: 8px;">💾 Gespeichert</span>
</div>
<div class="workspace-actions">
@ -524,6 +535,9 @@
const doc = parser.parseFromString(htmlDoc, "text/html");
const mainContent = doc.querySelector("main.container") || doc.body;
document.getElementById("tab-content-theorie").innerHTML = mainContent.innerHTML;
if (window.renderWorkspaceTheoryNavigator) {
window.renderWorkspaceTheoryNavigator();
}
}
// 2. Subgoals (Exakte Regex ohne Duplikate)