852 lines
25 KiB
HTML
852 lines
25 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}Mindmap{% endblock %}
|
|
|
|
{% block extra_css %}
|
|
<style>
|
|
/* Full page background */
|
|
html, body {
|
|
min-height: 100vh;
|
|
width: 100%;
|
|
margin: 0;
|
|
padding: 0;
|
|
overflow-x: hidden;
|
|
}
|
|
|
|
/* Mindmap Container */
|
|
#mindmap-container {
|
|
position: relative;
|
|
min-height: calc(100vh - 160px);
|
|
z-index: 1;
|
|
}
|
|
|
|
/* Control Panel */
|
|
.control-panel {
|
|
position: fixed;
|
|
top: 100px;
|
|
left: 20px;
|
|
z-index: 10;
|
|
transition: all 0.3s ease;
|
|
border-radius: 1rem;
|
|
overflow: hidden;
|
|
border: 1px solid;
|
|
}
|
|
|
|
.dark .control-panel {
|
|
background-color: rgba(17, 24, 39, 0.8);
|
|
border-color: rgba(109, 40, 217, 0.3);
|
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
|
|
}
|
|
|
|
.control-panel {
|
|
background-color: rgba(255, 255, 255, 0.85);
|
|
border-color: rgba(139, 92, 246, 0.2);
|
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
/* Control Panel Toggle */
|
|
.panel-toggle {
|
|
position: absolute;
|
|
top: 8px;
|
|
right: 8px;
|
|
z-index: 2;
|
|
width: 30px;
|
|
height: 30px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
border-radius: 50%;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.dark .panel-toggle {
|
|
background-color: rgba(109, 40, 217, 0.2);
|
|
color: rgba(255, 255, 255, 0.8);
|
|
}
|
|
|
|
.panel-toggle {
|
|
background-color: rgba(139, 92, 246, 0.1);
|
|
color: rgba(30, 41, 59, 0.8);
|
|
}
|
|
|
|
.panel-toggle:hover {
|
|
transform: rotate(180deg);
|
|
}
|
|
|
|
/* Category Tree */
|
|
.category-tree {
|
|
max-height: 70vh;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.category-item {
|
|
transition: all 0.3s ease;
|
|
border-left: 2px solid transparent;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.dark .category-item:hover {
|
|
background-color: rgba(109, 40, 217, 0.1);
|
|
border-left-color: rgba(139, 92, 246, 0.5);
|
|
}
|
|
|
|
.category-item:hover {
|
|
background-color: rgba(139, 92, 246, 0.05);
|
|
border-left-color: rgba(139, 92, 246, 0.5);
|
|
}
|
|
|
|
/* Node List */
|
|
.node-list {
|
|
max-height: 300px;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.node-item {
|
|
transition: all 0.3s ease;
|
|
border-radius: 0.5rem;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.dark .node-item {
|
|
background-color: rgba(31, 41, 55, 0.5);
|
|
border: 1px solid rgba(55, 65, 81, 0.5);
|
|
}
|
|
|
|
.node-item {
|
|
background-color: rgba(255, 255, 255, 0.5);
|
|
border: 1px solid rgba(226, 232, 240, 0.5);
|
|
}
|
|
|
|
.dark .node-item:hover {
|
|
background-color: rgba(55, 65, 81, 0.7);
|
|
border-color: rgba(139, 92, 246, 0.5);
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
|
|
}
|
|
|
|
.node-item:hover {
|
|
background-color: rgba(255, 255, 255, 0.8);
|
|
border-color: rgba(139, 92, 246, 0.3);
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05);
|
|
}
|
|
|
|
/* Node Counter Badge */
|
|
.node-counter {
|
|
min-width: 20px;
|
|
height: 20px;
|
|
border-radius: 10px;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 0.75rem;
|
|
font-weight: 500;
|
|
padding: 0 6px;
|
|
}
|
|
|
|
.dark .node-counter {
|
|
background-color: rgba(109, 40, 217, 0.3);
|
|
color: rgba(255, 255, 255, 0.9);
|
|
}
|
|
|
|
.node-counter {
|
|
background-color: rgba(139, 92, 246, 0.1);
|
|
color: rgba(109, 40, 217, 0.9);
|
|
}
|
|
|
|
/* Canvas area */
|
|
#mindmap-canvas {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
overflow: hidden;
|
|
z-index: 1;
|
|
}
|
|
|
|
/* Tooltip */
|
|
.tooltip-container {
|
|
position: absolute;
|
|
pointer-events: none;
|
|
z-index: 1000;
|
|
max-width: 300px;
|
|
opacity: 0;
|
|
transition: opacity 0.3s ease;
|
|
}
|
|
|
|
.dark .tooltip-container {
|
|
background-color: rgba(17, 24, 39, 0.9);
|
|
border: 1px solid rgba(109, 40, 217, 0.3);
|
|
color: rgba(255, 255, 255, 0.9);
|
|
}
|
|
|
|
.tooltip-container {
|
|
background-color: rgba(255, 255, 255, 0.95);
|
|
border: 1px solid rgba(139, 92, 246, 0.2);
|
|
color: rgba(30, 41, 59, 0.9);
|
|
}
|
|
|
|
/* Search input */
|
|
.search-input {
|
|
transition: all 0.3s ease;
|
|
width: 100%;
|
|
border-radius: 0.5rem;
|
|
padding: 0.5rem 0.75rem;
|
|
outline: none;
|
|
}
|
|
|
|
.dark .search-input {
|
|
background-color: rgba(31, 41, 55, 0.7);
|
|
border: 1px solid rgba(55, 65, 81, 0.5);
|
|
color: rgba(255, 255, 255, 0.9);
|
|
}
|
|
|
|
.search-input {
|
|
background-color: rgba(255, 255, 255, 0.8);
|
|
border: 1px solid rgba(226, 232, 240, 0.8);
|
|
color: rgba(30, 41, 59, 0.9);
|
|
}
|
|
|
|
.dark .search-input:focus {
|
|
border-color: rgba(139, 92, 246, 0.5);
|
|
box-shadow: 0 0 0 2px rgba(139, 92, 246, 0.2);
|
|
}
|
|
|
|
.search-input:focus {
|
|
border-color: rgba(139, 92, 246, 0.3);
|
|
box-shadow: 0 0 0 2px rgba(139, 92, 246, 0.1);
|
|
}
|
|
|
|
/* Mode toggle */
|
|
.mode-toggle {
|
|
padding: 0.5rem 1rem;
|
|
border-radius: 0.5rem;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.dark .mode-toggle {
|
|
background-color: rgba(31, 41, 55, 0.5);
|
|
border: 1px solid rgba(55, 65, 81, 0.5);
|
|
color: rgba(255, 255, 255, 0.9);
|
|
}
|
|
|
|
.mode-toggle {
|
|
background-color: rgba(255, 255, 255, 0.7);
|
|
border: 1px solid rgba(226, 232, 240, 0.8);
|
|
color: rgba(30, 41, 59, 0.9);
|
|
}
|
|
|
|
.dark .mode-toggle.active {
|
|
background-color: rgba(109, 40, 217, 0.2);
|
|
border-color: rgba(139, 92, 246, 0.4);
|
|
color: rgba(255, 255, 255, 1);
|
|
}
|
|
|
|
.mode-toggle.active {
|
|
background-color: rgba(139, 92, 246, 0.1);
|
|
border-color: rgba(139, 92, 246, 0.3);
|
|
color: rgba(109, 40, 217, 1);
|
|
}
|
|
|
|
/* User Mindmaps */
|
|
.user-mindmap-section {
|
|
position: fixed;
|
|
bottom: 20px;
|
|
right: 20px;
|
|
z-index: 10;
|
|
transition: all 0.3s ease;
|
|
border-radius: 1rem;
|
|
overflow: hidden;
|
|
max-width: 350px;
|
|
}
|
|
|
|
.dark .user-mindmap-section {
|
|
background-color: rgba(17, 24, 39, 0.85);
|
|
border: 1px solid rgba(109, 40, 217, 0.3);
|
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
|
|
}
|
|
|
|
.user-mindmap-section {
|
|
background-color: rgba(255, 255, 255, 0.9);
|
|
border: 1px solid rgba(139, 92, 246, 0.2);
|
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
/* User Mindmap List */
|
|
.user-mindmap-item {
|
|
transition: all 0.3s ease;
|
|
border-radius: 0.5rem;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.dark .user-mindmap-item {
|
|
background-color: rgba(31, 41, 55, 0.5);
|
|
border: 1px solid rgba(55, 65, 81, 0.5);
|
|
}
|
|
|
|
.user-mindmap-item {
|
|
background-color: rgba(255, 255, 255, 0.7);
|
|
border: 1px solid rgba(226, 232, 240, 0.7);
|
|
}
|
|
|
|
.dark .user-mindmap-item:hover {
|
|
background-color: rgba(55, 65, 81, 0.7);
|
|
border-color: rgba(139, 92, 246, 0.4);
|
|
transform: translateY(-2px);
|
|
}
|
|
|
|
.user-mindmap-item:hover {
|
|
background-color: rgba(255, 255, 255, 0.9);
|
|
border-color: rgba(139, 92, 246, 0.3);
|
|
transform: translateY(-2px);
|
|
}
|
|
|
|
/* Zoom Controls */
|
|
.zoom-controls {
|
|
position: fixed;
|
|
bottom: 20px;
|
|
left: 20px;
|
|
z-index: 10;
|
|
display: flex;
|
|
gap: 0.5rem;
|
|
border-radius: 2rem;
|
|
padding: 0.5rem;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.dark .zoom-controls {
|
|
background-color: rgba(17, 24, 39, 0.7);
|
|
border: 1px solid rgba(55, 65, 81, 0.5);
|
|
}
|
|
|
|
.zoom-controls {
|
|
background-color: rgba(255, 255, 255, 0.8);
|
|
border: 1px solid rgba(226, 232, 240, 0.7);
|
|
}
|
|
|
|
.zoom-btn {
|
|
width: 36px;
|
|
height: 36px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
border-radius: 50%;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.dark .zoom-btn {
|
|
background-color: rgba(31, 41, 55, 0.7);
|
|
color: rgba(255, 255, 255, 0.9);
|
|
}
|
|
|
|
.zoom-btn {
|
|
background-color: rgba(255, 255, 255, 0.9);
|
|
color: rgba(30, 41, 59, 0.9);
|
|
}
|
|
|
|
.dark .zoom-btn:hover {
|
|
background-color: rgba(139, 92, 246, 0.3);
|
|
color: rgba(255, 255, 255, 1);
|
|
}
|
|
|
|
.zoom-btn:hover {
|
|
background-color: rgba(139, 92, 246, 0.1);
|
|
color: rgba(109, 40, 217, 1);
|
|
}
|
|
|
|
/* Loading spinner */
|
|
.spinner {
|
|
border: 3px solid rgba(255, 255, 255, 0.3);
|
|
border-radius: 50%;
|
|
border-top: 3px solid;
|
|
width: 24px;
|
|
height: 24px;
|
|
animation: spin 1s linear infinite;
|
|
}
|
|
|
|
.dark .spinner {
|
|
border-top-color: rgba(139, 92, 246, 0.7);
|
|
}
|
|
|
|
.spinner {
|
|
border-top-color: rgba(109, 40, 217, 0.7);
|
|
}
|
|
|
|
@keyframes spin {
|
|
0% { transform: rotate(0deg); }
|
|
100% { transform: rotate(360deg); }
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<!-- Mindmap Container -->
|
|
<div id="mindmap-container">
|
|
<!-- Main Canvas -->
|
|
<div id="mindmap-canvas"></div>
|
|
|
|
<!-- Control Panel -->
|
|
<div class="control-panel p-4 w-64" x-data="{ isExpanded: true }">
|
|
<div class="panel-toggle" @click="isExpanded = !isExpanded">
|
|
<i class="fa-solid" :class="isExpanded ? 'fa-chevron-left' : 'fa-chevron-right'"></i>
|
|
</div>
|
|
|
|
<div x-show="isExpanded">
|
|
<h2 class="text-xl font-semibold mb-4 text-gray-900 dark:text-white">Wissensbereiche</h2>
|
|
|
|
<!-- Search Box -->
|
|
<div class="mb-4">
|
|
<input type="text" id="category-search" class="search-input" placeholder="Bereich suchen...">
|
|
</div>
|
|
|
|
<!-- Category Tree -->
|
|
<div class="category-tree" id="category-tree">
|
|
<div id="categories-container" class="space-y-1">
|
|
<!-- Categories will be loaded dynamically -->
|
|
<div class="py-3 text-center text-gray-500 dark:text-gray-400" id="loading-categories">
|
|
<div class="spinner mx-auto mb-2"></div>
|
|
<p>Kategorien werden geladen...</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- View Mode Toggle -->
|
|
<div class="mt-4">
|
|
<h3 class="text-sm font-medium mb-2 text-gray-700 dark:text-gray-300">Ansicht</h3>
|
|
<div class="flex justify-between gap-2">
|
|
<button id="view-all" class="mode-toggle text-sm flex-1 active">
|
|
<i class="fa-solid fa-diagram-project mr-1"></i> Alles
|
|
</button>
|
|
<button id="view-focused" class="mode-toggle text-sm flex-1">
|
|
<i class="fa-solid fa-bullseye mr-1"></i> Fokus
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- User Mindmaps Section -->
|
|
{% if current_user.is_authenticated %}
|
|
<div class="user-mindmap-section p-4 w-64">
|
|
<div class="flex items-center justify-between mb-4">
|
|
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">Meine Mindmaps</h2>
|
|
<button @click="isExpanded = !isExpanded" class="text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200">
|
|
<i class="fa-solid" :class="isExpanded ? 'fa-chevron-down' : 'fa-chevron-up'"></i>
|
|
</button>
|
|
</div>
|
|
|
|
<div x-show="isExpanded">
|
|
<!-- User Mindmap List -->
|
|
<div class="space-y-2 max-h-60 overflow-y-auto mb-3">
|
|
<!-- Will be populated by JS -->
|
|
<div id="user-mindmaps-list" class="space-y-2">
|
|
<div class="py-3 text-center text-gray-500 dark:text-gray-400" id="loading-mindmaps">
|
|
<div class="spinner mx-auto mb-2"></div>
|
|
<p>Mindmaps werden geladen...</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Add New Mindmap Button -->
|
|
<a href="{{ url_for('create_mindmap') }}" class="mystical-button mystical-button-primary w-full text-center text-sm">
|
|
<i class="fa-solid fa-plus mr-1"></i> Neue Mindmap erstellen
|
|
</a>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Zoom Controls -->
|
|
<div class="zoom-controls">
|
|
<button id="zoom-in" class="zoom-btn">
|
|
<i class="fa-solid fa-plus"></i>
|
|
</button>
|
|
<button id="zoom-out" class="zoom-btn">
|
|
<i class="fa-solid fa-minus"></i>
|
|
</button>
|
|
<button id="reset-view" class="zoom-btn">
|
|
<i class="fa-solid fa-home"></i>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Node Tooltip -->
|
|
<div id="node-tooltip" class="tooltip-container rounded-lg p-4 shadow-lg"></div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block extra_js %}
|
|
<!-- D3.js for Mindmap Visualization -->
|
|
<script src="https://d3js.org/d3.v7.min.js"></script>
|
|
|
|
<!-- Custom D3 Extensions -->
|
|
<script src="{{ url_for('static', filename='d3-extensions.js') }}"></script>
|
|
|
|
<!-- Mindmap Visualisierungsmodul -->
|
|
<script src="{{ url_for('static', filename='js/modules/mindmap.js') }}"></script>
|
|
|
|
<script>
|
|
// Initialize the public mindmap
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
console.log('Mindmap-Seite wird initialisiert...');
|
|
|
|
// Prüfe, ob D3.js geladen ist
|
|
if (typeof d3 === 'undefined') {
|
|
console.error('D3.js Bibliothek ist nicht geladen!');
|
|
document.getElementById('mindmap-container').innerHTML =
|
|
'<div class="glass-effect p-6 text-center">' +
|
|
'<div class="text-red-500 mb-4">' +
|
|
'<i class="fa-solid fa-triangle-exclamation text-4xl"></i>' +
|
|
'</div>' +
|
|
'<p class="text-xl">D3.js konnte nicht geladen werden. Bitte laden Sie die Seite neu.</p>' +
|
|
'</div>';
|
|
return;
|
|
}
|
|
|
|
// Prüfe, ob MindMapVisualization geladen ist
|
|
if (typeof MindMapVisualization === 'undefined') {
|
|
console.error('MindMapVisualization-Klasse ist nicht geladen!');
|
|
document.getElementById('mindmap-container').innerHTML =
|
|
'<div class="glass-effect p-6 text-center">' +
|
|
'<div class="text-red-500 mb-4">' +
|
|
'<i class="fa-solid fa-triangle-exclamation text-4xl"></i>' +
|
|
'</div>' +
|
|
'<p class="text-xl">Die Mindmap-Visualisierung konnte nicht geladen werden. Bitte laden Sie die Seite neu.</p>' +
|
|
'</div>';
|
|
return;
|
|
}
|
|
|
|
// Set up for dark/light mode changes
|
|
const isDarkMode = document.documentElement.classList.contains('dark');
|
|
|
|
// Initialize the node tooltip
|
|
const tooltip = document.getElementById('node-tooltip');
|
|
|
|
try {
|
|
console.log('Erstelle MindMapVisualization...');
|
|
// Mindmap-Visualisierung initialisieren
|
|
const mindmap = new MindMapVisualization('#mindmap-canvas', {
|
|
height: document.getElementById('mindmap-container').clientHeight || 600,
|
|
tooltipEnabled: true,
|
|
onNodeClick: function(node) {
|
|
console.log('Knoten geklickt:', node);
|
|
}
|
|
});
|
|
|
|
// Speichere als globale Instanz für Zugriff über Buttons
|
|
window.mindmapInstance = mindmap;
|
|
|
|
// Lade die Mindmap-Daten
|
|
mindmap.loadData();
|
|
console.log('Mindmap-Visualisierung erfolgreich erstellt');
|
|
|
|
// View mode toggle
|
|
document.getElementById('view-all').addEventListener('click', function() {
|
|
this.classList.add('active');
|
|
document.getElementById('view-focused').classList.remove('active');
|
|
if (window.mindmapInstance && window.mindmapInstance.setViewMode) {
|
|
window.mindmapInstance.setViewMode('all');
|
|
}
|
|
});
|
|
|
|
document.getElementById('view-focused').addEventListener('click', function() {
|
|
this.classList.add('active');
|
|
document.getElementById('view-all').classList.remove('active');
|
|
if (window.mindmapInstance && window.mindmapInstance.setViewMode) {
|
|
window.mindmapInstance.setViewMode('focus');
|
|
}
|
|
});
|
|
|
|
// Zoom controls
|
|
document.getElementById('zoom-in').addEventListener('click', function() {
|
|
if (window.mindmapInstance) {
|
|
const svg = d3.select('#mindmap-container svg');
|
|
const currentZoom = d3.zoomTransform(svg.node());
|
|
const newScale = currentZoom.k * 1.3;
|
|
svg.transition().duration(300).call(
|
|
d3.zoom().transform,
|
|
d3.zoomIdentity.translate(currentZoom.x, currentZoom.y).scale(newScale)
|
|
);
|
|
}
|
|
});
|
|
|
|
document.getElementById('zoom-out').addEventListener('click', function() {
|
|
if (window.mindmapInstance) {
|
|
const svg = d3.select('#mindmap-container svg');
|
|
const currentZoom = d3.zoomTransform(svg.node());
|
|
const newScale = currentZoom.k / 1.3;
|
|
svg.transition().duration(300).call(
|
|
d3.zoom().transform,
|
|
d3.zoomIdentity.translate(currentZoom.x, currentZoom.y).scale(newScale)
|
|
);
|
|
}
|
|
});
|
|
|
|
document.getElementById('reset-view').addEventListener('click', function() {
|
|
if (window.mindmapInstance) {
|
|
const svg = d3.select('#mindmap-container svg');
|
|
svg.transition().duration(500).call(
|
|
d3.zoom().transform,
|
|
d3.zoomIdentity.scale(1)
|
|
);
|
|
}
|
|
});
|
|
|
|
// Handle dark mode toggle
|
|
document.addEventListener('darkModeToggled', function(event) {
|
|
const isDark = event.detail.isDark;
|
|
if (window.mindmapInstance && window.mindmapInstance.updateTheme) {
|
|
window.mindmapInstance.updateTheme(isDark);
|
|
}
|
|
});
|
|
|
|
// Load categories
|
|
loadCategories();
|
|
|
|
// Search functionality
|
|
const searchInput = document.getElementById('category-search');
|
|
if (searchInput) {
|
|
searchInput.addEventListener('input', function() {
|
|
const searchTerm = this.value.toLowerCase();
|
|
if (window.mindmapInstance && window.mindmapInstance.filterBySearchTerm) {
|
|
window.mindmapInstance.filterBySearchTerm(searchTerm);
|
|
}
|
|
|
|
// Filter categories in the sidebar
|
|
filterCategoriesInSidebar(searchTerm);
|
|
});
|
|
}
|
|
} catch (error) {
|
|
console.error('Fehler bei der Initialisierung der Mindmap:', error);
|
|
const errorContainer = document.getElementById('mindmap-container');
|
|
errorContainer.innerHTML = '<div class="glass-effect p-6 text-center">' +
|
|
'<div class="text-red-500 mb-4">' +
|
|
'<i class="fa-solid fa-triangle-exclamation text-4xl"></i>' +
|
|
'</div>' +
|
|
'<p class="text-xl">Fehler bei der Initialisierung der Mindmap:</p>' +
|
|
'<p class="text-md mt-2">' + (error.message || 'Unbekannter Fehler') + '</p>' +
|
|
'</div>';
|
|
}
|
|
});
|
|
|
|
// Kategorien laden
|
|
function loadCategories() {
|
|
const categoriesContainer = document.getElementById('categories-container');
|
|
const loadingElement = document.getElementById('loading-categories');
|
|
|
|
fetch('/api/categories')
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error('Kategorien konnten nicht geladen werden');
|
|
}
|
|
return response.json();
|
|
})
|
|
.then(categories => {
|
|
// Loading-Anzeige entfernen
|
|
if (loadingElement) {
|
|
loadingElement.remove();
|
|
}
|
|
|
|
// Kategorien rendern
|
|
renderCategories(categories, categoriesContainer);
|
|
})
|
|
.catch(error => {
|
|
console.error('Fehler beim Laden der Kategorien:', error);
|
|
if (loadingElement) {
|
|
loadingElement.innerHTML = `
|
|
<div class="text-red-500 mb-2">
|
|
<i class="fa-solid fa-exclamation-circle"></i>
|
|
</div>
|
|
<p>Fehler beim Laden der Kategorien</p>
|
|
`;
|
|
}
|
|
});
|
|
}
|
|
|
|
// Kategorien rekursiv rendern
|
|
function renderCategories(categories, container, level = 0) {
|
|
categories.forEach(category => {
|
|
const categoryElement = document.createElement('div');
|
|
categoryElement.className = 'category-item pl-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-700';
|
|
categoryElement.setAttribute('data-category-id', category.id);
|
|
categoryElement.style.marginLeft = level > 0 ? `${level * 12}px` : '0';
|
|
|
|
const hasChildren = category.children && category.children.length > 0;
|
|
const hasNodes = category.nodes && category.nodes.length > 0;
|
|
|
|
categoryElement.innerHTML = `
|
|
<div class="flex items-center justify-between">
|
|
<div class="flex items-center">
|
|
<i class="fa-solid fa-chevron-right mr-2 text-sm transition-transform ${hasChildren ? '' : 'opacity-0'}"></i>
|
|
<span>
|
|
<i class="fa-solid ${category.icon || 'fa-folder'} mr-2"></i>
|
|
${category.name}
|
|
</span>
|
|
</div>
|
|
<span class="node-counter">${hasNodes ? category.nodes.length : 0}</span>
|
|
</div>
|
|
`;
|
|
|
|
container.appendChild(categoryElement);
|
|
|
|
// Bereich für Knoten und Unterkategorien erstellen
|
|
const expandableArea = document.createElement('div');
|
|
expandableArea.className = 'hidden mt-2';
|
|
expandableArea.setAttribute('data-category-expand', category.id);
|
|
container.appendChild(expandableArea);
|
|
|
|
// Knoten für diese Kategorie anzeigen
|
|
if (hasNodes) {
|
|
const nodesContainer = document.createElement('div');
|
|
nodesContainer.className = 'node-list pl-4';
|
|
|
|
category.nodes.forEach(node => {
|
|
const nodeItem = document.createElement('div');
|
|
nodeItem.className = 'node-item p-2 mb-2';
|
|
nodeItem.style.borderLeft = `3px solid ${node.color_code || '#9F7AEA'}`;
|
|
nodeItem.setAttribute('data-node-id', node.id);
|
|
|
|
nodeItem.innerHTML = `
|
|
<div class="flex items-center justify-between">
|
|
<div>${node.name}</div>
|
|
<span class="node-counter">${node.thought_count || 0}</span>
|
|
</div>
|
|
`;
|
|
|
|
nodeItem.addEventListener('click', function(e) {
|
|
e.stopPropagation();
|
|
if (window.mindmapInstance && window.mindmapInstance.focusNode) {
|
|
window.mindmapInstance.focusNode(node.id);
|
|
}
|
|
});
|
|
|
|
nodesContainer.appendChild(nodeItem);
|
|
});
|
|
|
|
expandableArea.appendChild(nodesContainer);
|
|
}
|
|
|
|
// Unterkategorien rekursiv rendern
|
|
if (hasChildren) {
|
|
const childrenContainer = document.createElement('div');
|
|
childrenContainer.className = 'mt-2';
|
|
expandableArea.appendChild(childrenContainer);
|
|
|
|
renderCategories(category.children, childrenContainer, level + 1);
|
|
}
|
|
|
|
// Event-Listener für Aufklappen/Zuklappen
|
|
categoryElement.addEventListener('click', function() {
|
|
const expandArea = document.querySelector(`[data-category-expand="${category.id}"]`);
|
|
const chevron = this.querySelector('.fa-chevron-right');
|
|
|
|
if (expandArea) {
|
|
if (expandArea.classList.contains('hidden')) {
|
|
expandArea.classList.remove('hidden');
|
|
if (chevron) chevron.style.transform = 'rotate(90deg)';
|
|
} else {
|
|
expandArea.classList.add('hidden');
|
|
if (chevron) chevron.style.transform = 'rotate(0)';
|
|
}
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
// Categories filtering
|
|
function filterCategoriesInSidebar(searchTerm) {
|
|
if (!searchTerm) {
|
|
// Show all categories
|
|
document.querySelectorAll('.category-item').forEach(el => {
|
|
el.style.display = '';
|
|
});
|
|
return;
|
|
}
|
|
|
|
// Hide/show categories based on search
|
|
document.querySelectorAll('.category-item').forEach(el => {
|
|
const categoryName = el.querySelector('span').textContent.trim().toLowerCase();
|
|
if (categoryName.includes(searchTerm)) {
|
|
el.style.display = '';
|
|
|
|
// Show parent categories
|
|
let parent = el.parentElement;
|
|
while (parent && !parent.matches('#categories-container')) {
|
|
if (parent.hasAttribute('data-category-expand')) {
|
|
parent.classList.remove('hidden');
|
|
const parentId = parent.getAttribute('data-category-expand');
|
|
const parentCategory = document.querySelector(`[data-category-id="${parentId}"]`);
|
|
if (parentCategory) {
|
|
const chevron = parentCategory.querySelector('.fa-chevron-right');
|
|
if (chevron) chevron.style.transform = 'rotate(90deg)';
|
|
}
|
|
}
|
|
parent = parent.parentElement;
|
|
}
|
|
} else {
|
|
el.style.display = 'none';
|
|
}
|
|
});
|
|
}
|
|
</script>
|
|
|
|
{% if current_user.is_authenticated %}
|
|
<!-- Script für eingeloggte Benutzer -->
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Load user mindmaps
|
|
const mindmapsList = document.getElementById('user-mindmaps-list');
|
|
const loadingMindmaps = document.getElementById('loading-mindmaps');
|
|
|
|
fetch('/api/mindmap/user')
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error('Benutzer-Mindmaps konnten nicht geladen werden');
|
|
}
|
|
return response.json();
|
|
})
|
|
.then(data => {
|
|
if (!mindmapsList) return;
|
|
|
|
// Loading-Anzeige entfernen
|
|
if (loadingMindmaps) {
|
|
loadingMindmaps.remove();
|
|
}
|
|
|
|
if (data.length === 0) {
|
|
mindmapsList.innerHTML = '<div class="text-center text-gray-500 dark:text-gray-400 py-2">Keine Mindmaps gefunden</div>';
|
|
return;
|
|
}
|
|
|
|
// Mindmaps anzeigen
|
|
data.forEach(mindmap => {
|
|
const item = document.createElement('div');
|
|
item.className = 'user-mindmap-item p-3';
|
|
item.innerHTML = `
|
|
<div class="font-medium text-gray-800 dark:text-gray-200">${mindmap.name}</div>
|
|
<div class="text-xs text-gray-500 dark:text-gray-400 mb-2">${mindmap.description || ''}</div>
|
|
<a href="/my-mindmap/${mindmap.id}" class="text-purple-600 dark:text-purple-400 text-xs hover:underline">
|
|
<i class="fa-solid fa-arrow-right mr-1"></i> Öffnen
|
|
</a>
|
|
`;
|
|
mindmapsList.appendChild(item);
|
|
});
|
|
})
|
|
.catch(error => {
|
|
console.error('Fehler beim Laden der Benutzer-Mindmaps:', error);
|
|
if (loadingMindmaps) {
|
|
loadingMindmaps.innerHTML = `
|
|
<div class="text-red-500 mb-2">
|
|
<i class="fa-solid fa-exclamation-circle"></i>
|
|
</div>
|
|
<p>Fehler beim Laden der Mindmaps</p>
|
|
`;
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
{% endif %}
|
|
{% endblock %} |