From 699127f41fb466681b98fe5d25046eb38056d356 Mon Sep 17 00:00:00 2001 From: Till Tomczak Date: Fri, 2 May 2025 18:49:02 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8=20style:=20update=20UI=20and=20dat?= =?UTF-8?q?abase=20schema=20for=20improved=20user=20experience?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- database/systades.db | Bin 147456 -> 147456 bytes static/css/neural-network-background.css | 111 +++++ static/neural-network-background.js | 242 +++++++---- templates/base.html | 52 ++- templates/profile.html | 514 +++++++++++++++++++++++ 5 files changed, 824 insertions(+), 95 deletions(-) diff --git a/database/systades.db b/database/systades.db index 286c46f6fe82824877c1ddadaa5e81ed311d74a2..129ea8de443643252bda7d3a7e660a3185c31d67 100644 GIT binary patch delta 112 zcmZo@;B08%oFL7pF;T{uQDbAml6(#(es2c;iTvIh8}0esT$nf*L`69r9XU%= 1) { // Flow beenden connection.active = false; + connection.flowProgress = 0; this.activeConnections.delete(connectionId); } else { connection.flowProgress = progress; } } - // Neue Flows starten, wenn unter dem Limit - if (this.activeConnections.size < this.config.flowDensity) { - // Wähle eine zufällige Verbindung - const availableConnections = this.connections.filter(c => !c.active); + // Neue aktive Verbindungen starten + if (this.activeConnections.size < this.config.flowDensity && Math.random() < 0.05) { + // Zufälligen Knoten auswählen + const nodeIndex = Math.floor(Math.random() * this.nodes.length); + const node = this.nodes[nodeIndex]; - if (availableConnections.length > 0) { - const randomIndex = Math.floor(Math.random() * availableConnections.length); - const connection = availableConnections[randomIndex]; + // Anzahl der aktiven Verbindungen für diesen Knoten zählen + const activeConnectionsCount = Array.from(this.activeConnections) + .filter(id => { + const [from, to] = id.split('-').map(Number); + return from === nodeIndex || to === nodeIndex; + }).length; + + // Nur neue Verbindung aktivieren, wenn Knoten noch nicht zu viele aktive hat + if (activeConnectionsCount < this.config.maxFlowsPerNode) { + // Verfügbare Verbindungen für diesen Knoten finden + const availableConnections = node.connections.filter(conn => !conn.active); - // Aktiviere die Verbindung - connection.active = true; - connection.flowProgress = 0; - connection.flowStart = now; - connection.flowDuration = this.config.flowDuration[0] + - Math.random() * (this.config.flowDuration[1] - this.config.flowDuration[0]); + if (availableConnections.length > 0) { + // Zufällige Verbindung auswählen + const connection = availableConnections[Math.floor(Math.random() * availableConnections.length)]; + + // Verbindung aktivieren + connection.active = true; + connection.flowProgress = 0; + connection.flowStart = now; + connection.flowDuration = this.config.flowDuration[0] + + Math.random() * (this.config.flowDuration[1] - this.config.flowDuration[0]); + + this.activeConnections.add(connection.id); + } + } + } + + // Verbindungsdistanzen neu berechnen + for (let i = 0; i < this.connections.length; i++) { + const connection = this.connections[i]; + const nodeA = this.nodes[connection.from]; + const nodeB = this.nodes[connection.to]; + + const dx = nodeA.x - nodeB.x; + const dy = nodeA.y - nodeB.y; + const distance = Math.sqrt(dx * dx + dy * dy); + + connection.distance = distance; + + // Bei zu großer Distanz Verbindung deaktivieren + if (distance > this.config.connectionDistance) { + connection.opacity = 0; - this.activeConnections.add(connection.id); + if (connection.active) { + connection.active = false; + connection.flowProgress = 0; + this.activeConnections.delete(connection.id); + } + } else { + // Verbesserte Berechnung der Opazität für einen natürlicheren Look + const opacityFactor = document.documentElement.classList.contains('dark') ? 1.0 : 0.85; + connection.opacity = Math.max(0.08, (1 - (distance / this.config.connectionDistance)) * this.config.connectionOpacity * opacityFactor); } } } render(now) { - // Aktualisiere Farben basierend auf aktuellem Theme + // Canvas löschen + this.ctx.clearRect(0, 0, this.canvas.width / (window.devicePixelRatio || 1), this.canvas.height / (window.devicePixelRatio || 1)); + + // Aktualisiere Farbpalette basierend auf aktuellem Theme this.currentColors = document.documentElement.classList.contains('dark') ? this.colors.dark : this.colors.light; - const colors = this.currentColors; - const width = this.canvas.width / (window.devicePixelRatio || 1); - const height = this.canvas.height / (window.devicePixelRatio || 1); - - // Hintergrund löschen - this.ctx.fillStyle = colors.background; - this.ctx.fillRect(0, 0, width, height); - - // Verbindungen zeichnen (statisch) - this.ctx.strokeStyle = colors.connectionColor; - this.ctx.lineWidth = 1.2; - - for (const connection of this.connections) { - const fromNode = this.nodes[connection.from]; - const toNode = this.nodes[connection.to]; - this.ctx.globalAlpha = connection.opacity * 0.5; - - this.ctx.beginPath(); - this.ctx.moveTo(fromNode.x, fromNode.y); - this.ctx.lineTo(toNode.x, toNode.y); - this.ctx.stroke(); + // Light Mode mit zusätzlichem Blur-Effekt für weicheres Erscheinungsbild + if (!document.documentElement.classList.contains('dark')) { + this.ctx.filter = 'blur(0.5px)'; + } else { + this.ctx.filter = 'none'; } - // Aktive Verbindungen zeichnen (Flows) - this.ctx.strokeStyle = colors.flowColor; - this.ctx.lineWidth = 2.5; - - for (const connectionId of this.activeConnections) { - const connection = this.connections.find(c => c.id === connectionId); - if (!connection) continue; + // Verbindungen zeichnen + for (let i = 0; i < this.connections.length; i++) { + const connection = this.connections[i]; - const fromNode = this.nodes[connection.from]; - const toNode = this.nodes[connection.to]; + if (connection.opacity <= 0) continue; - // Glühen-Effekt - this.ctx.globalAlpha = Math.sin(connection.flowProgress * Math.PI) * 0.8; + const nodeA = this.nodes[connection.from]; + const nodeB = this.nodes[connection.to]; - // Linie zeichnen + this.ctx.strokeStyle = this.currentColors.connectionColor; + this.ctx.globalAlpha = connection.opacity; this.ctx.beginPath(); - this.ctx.moveTo(fromNode.x, fromNode.y); - this.ctx.lineTo(toNode.x, toNode.y); + this.ctx.moveTo(nodeA.x, nodeA.y); + this.ctx.lineTo(nodeB.x, nodeB.y); this.ctx.stroke(); - // Fließendes Partikel - const progress = connection.flowProgress; - const x = fromNode.x + (toNode.x - fromNode.x) * progress; - const y = fromNode.y + (toNode.y - fromNode.y) * progress; - - this.ctx.globalAlpha = 0.9; - this.ctx.fillStyle = colors.flowColor; - - this.ctx.beginPath(); - this.ctx.arc(x, y, 2, 0, Math.PI * 2); - this.ctx.fill(); - } - - // Knoten zeichnen - for (const node of this.nodes) { - // Pulsierende Knoten - const timeSinceLastPulse = now - node.lastPulse; - const isPulsing = timeSinceLastPulse < 800; - const pulseProgress = isPulsing ? timeSinceLastPulse / 800 : 0; - - // Knoten selbst - this.ctx.globalAlpha = 1; - this.ctx.fillStyle = isPulsing - ? colors.nodePulse - : colors.nodeColor; - - this.ctx.beginPath(); - this.ctx.arc(node.x, node.y, node.size + (isPulsing ? 1 * Math.sin(pulseProgress * Math.PI) : 0), 0, Math.PI * 2); - this.ctx.fill(); - - // Wenn pulsierend, füge einen Glow-Effekt hinzu - if (isPulsing) { - this.ctx.globalAlpha = 0.5 * (1 - pulseProgress); + // Aktive Verbindungen mit Fluss darstellen + if (connection.active) { + const fromX = nodeA.x; + const fromY = nodeA.y; + const toX = nodeB.x; + const toY = nodeB.y; + + // Position des Flusspunkts + const x = fromX + (toX - fromX) * connection.flowProgress; + const y = fromY + (toY - fromY) * connection.flowProgress; + + // Fluss-Effekt zeichnen + const pulseSize = document.documentElement.classList.contains('dark') ? 3 : 4; + const pulseOpacity = document.documentElement.classList.contains('dark') ? 0.8 : 0.85; + + // Pulse-Effekt + this.ctx.fillStyle = this.currentColors.flowColor; + this.ctx.globalAlpha = pulseOpacity; this.ctx.beginPath(); - this.ctx.arc(node.x, node.y, node.size + 5 * pulseProgress, 0, Math.PI * 2); + this.ctx.arc(x, y, pulseSize, 0, Math.PI * 2); + this.ctx.fill(); + + // Glow-Effekt + const gradient = this.ctx.createRadialGradient(x, y, 0, x, y, pulseSize * 2); + gradient.addColorStop(0, this.hexToRgba(this.currentColors.flowColor, 0.4)); + gradient.addColorStop(1, this.hexToRgba(this.currentColors.flowColor, 0)); + + this.ctx.fillStyle = gradient; + this.ctx.globalAlpha = 0.8; + this.ctx.beginPath(); + this.ctx.arc(x, y, pulseSize * 2, 0, Math.PI * 2); this.ctx.fill(); } } + // Knoten zeichnen + for (let i = 0; i < this.nodes.length; i++) { + const node = this.nodes[i]; + const isPulsing = now - node.lastPulse < 300; + + // Erhöhte Helligkeit für pulsierende Knoten + const nodeColor = isPulsing ? this.currentColors.nodePulse : this.currentColors.nodeColor; + const glowSize = isPulsing ? node.size * 2.5 : node.size * 1.5; + + // Glow-Effekt + const gradient = this.ctx.createRadialGradient( + node.x, node.y, 0, + node.x, node.y, glowSize + ); + + gradient.addColorStop(0, this.hexToRgba(nodeColor, isPulsing ? 0.6 : 0.3)); + gradient.addColorStop(1, this.hexToRgba(nodeColor, 0)); + + this.ctx.fillStyle = gradient; + this.ctx.globalAlpha = document.documentElement.classList.contains('dark') ? 0.7 : 0.5; + this.ctx.beginPath(); + this.ctx.arc(node.x, node.y, glowSize, 0, Math.PI * 2); + this.ctx.fill(); + + // Knoten selbst zeichnen + this.ctx.fillStyle = nodeColor; + this.ctx.globalAlpha = 0.8; + this.ctx.beginPath(); + this.ctx.arc(node.x, node.y, node.size, 0, Math.PI * 2); + this.ctx.fill(); + } + + // Zurücksetzen der Globalwerte this.ctx.globalAlpha = 1; + this.ctx.filter = 'none'; } destroy() { @@ -391,6 +447,9 @@ class NeuralNetworkBackground { } hexToRgb(hex) { + const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; + hex = hex.replace(shorthandRegex, (m, r, g, b) => r + r + g + g + b + b); + const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return result ? { r: parseInt(result[1], 16), @@ -398,6 +457,11 @@ class NeuralNetworkBackground { b: parseInt(result[3], 16) } : null; } + + hexToRgba(hex, alpha) { + const rgb = this.hexToRgb(hex); + return rgb ? `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha})` : `rgba(0, 0, 0, ${alpha})`; + } } // Initialisiert den Hintergrund, sobald die Seite geladen ist diff --git a/templates/base.html b/templates/base.html index eeaa1cc..c924b0b 100644 --- a/templates/base.html +++ b/templates/base.html @@ -397,12 +397,52 @@
- {% if current_user.is_authenticated %} diff --git a/templates/profile.html b/templates/profile.html index ef43060..8696cf3 100644 --- a/templates/profile.html +++ b/templates/profile.html @@ -4,7 +4,521 @@ {% block extra_css %} {% endblock %} {% block content %}