Compare commits
3 Commits
10747a8336
...
e5f485d9d7
| Author | SHA1 | Date | |
|---|---|---|---|
| e5f485d9d7 | |||
| cf3fc09a63 | |||
| 7eb958f3c8 |
111
COMMON_ERRORS.md
111
COMMON_ERRORS.md
@@ -3,15 +3,20 @@
|
||||
- Implementierung von Content Security Policy (CSP) - UNTER KEINEN UMSTÄNDEN!
|
||||
- Implementierung von Cross-Site Request Forgery (CSRF) Schutz
|
||||
- Implementierung von Security Headers
|
||||
- Verwendung von TypeScript anstelle von JavaScript
|
||||
- Implementierung von OAuth oder anderen externen Authentifizierungsmethoden
|
||||
|
||||
# HÄUFIGE FEHLER:
|
||||
- Verwendung der falschen Datenbank (die korrekte ist: database/systades.db)
|
||||
- Falsche Pfadangaben bei statischen Dateien
|
||||
- Vergessen der deutschen Spracheinstellungen in Templates
|
||||
- Nicht beachten der vorhandenen Projektstruktur
|
||||
- Falsche Einbindung der Neural Network Background Animation
|
||||
- Verwendung von englischen Variablennamen in deutschen Funktionen
|
||||
- Vergessen der Mindmap-Datenstruktur gemäß der Roadmap
|
||||
|
||||
# Häufige Fehler und Lösungen
|
||||
|
||||
D
|
||||
## Content Security Policy (CSP)
|
||||
|
||||
### Problem: Externe Ressourcen werden nicht geladen
|
||||
@@ -29,6 +34,35 @@
|
||||
```html
|
||||
<link href="{{ url_for('static', filename='css/tailwind.min.css') }}" rel="stylesheet">
|
||||
```
|
||||
|
||||
### Problem: CSP-Fehler (script-src-elem 'none', font-src 'none', etc.)
|
||||
**Fehler:** Skripte werden aufgrund von CSP-Einschränkungen blockiert.
|
||||
|
||||
**Lösung:**
|
||||
1. WICHTIG: CSP-Einschränkungen NICHT implementieren! Diese sind im Projekt unerwünscht.
|
||||
|
||||
2. Falls CSP-Header bereits vorhanden sind, entfernen Sie diese aus der Anwendung:
|
||||
```python
|
||||
# Entfernen Sie diesen Code, falls vorhanden:
|
||||
# @app.after_request
|
||||
# def add_security_headers(response):
|
||||
# response.headers['Content-Security-Policy'] = '...'
|
||||
# return response
|
||||
```
|
||||
|
||||
3. Stellen Sie sicher, dass externe Ressourcen direkt geladen werden:
|
||||
```html
|
||||
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
||||
<script src="{{ url_for('static', filename='js/alpine.min.js') }}" defer></script>
|
||||
```
|
||||
|
||||
4. Für Inline-Skripte keine Nonce verwenden:
|
||||
```html
|
||||
<script>
|
||||
// Inline-JavaScript-Code ohne Einschränkungen
|
||||
</script>
|
||||
```
|
||||
|
||||
### Problem: Tailwind CSS CDN wird blockiert
|
||||
**Fehler:** Tailwind CSS kann nicht von CDN geladen werden.
|
||||
|
||||
@@ -62,3 +96,78 @@
|
||||
**Lösung:**
|
||||
1. Standard-Admin-Benutzer erstellen: `python TOOLS.py user:admin`
|
||||
2. Passwort zurücksetzen: `python TOOLS.py user:reset-pw -u USERNAME -p NEWPASSWORD`
|
||||
|
||||
## Neural Network Background
|
||||
|
||||
### Problem: Hintergrund-Animation wird nicht angezeigt
|
||||
**Fehler:** Die Neural Network Animation im Hintergrund erscheint nicht.
|
||||
|
||||
**Lösung:**
|
||||
1. Überprüfen Sie, ob die Datei `static/neural-network-background.js` korrekt eingebunden ist:
|
||||
```html
|
||||
<script src="{{ url_for('static', filename='neural-network-background.js') }}"></script>
|
||||
```
|
||||
|
||||
2. Initialisieren Sie die Animation im Template:
|
||||
```html
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const background = new NeuralNetworkBackground();
|
||||
background.initialize();
|
||||
background.animate();
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
3. Stellen Sie sicher, dass keine CSS-Regeln die Animation überdecken:
|
||||
```css
|
||||
#neural-network-background {
|
||||
z-index: -10;
|
||||
opacity: 1;
|
||||
}
|
||||
```
|
||||
|
||||
## Mindmap-Funktionalität
|
||||
|
||||
### Problem: Mindmap-Daten werden nicht geladen
|
||||
**Fehler:** Die dynamische Mindmap zeigt keine Daten an.
|
||||
|
||||
**Lösung:**
|
||||
1. Überprüfen Sie die API-Endpunkte für die Mindmap-Daten:
|
||||
```python
|
||||
@app.route('/api/mindmap/nodes', methods=['GET'])
|
||||
def get_mindmap_nodes():
|
||||
# Implementierung...
|
||||
```
|
||||
|
||||
2. Stellen Sie sicher, dass die AJAX-Anfragen korrekt implementiert sind:
|
||||
```javascript
|
||||
fetch('/api/mindmap/nodes')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
// Verarbeitung der Mindmap-Daten
|
||||
});
|
||||
```
|
||||
|
||||
3. Überprüfen Sie die Datenbankeinträge für Mindmap-Knoten und -Verbindungen.
|
||||
|
||||
## ChatGPT-Assistent
|
||||
|
||||
### Problem: Assistent reagiert nicht auf Eingaben
|
||||
**Fehler:** Der ChatGPT-Assistent verarbeitet keine Benutzereingaben.
|
||||
|
||||
**Lösung:**
|
||||
1. Überprüfen Sie die Einbindung der JavaScript-Datei:
|
||||
```html
|
||||
<script src="{{ url_for('static', filename='js/modules/chatgpt-assistant.js') }}"></script>
|
||||
```
|
||||
|
||||
2. Stellen Sie sicher, dass der Assistent korrekt initialisiert wird:
|
||||
```javascript
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const assistant = new ChatGPTAssistant();
|
||||
assistant.initialize();
|
||||
});
|
||||
```
|
||||
|
||||
3. Überprüfen Sie die API-Endpunkte für die Kommunikation mit dem Assistenten.
|
||||
Binary file not shown.
2
app.py
2
app.py
@@ -73,7 +73,7 @@ def inject_globals():
|
||||
'current_year': datetime.now().year
|
||||
}
|
||||
|
||||
# Kontext-Prozessor für alle Templates
|
||||
# Context-Prozessor für alle Templates
|
||||
@app.context_processor
|
||||
def inject_current_year():
|
||||
return {'current_year': datetime.now().year}
|
||||
|
||||
18
static/css/tailwind.min.css
vendored
18
static/css/tailwind.min.css
vendored
@@ -1,16 +1,6 @@
|
||||
/*
|
||||
* Tailwind CSS v3.4.16
|
||||
*
|
||||
* This is a placeholder file. For production, you should:
|
||||
* 1. Install Tailwind CSS as a PostCSS plugin: https://tailwindcss.com/docs/installation
|
||||
* 2. Run the Tailwind CLI to compile this file with your custom configuration
|
||||
* 3. Replace this file with the compiled CSS
|
||||
*
|
||||
* The actual file should be generated using:
|
||||
* npx tailwindcss -i ./src/input.css -o ./static/css/tailwind.min.css --minify
|
||||
/**
|
||||
* Failed to bundle using Rollup v2.79.2: the file imports a not supported node.js built-in module "fs".
|
||||
* If you believe this to be an issue with jsDelivr, and not with the package itself, please open an issue at https://github.com/jsdelivr/jsdelivr
|
||||
*/
|
||||
|
||||
/* Base Tailwind imports */
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
throw new Error('Failed to bundle using Rollup v2.79.2: the file imports a not supported node.js built-in module "fs". If you believe this to be an issue with jsDelivr, and not with the package itself, please open an issue at https://github.com/jsdelivr/jsdelivr');
|
||||
15
static/js/alpine.min.js
vendored
15
static/js/alpine.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -2,9 +2,6 @@
|
||||
* MindMap - Hauptdatei für globale JavaScript-Funktionen
|
||||
*/
|
||||
|
||||
// Import des ChatGPT-Assistenten
|
||||
import ChatGPTAssistant from './modules/chatgpt-assistant.js';
|
||||
|
||||
/**
|
||||
* Hauptmodul für die MindMap-Anwendung
|
||||
* Verwaltet die globale Anwendungslogik
|
||||
@@ -38,10 +35,12 @@ const MindMap = {
|
||||
console.log('MindMap-Anwendung wird initialisiert...');
|
||||
|
||||
// Initialisiere den ChatGPT-Assistenten
|
||||
if (typeof ChatGPTAssistant !== 'undefined') {
|
||||
const assistant = new ChatGPTAssistant();
|
||||
assistant.init();
|
||||
// Speichere als Teil von MindMap
|
||||
this.assistant = assistant;
|
||||
}
|
||||
|
||||
// Seiten-spezifische Initialisierer aufrufen
|
||||
if (this.currentPage && this.pageInitializers[this.currentPage]) {
|
||||
@@ -74,6 +73,12 @@ const MindMap = {
|
||||
try {
|
||||
console.log('Initialisiere Mindmap...');
|
||||
|
||||
// Prüfe, ob MindMapVisualization geladen ist
|
||||
if (typeof MindMapVisualization === 'undefined') {
|
||||
console.error('MindMapVisualization-Klasse ist nicht definiert!');
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialisiere die Mindmap
|
||||
const mindmap = new MindMapVisualization('#mindmap-container', {
|
||||
height: mindmapContainer.clientHeight || 600,
|
||||
@@ -227,6 +232,3 @@ const MindMap = {
|
||||
|
||||
// Globale Export für andere Module
|
||||
window.MindMap = MindMap;
|
||||
|
||||
// Export als Modul
|
||||
export default MindMap;
|
||||
@@ -568,5 +568,5 @@ class ChatGPTAssistant {
|
||||
}
|
||||
}
|
||||
|
||||
// Exportiere die Klasse für die Verwendung in anderen Modulen
|
||||
export default ChatGPTAssistant;
|
||||
// Mache die Klasse global verfügbar
|
||||
window.ChatGPTAssistant = ChatGPTAssistant;
|
||||
@@ -3,12 +3,18 @@
|
||||
* Spezifische Funktionen für die Mindmap-Seite
|
||||
*/
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Füge das Modul zum globalen MindMap-Objekt hinzu
|
||||
if (!window.MindMap) {
|
||||
window.MindMap = {};
|
||||
}
|
||||
|
||||
// Registriere den Initialisierer im MindMap-Objekt
|
||||
if (window.MindMap) {
|
||||
window.MindMap.pageInitializers = window.MindMap.pageInitializers || {};
|
||||
window.MindMap.pageInitializers.mindmap = initMindmapPage;
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Prüfe, ob wir auf der Mindmap-Seite sind und initialisiere
|
||||
if (document.body.dataset.page === 'mindmap') {
|
||||
initMindmapPage();
|
||||
@@ -461,13 +467,13 @@ function initMindmapPage() {
|
||||
|
||||
// Erfolgsbenachrichtigung
|
||||
if (window.MindMap && window.MindMap.showNotification) {
|
||||
MindMap.showNotification('Gedanke erfolgreich gespeichert.', 'success');
|
||||
window.MindMap.showNotification('Gedanke erfolgreich gespeichert.', 'success');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Speichern:', error);
|
||||
if (window.MindMap && window.MindMap.showNotification) {
|
||||
MindMap.showNotification('Fehler beim Speichern des Gedankens.', 'error');
|
||||
window.MindMap.showNotification('Fehler beim Speichern des Gedankens.', 'error');
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -483,7 +489,7 @@ function initMindmapPage() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeigt die Kommentare zu einem Gedanken an
|
||||
* Füge globale Funktionen für das Mindmap-Objekt hinzu
|
||||
*/
|
||||
window.showComments = async function(thoughtId) {
|
||||
try {
|
||||
@@ -505,7 +511,11 @@ window.showComments = async function(thoughtId) {
|
||||
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Laden der Kommentare:', error);
|
||||
MindMap.showNotification('Fehler beim Laden der Kommentare.', 'error');
|
||||
if (window.MindMap && window.MindMap.showNotification) {
|
||||
window.MindMap.showNotification('Fehler beim Laden der Kommentare.', 'error');
|
||||
} else {
|
||||
alert('Fehler beim Laden der Kommentare.');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -532,7 +542,11 @@ window.showRelations = async function(thoughtId) {
|
||||
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Laden der Beziehungen:', error);
|
||||
MindMap.showNotification('Fehler beim Laden der Beziehungen.', 'error');
|
||||
if (window.MindMap && window.MindMap.showNotification) {
|
||||
window.MindMap.showNotification('Fehler beim Laden der Beziehungen.', 'error');
|
||||
} else {
|
||||
alert('Fehler beim Laden der Beziehungen.');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -14,9 +14,11 @@
|
||||
<meta name="keywords" content="systades, wissen, visualisierung, lernen, gedanken, theorie">
|
||||
<meta name="author" content="Systades-Team">
|
||||
|
||||
<!-- Tailwind CSS - CDN Version -->
|
||||
<script src="https://cdn.tailwindcss.com" nonce="{{ csp_nonce }}"></script>
|
||||
<script nonce="{{ csp_nonce }}">
|
||||
<!-- Tailwind CSS - Beide Optionen verfügbar -->
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<!-- Alternative lokale Version, falls die CDN-Version blockiert wird -->
|
||||
<link href="{{ url_for('static', filename='css/tailwind.min.css') }}" rel="stylesheet">
|
||||
<script>
|
||||
tailwind.config = {
|
||||
darkMode: 'class',
|
||||
theme: {
|
||||
@@ -79,88 +81,32 @@
|
||||
<!-- Base-Styles ausgelagert in eigene Datei -->
|
||||
<link href="{{ url_for('static', filename='css/base-styles.css') }}" rel="stylesheet">
|
||||
|
||||
<!-- Alpine.js - Self-hosted -->
|
||||
<script src="{{ url_for('static', filename='js/alpine.min.js') }}" defer nonce="{{ csp_nonce }}"></script>
|
||||
<!-- Alpine.js - CDN Version -->
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.12.3/dist/cdn.min.js"></script>
|
||||
|
||||
<!-- Neural Network Background CSS -->
|
||||
<link href="{{ url_for('static', filename='css/neural-network-background.css') }}" rel="stylesheet">
|
||||
|
||||
<!-- D3.js für Visualisierungen -->
|
||||
<script src="https://d3js.org/d3.v7.min.js"></script>
|
||||
|
||||
<!-- Marked.js für Markdown-Parsing -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
||||
|
||||
<!-- ChatGPT Assistant -->
|
||||
<script src="{{ url_for('static', filename='js/modules/chatgpt-assistant.js') }}"></script>
|
||||
|
||||
<!-- MindMap Visualization Module -->
|
||||
<script src="{{ url_for('static', filename='js/modules/mindmap.js') }}"></script>
|
||||
|
||||
<!-- MindMap Page Module -->
|
||||
<script src="{{ url_for('static', filename='js/modules/mindmap-page.js') }}"></script>
|
||||
|
||||
<!-- Neural Network Background Script -->
|
||||
<script src="{{ url_for('static', filename='neural-network-background.js') }}" nonce="{{ csp_nonce }}"></script>
|
||||
<script src="{{ url_for('static', filename='neural-network-background.js') }}"></script>
|
||||
|
||||
<!-- Hauptmodul laden (als ES6 Modul) -->
|
||||
<script type="module" nonce="{{ csp_nonce }}">
|
||||
import MindMap from "{{ url_for('static', filename='js/main.js') }}";
|
||||
// Alpine.js-Integration
|
||||
document.addEventListener('alpine:init', () => {
|
||||
Alpine.data('layout', () => ({
|
||||
darkMode: true, // Default to dark mode
|
||||
mobileMenuOpen: false, // Mobile Menü standardmäßig geschlossen
|
||||
userMenuOpen: false,
|
||||
showSettingsModal: false,
|
||||
|
||||
init() {
|
||||
this.fetchDarkModeFromSession();
|
||||
},
|
||||
|
||||
fetchDarkModeFromSession() {
|
||||
// Lade den Dark Mode-Status vom Server
|
||||
fetch('/api/get_dark_mode')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
this.darkMode = data.darkMode === 'true';
|
||||
document.querySelector('html').classList.toggle('dark', this.darkMode);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Fehler beim Laden der Dark Mode-Einstellung:', error);
|
||||
});
|
||||
},
|
||||
|
||||
toggleDarkMode() {
|
||||
this.darkMode = !this.darkMode;
|
||||
document.querySelector('html').classList.toggle('dark', this.darkMode);
|
||||
|
||||
// Speichere den Dark Mode-Status auf dem Server
|
||||
fetch('/api/set_dark_mode', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ darkMode: this.darkMode })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
// Zusätzlich im localStorage speichern für sofortige Reaktion bei Seitenwechsel
|
||||
localStorage.setItem('darkMode', this.darkMode ? 'dark' : 'light');
|
||||
// Event auslösen für andere Komponenten
|
||||
document.dispatchEvent(new CustomEvent('darkModeToggled', {
|
||||
detail: { isDark: this.darkMode }
|
||||
}));
|
||||
} else {
|
||||
console.error('Fehler beim Speichern der Dark Mode-Einstellung:', data.error);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Fehler beim Speichern der Dark Mode-Einstellung:', error);
|
||||
});
|
||||
}
|
||||
}));
|
||||
});
|
||||
|
||||
// Setze einen globalen Alpine-Initialisierer
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
// Fallback für Alpine-Initialisierung
|
||||
if (typeof Alpine !== 'undefined' && !document.body.hasAttribute('x-data')) {
|
||||
document.body.setAttribute('x-data', 'layout()');
|
||||
}
|
||||
});
|
||||
|
||||
// MindMap global verfügbar machen (für Alpine.js und andere nicht-Module Skripte)
|
||||
window.MindMap = MindMap;
|
||||
</script>
|
||||
<!-- Hauptmodul laden (als traditionelles Skript) -->
|
||||
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
|
||||
|
||||
<!-- Seitenspezifische Styles -->
|
||||
{% block extra_css %}{% endblock %}
|
||||
@@ -243,7 +189,57 @@
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body data-page="{{ request.endpoint }}" class="relative overflow-x-hidden dark bg-gray-900 text-white" x-data="layout()">
|
||||
<body data-page="{{ request.endpoint }}" class="relative overflow-x-hidden dark bg-gray-900 text-white" x-data="{
|
||||
darkMode: true,
|
||||
mobileMenuOpen: false,
|
||||
userMenuOpen: false,
|
||||
showSettingsModal: false,
|
||||
|
||||
init() {
|
||||
this.fetchDarkModeFromSession();
|
||||
},
|
||||
|
||||
fetchDarkModeFromSession() {
|
||||
fetch('/api/get_dark_mode')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
this.darkMode = data.darkMode === 'true';
|
||||
document.querySelector('html').classList.toggle('dark', this.darkMode);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Fehler beim Laden der Dark Mode-Einstellung:', error);
|
||||
});
|
||||
},
|
||||
|
||||
toggleDarkMode() {
|
||||
this.darkMode = !this.darkMode;
|
||||
document.querySelector('html').classList.toggle('dark', this.darkMode);
|
||||
|
||||
fetch('/api/set_dark_mode', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ darkMode: this.darkMode })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
localStorage.setItem('darkMode', this.darkMode ? 'dark' : 'light');
|
||||
document.dispatchEvent(new CustomEvent('darkModeToggled', {
|
||||
detail: { isDark: this.darkMode }
|
||||
}));
|
||||
} else {
|
||||
console.error('Fehler beim Speichern der Dark Mode-Einstellung:', data.error);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Fehler beim Speichern der Dark Mode-Einstellung:', error);
|
||||
});
|
||||
}
|
||||
}">
|
||||
<!-- App-Container -->
|
||||
<div id="app-container" class="flex flex-col min-h-screen">
|
||||
<!-- Hauptnavigation -->
|
||||
@@ -597,11 +593,9 @@
|
||||
{% block scripts %}{% endblock %}
|
||||
|
||||
<!-- KI-Chat Initialisierung -->
|
||||
<script type="module" nonce="{{ csp_nonce }}">
|
||||
// Importiere und initialisiere den ChatGPT-Assistenten direkt, um sicherzustellen,
|
||||
<script>
|
||||
// Initialisiere den ChatGPT-Assistenten direkt, um sicherzustellen,
|
||||
// dass er auf jeder Seite verfügbar ist, selbst wenn MindMap nicht geladen ist
|
||||
import ChatGPTAssistant from "{{ url_for('static', filename='js/modules/chatgpt-assistant.js') }}";
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Prüfen, ob der Assistent bereits durch MindMap initialisiert wurde
|
||||
if (!window.MindMap || !window.MindMap.assistant) {
|
||||
|
||||
@@ -391,7 +391,7 @@
|
||||
<div id="mindmap-canvas"></div>
|
||||
|
||||
<!-- Control Panel -->
|
||||
<div class="control-panel p-4 w-64" id="control-panel" x-data="{ isExpanded: true }">
|
||||
<div class="control-panel p-4 w-64">
|
||||
<div class="panel-toggle" @click="isExpanded = !isExpanded">
|
||||
<i class="fa-solid" :class="isExpanded ? 'fa-chevron-left' : 'fa-chevron-right'"></i>
|
||||
</div>
|
||||
@@ -432,7 +432,7 @@
|
||||
|
||||
<!-- User Mindmaps Section -->
|
||||
{% if current_user.is_authenticated %}
|
||||
<div class="user-mindmap-section p-4 w-64" x-data="{ isExpanded: true }">
|
||||
<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">
|
||||
|
||||
Reference in New Issue
Block a user