Adds Grounding, Reasoning-Modelle, Token/Parameter examples, an autocomplete mini-game, and a Copilot agent-building walkthrough with a live chat-demo payoff. Adds Sprecher.md with per-slide speaker cards. Fixes malformed data-def attributes and stray baked-in active/visible classes left over from in-browser edit-mode sessions, and stops the local save-in-place backups from being tracked.
270 lines
12 KiB
HTML
270 lines
12 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>CANCOM · Deck konfigurieren</title>
|
||
|
||
<link rel="preconnect" href="https://api.fontshare.com">
|
||
<link rel="stylesheet" href="https://api.fontshare.com/v2/css?f[]=general-sans@700,600,500&f[]=satoshi@700,500,400&f[]=jetbrains-mono@700,500,400&display=swap">
|
||
<script src="slides-manifest.js?v=2"></script>
|
||
|
||
<style>
|
||
:root {
|
||
--cancom-red: #E4002B;
|
||
--cancom-red-glow: rgba(228,0,43,0.55);
|
||
--cancom-red-dim: rgba(228,0,43,0.15);
|
||
--ink: #0A0A0F;
|
||
--ink-soft: #14141C;
|
||
--ink-line: #23232E;
|
||
--paper: #F5F5F2;
|
||
--paper-dim: rgba(245,245,242,0.6);
|
||
--paper-mute: rgba(245,245,242,0.35);
|
||
--font-display: 'General Sans', sans-serif;
|
||
--font-body: 'Satoshi', sans-serif;
|
||
--font-mono: 'JetBrains Mono', monospace;
|
||
--ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
|
||
}
|
||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||
html, body { background: var(--ink); color: var(--paper); font-family: var(--font-body); min-height: 100%; }
|
||
body { padding: 64px 64px 140px; max-width: 1100px; margin: 0 auto; }
|
||
|
||
.page-eyebrow {
|
||
font-family: var(--font-mono); font-size: 14px; letter-spacing: 0.28em; text-transform: uppercase;
|
||
color: var(--cancom-red); display: inline-flex; align-items: center; gap: 14px; margin-bottom: 20px;
|
||
}
|
||
.page-eyebrow::before { content: ""; width: 40px; height: 2px; background: var(--cancom-red); }
|
||
h1 {
|
||
font-family: var(--font-display); font-weight: 700; font-size: 48px; letter-spacing: -0.03em;
|
||
line-height: 1.1; margin-bottom: 14px;
|
||
}
|
||
.page-lead { font-size: 18px; color: var(--paper-dim); line-height: 1.5; max-width: 640px; margin-bottom: 40px; }
|
||
|
||
.toolbar {
|
||
position: sticky; top: 0; z-index: 50;
|
||
display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
|
||
background: rgba(10,10,15,0.9); backdrop-filter: blur(12px);
|
||
border: 1px solid var(--ink-line); border-radius: 14px;
|
||
padding: 18px 22px; margin-bottom: 36px;
|
||
}
|
||
.toolbar .count {
|
||
font-family: var(--font-mono); font-size: 14px; letter-spacing: 0.1em; color: var(--paper-mute);
|
||
margin-right: auto;
|
||
}
|
||
.toolbar .count strong { color: var(--paper); font-weight: 700; }
|
||
.btn {
|
||
font-family: var(--font-mono); font-size: 13px; letter-spacing: 0.08em; text-transform: uppercase;
|
||
padding: 12px 18px; border-radius: 8px; border: 1px solid var(--ink-line);
|
||
background: #0f0f16; color: var(--paper-dim); cursor: pointer;
|
||
transition: border-color 0.12s ease-out, color 0.12s ease-out, background 0.12s ease-out;
|
||
}
|
||
.btn:hover { border-color: var(--cancom-red); color: var(--paper); }
|
||
.btn.primary {
|
||
background: var(--cancom-red); border-color: var(--cancom-red); color: #fff; font-weight: 700;
|
||
box-shadow: 0 10px 30px var(--cancom-red-glow);
|
||
}
|
||
.btn.primary:hover { transform: translateY(-1px); }
|
||
|
||
.chapter { margin-bottom: 36px; }
|
||
.chapter-head {
|
||
display: flex; align-items: center; gap: 14px; margin-bottom: 14px;
|
||
font-family: var(--font-mono); font-size: 13px; letter-spacing: 0.18em; text-transform: uppercase;
|
||
color: var(--paper-mute);
|
||
}
|
||
.chapter-head .chapter-toggle-all {
|
||
margin-left: auto; font-size: 11px; color: var(--cancom-red); cursor: pointer; letter-spacing: 0.1em;
|
||
background: none; border: none; font-family: var(--font-mono); padding: 4px 8px;
|
||
}
|
||
.chapter-head .chapter-toggle-all:hover { text-decoration: underline; }
|
||
|
||
.row {
|
||
display: flex; align-items: center; gap: 18px;
|
||
padding: 16px 20px; border: 1px solid var(--ink-line); border-radius: 10px;
|
||
background: #0f0f16; margin-bottom: 10px;
|
||
transition: border-color 0.12s ease-out, background 0.12s ease-out;
|
||
}
|
||
.row:hover { border-color: rgba(228,0,43,0.35); background: #14141c; }
|
||
.row.divider-row { background: transparent; border-style: dashed; }
|
||
.row.locked { opacity: 0.55; }
|
||
|
||
.row input[type="checkbox"] {
|
||
appearance: none; width: 22px; height: 22px; flex-shrink: 0;
|
||
border: 1.5px solid var(--ink-line); border-radius: 6px; background: #0a0a0f;
|
||
cursor: pointer; position: relative; transition: border-color 0.12s ease-out, background 0.12s ease-out;
|
||
}
|
||
.row input[type="checkbox"]:checked { background: var(--cancom-red); border-color: var(--cancom-red); }
|
||
.row input[type="checkbox"]:checked::after {
|
||
content: ""; position: absolute; left: 7px; top: 3px; width: 5px; height: 10px;
|
||
border: solid #fff; border-width: 0 2px 2px 0; transform: rotate(45deg);
|
||
}
|
||
.row input[type="checkbox"]:disabled { cursor: not-allowed; }
|
||
|
||
.row .slide-id {
|
||
font-family: var(--font-mono); font-size: 13px; color: var(--paper-mute); width: 28px; flex-shrink: 0;
|
||
}
|
||
.row .slide-title { font-size: 17px; color: var(--paper); flex: 1; }
|
||
.row.divider-row .slide-title { color: var(--paper-mute); font-family: var(--font-mono); font-size: 13px; letter-spacing: 0.1em; text-transform: uppercase; }
|
||
.row .badge {
|
||
font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase;
|
||
color: var(--paper-mute); border: 1px solid var(--ink-line); border-radius: 20px; padding: 4px 10px;
|
||
}
|
||
|
||
.footer-bar {
|
||
position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
|
||
display: flex; justify-content: center; gap: 16px;
|
||
padding: 22px; background: linear-gradient(0deg, var(--ink) 60%, transparent);
|
||
}
|
||
.footer-bar .btn { padding: 16px 32px; font-size: 14px; }
|
||
|
||
.hint { font-size: 14px; color: var(--paper-mute); margin-top: -8px; margin-bottom: 30px; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<div class="page-eyebrow">Präsentations-Konfigurator</div>
|
||
<h1>Welche Slides sollen gezeigt werden?</h1>
|
||
<p class="page-lead">Häkchen entfernen blendet eine Slide für den Vortrag aus, ohne sie zu löschen. Die Auswahl wird lokal in diesem Browser gespeichert und beim nächsten Öffnen des Decks automatisch angewendet.</p>
|
||
|
||
<div class="toolbar">
|
||
<span class="count" id="count">– / – Slides aktiv</span>
|
||
<button class="btn" id="btnAll">Alle an</button>
|
||
<button class="btn" id="btnNone">Alle aus</button>
|
||
<button class="btn" id="btnReset">Zurücksetzen</button>
|
||
<button class="btn primary" id="btnOpen">Zur Präsentation →</button>
|
||
</div>
|
||
|
||
<div id="chapters"></div>
|
||
|
||
<div class="footer-bar">
|
||
<button class="btn primary" id="btnSaveBottom">Speichern & zur Präsentation →</button>
|
||
</div>
|
||
|
||
<script>
|
||
(function () {
|
||
const chaptersEl = document.getElementById('chapters');
|
||
const countEl = document.getElementById('count');
|
||
|
||
// Slides nach Kapitel gruppieren, Reihenfolge aus dem Manifest beibehalten
|
||
const groups = [];
|
||
const groupIndex = {};
|
||
SLIDE_MANIFEST.forEach((slide) => {
|
||
const key = slide.kapitel;
|
||
if (!(key in groupIndex)) {
|
||
groupIndex[key] = groups.length;
|
||
groups.push({ kapitel: key, slides: [] });
|
||
}
|
||
groups[groupIndex[key]].slides.push(slide);
|
||
});
|
||
|
||
const maxId = SLIDE_MANIFEST.length;
|
||
let enabled = loadSlideConfig();
|
||
// Veraltete Auswahl von einem Deck-Stand mit anderer Slide-Zahl verwerfen
|
||
// (die letzte Slide ist immer `locked` und muss daher immer enthalten sein).
|
||
if (enabled && !enabled.has(maxId)) {
|
||
enabled = null;
|
||
}
|
||
if (!enabled) {
|
||
enabled = new Set(SLIDE_MANIFEST.map((s) => s.id));
|
||
}
|
||
|
||
function render() {
|
||
chaptersEl.innerHTML = '';
|
||
groups.forEach((group) => {
|
||
const chapterDiv = document.createElement('div');
|
||
chapterDiv.className = 'chapter';
|
||
|
||
const head = document.createElement('div');
|
||
head.className = 'chapter-head';
|
||
head.innerHTML = '<span>' + group.kapitel + '</span>';
|
||
const toggleAllBtn = document.createElement('button');
|
||
toggleAllBtn.className = 'chapter-toggle-all';
|
||
toggleAllBtn.textContent = 'Kapitel an/aus';
|
||
toggleAllBtn.addEventListener('click', () => {
|
||
const toggleable = group.slides.filter((s) => !s.locked);
|
||
const allOn = toggleable.every((s) => enabled.has(s.id));
|
||
toggleable.forEach((s) => {
|
||
if (allOn) enabled.delete(s.id); else enabled.add(s.id);
|
||
});
|
||
render();
|
||
});
|
||
head.appendChild(toggleAllBtn);
|
||
chapterDiv.appendChild(head);
|
||
|
||
group.slides.forEach((slide) => {
|
||
const row = document.createElement('label');
|
||
row.className = 'row' + (slide.type === 'divider' ? ' divider-row' : '') + (slide.locked ? ' locked' : '');
|
||
|
||
const cb = document.createElement('input');
|
||
cb.type = 'checkbox';
|
||
cb.checked = enabled.has(slide.id);
|
||
cb.disabled = !!slide.locked;
|
||
cb.addEventListener('change', () => {
|
||
if (cb.checked) enabled.add(slide.id); else enabled.delete(slide.id);
|
||
updateCount();
|
||
});
|
||
|
||
const idEl = document.createElement('span');
|
||
idEl.className = 'slide-id';
|
||
idEl.textContent = String(slide.id).padStart(2, '0');
|
||
|
||
const titleEl = document.createElement('span');
|
||
titleEl.className = 'slide-title';
|
||
titleEl.textContent = slide.title;
|
||
|
||
row.appendChild(cb);
|
||
row.appendChild(idEl);
|
||
row.appendChild(titleEl);
|
||
|
||
if (slide.locked) {
|
||
const badge = document.createElement('span');
|
||
badge.className = 'badge';
|
||
badge.textContent = 'immer aktiv';
|
||
row.appendChild(badge);
|
||
} else if (slide.type === 'divider') {
|
||
const badge = document.createElement('span');
|
||
badge.className = 'badge';
|
||
badge.textContent = 'Kapitel-Trenner';
|
||
row.appendChild(badge);
|
||
}
|
||
|
||
chapterDiv.appendChild(row);
|
||
});
|
||
|
||
chaptersEl.appendChild(chapterDiv);
|
||
});
|
||
updateCount();
|
||
}
|
||
|
||
function updateCount() {
|
||
countEl.innerHTML = '<strong>' + enabled.size + '</strong> / ' + SLIDE_MANIFEST.length + ' Slides aktiv';
|
||
saveSlideConfig(enabled);
|
||
}
|
||
|
||
document.getElementById('btnAll').addEventListener('click', () => {
|
||
enabled = new Set(SLIDE_MANIFEST.map((s) => s.id));
|
||
render();
|
||
});
|
||
document.getElementById('btnNone').addEventListener('click', () => {
|
||
enabled = new Set(SLIDE_MANIFEST.filter((s) => s.locked).map((s) => s.id));
|
||
render();
|
||
});
|
||
document.getElementById('btnReset').addEventListener('click', () => {
|
||
enabled = new Set(SLIDE_MANIFEST.map((s) => s.id));
|
||
render();
|
||
});
|
||
function goToDeck() {
|
||
saveSlideConfig(enabled);
|
||
// localStorage wird bei file:// nicht zuverlässig zwischen Dateien geteilt (v. a. Safari) —
|
||
// die Auswahl deshalb zusätzlich als URL-Parameter mitgeben, das ist die verlässliche Quelle.
|
||
const ids = Array.from(enabled).sort((a, b) => a - b).join(',');
|
||
window.location.href = 'ki-verstehen.html?slides=' + encodeURIComponent(ids);
|
||
}
|
||
document.getElementById('btnOpen').addEventListener('click', goToDeck);
|
||
document.getElementById('btnSaveBottom').addEventListener('click', goToDeck);
|
||
|
||
render();
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|