Overhaul website to modernize design, integrate SVG visualizations, and enhance KI functionality; update documentation for MindMapProjekt.
This commit is contained in:
613
templates/mindmap.html
Normal file
613
templates/mindmap.html
Normal file
@@ -0,0 +1,613 @@
|
||||
{% 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" id="control-panel" 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">
|
||||
<!-- Recursive template for categories -->
|
||||
<script type="text/x-template" id="category-template">
|
||||
<div class="category-item pl-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-700"
|
||||
:class="[level > 0 ? 'ml-' + (level * 2) : '']"
|
||||
@click="toggleCategory(category.id)">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center">
|
||||
<i class="fa-solid" :class="[isExpanded ? 'fa-chevron-down' : 'fa-chevron-right', 'mr-2 text-sm transition-transform']"></i>
|
||||
<span :class="{'font-medium': isActive}">
|
||||
<i class="fa-solid mr-2" :class="category.icon || 'fa-folder'"></i>
|
||||
${category.name}
|
||||
</span>
|
||||
</div>
|
||||
<span class="node-counter">${category.nodes.length}</span>
|
||||
</div>
|
||||
<!-- Nodes for this category -->
|
||||
<div x-show="isExpanded && isActive" class="mt-2 node-list pl-4">
|
||||
<div v-for="node in category.nodes" class="node-item p-2 mb-2"
|
||||
:style="{ borderLeftColor: node.color_code }"
|
||||
@click.stop="addNodeToCanvas(node)">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>${node.name}</div>
|
||||
<span class="node-counter">${node.thought_count}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Subcategories recursive -->
|
||||
<div x-show="isExpanded" class="mt-2">
|
||||
<template v-for="child in category.children">
|
||||
<category-item :category="child" :level="level + 1"></category-item>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<!-- Root categories rendered here -->
|
||||
<div id="categories-container"></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" x-data="{ isExpanded: true }">
|
||||
<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>
|
||||
</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 Script -->
|
||||
<script src="{{ url_for('static', filename='mindmap.js') }}"></script>
|
||||
|
||||
<script>
|
||||
// Initialize the public mindmap
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Set up for dark/light mode changes
|
||||
const isDarkMode = document.documentElement.classList.contains('dark');
|
||||
|
||||
// Initialize the node tooltip
|
||||
const tooltip = document.getElementById('node-tooltip');
|
||||
|
||||
// Initialize mindmap
|
||||
const mindmap = new MindMap({
|
||||
container: '#mindmap-canvas',
|
||||
apiEndpoint: '/api/mindmap/public',
|
||||
isDarkMode: isDarkMode,
|
||||
tooltip: tooltip
|
||||
});
|
||||
|
||||
// Load public mindmap data
|
||||
mindmap.loadData().then(() => {
|
||||
console.log('Mindmap data loaded');
|
||||
});
|
||||
|
||||
// View mode toggle
|
||||
document.getElementById('view-all').addEventListener('click', function() {
|
||||
this.classList.add('active');
|
||||
document.getElementById('view-focused').classList.remove('active');
|
||||
mindmap.setViewMode('all');
|
||||
});
|
||||
|
||||
document.getElementById('view-focused').addEventListener('click', function() {
|
||||
this.classList.add('active');
|
||||
document.getElementById('view-all').classList.remove('active');
|
||||
mindmap.setViewMode('focus');
|
||||
});
|
||||
|
||||
// Zoom controls
|
||||
document.getElementById('zoom-in').addEventListener('click', function() {
|
||||
mindmap.zoomIn();
|
||||
});
|
||||
|
||||
document.getElementById('zoom-out').addEventListener('click', function() {
|
||||
mindmap.zoomOut();
|
||||
});
|
||||
|
||||
document.getElementById('reset-view').addEventListener('click', function() {
|
||||
mindmap.resetView();
|
||||
});
|
||||
|
||||
// Handle dark mode toggle
|
||||
document.addEventListener('darkModeToggled', function(event) {
|
||||
const isDark = event.detail.isDark;
|
||||
mindmap.updateTheme(isDark);
|
||||
});
|
||||
|
||||
// Search functionality
|
||||
const searchInput = document.getElementById('category-search');
|
||||
searchInput.addEventListener('input', function() {
|
||||
const searchTerm = this.value.toLowerCase();
|
||||
mindmap.searchCategories(searchTerm);
|
||||
});
|
||||
|
||||
{% if current_user.is_authenticated %}
|
||||
// Load user mindmaps
|
||||
fetch('/api/mindmap/user')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const mindmapsList = document.getElementById('user-mindmaps-list');
|
||||
mindmapsList.innerHTML = '';
|
||||
|
||||
if (data.length === 0) {
|
||||
mindmapsList.innerHTML = `
|
||||
<div class="text-center text-gray-500 dark:text-gray-400 py-2">
|
||||
Keine Mindmaps gefunden
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
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('Error loading user mindmaps:', error);
|
||||
});
|
||||
{% endif %}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user