claude-desktop/src/lib/components/AnimatedCode.svelte
Eddy 120715982b Phasen 12-15: Hooks, VSCodium-Bridge, Programm-Steuerung, Schulungsmodus
Phase 12 Hook-System (hooks.rs + HooksPanel):
- HookManager mit Event-Registry + Ausfuehrungs-Log
- 5 Built-in Hooks (SessionStart, PreToolUse, PostToolUse,
  BeforeCompacting, AfterCompacting)
- Tauri-Commands: list_hooks, set_hook_enabled, get_hook_executions, fire_hook
- HooksPanel.svelte mit Live-Ausfuehrungs-Log

Phase 13 VSCodium-Integration:
- vscode-extension/: WebSocket-Server auf Port 7890
  (Commands: openFile, goToLine, formatDocument, findInFiles,
   openTerminal, getStatus, executeCommand, ping)
- src-tauri/src/ide.rs: WebSocket-Client via tokio-tungstenite
- IdePanel.svelte: Status, Port-Konfig, Ping-Test, Live-Anzeige aktive Datei

Phase 14 Programm-Steuerung (programs.rs + ProgramsPanel):
- D-Bus: dbus_call + dbus_list_services
- Xvfb: start/stop/status + screenshot (scrot)
- Playwright-Info (MCP-Verweis)
- ProgramsPanel mit 4 Sektionen (VSCodium, Playwright, D-Bus, Xvfb)

Phase 15 Schulungsmodus (teaching.rs + presentation/+page.svelte):
- Separates Tauri-Webview-Fenster
- MermaidDiagram.svelte (dynamic import mermaid)
- AnimatedCode.svelte mit WPM-Steuerung
- Tauri-Commands: presentation_open/close/send_slide/clear
- 🎓-Button in der Titelbar
- Capabilities um core:webview:allow-create-webview-window erweitert

Deps:
- Cargo: +tokio-tungstenite 0.23, +futures-util 0.3
- npm: +mermaid ^11.4.0 (npm install erforderlich)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 19:10:41 +02:00

153 lines
2.9 KiB
Svelte

<script lang="ts">
import { onMount } from 'svelte';
interface Props {
code: string;
language?: string;
wpm?: number;
autoStart?: boolean;
}
let { code, language = 'text', wpm = 180, autoStart = true }: Props = $props();
let displayed = $state('');
let playing = $state(false);
let index = $state(0);
let timer: number | null = null;
function charDelay(): number {
// ~5 Zeichen pro Wort
return 60000 / (wpm * 5);
}
function play() {
if (playing) return;
playing = true;
step();
}
function pause() {
playing = false;
if (timer !== null) {
clearTimeout(timer);
timer = null;
}
}
function reset() {
pause();
displayed = '';
index = 0;
}
function step() {
if (!playing || index >= code.length) {
playing = false;
return;
}
displayed += code[index];
index++;
timer = window.setTimeout(step, charDelay());
}
function skipToEnd() {
pause();
displayed = code;
index = code.length;
}
onMount(() => {
if (autoStart) play();
return () => {
if (timer !== null) clearTimeout(timer);
};
});
</script>
<div class="animated-code">
<div class="toolbar">
<span class="lang">{language}</span>
<div class="controls">
{#if playing}
<button onclick={pause} title="Pause"></button>
{:else}
<button onclick={play} title="Abspielen"></button>
{/if}
<button onclick={reset} title="Zurücksetzen"></button>
<button onclick={skipToEnd} title="Zum Ende"></button>
<span class="speed">{wpm} WPM</span>
</div>
</div>
<pre class="code-block"><code>{displayed}{#if playing}<span class="cursor">|</span>{/if}</code></pre>
</div>
<style>
.animated-code {
background: var(--bg-secondary);
border-radius: var(--radius-sm);
overflow: hidden;
border: 1px solid var(--bg-tertiary);
}
.toolbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: var(--spacing-xs) var(--spacing-sm);
background: var(--bg-tertiary);
font-size: 0.78rem;
}
.lang {
color: var(--accent);
font-family: monospace;
font-weight: 600;
}
.controls {
display: flex;
gap: var(--spacing-xs);
align-items: center;
}
.controls button {
background: transparent;
border: 1px solid var(--bg-primary);
color: var(--text-primary);
padding: 2px 8px;
cursor: pointer;
border-radius: var(--radius-sm);
font-size: 0.85rem;
}
.controls button:hover {
background: var(--bg-primary);
}
.speed {
color: var(--text-secondary);
font-size: 0.72rem;
margin-left: var(--spacing-xs);
}
.code-block {
margin: 0;
padding: var(--spacing-md);
font-family: 'JetBrains Mono', 'Cascadia Code', monospace;
font-size: 0.85rem;
line-height: 1.5;
white-space: pre-wrap;
overflow-x: auto;
min-height: 60px;
max-height: 400px;
}
.cursor {
animation: blink 1s step-end infinite;
color: var(--accent);
}
@keyframes blink {
50% { opacity: 0; }
}
</style>