Bind NeuralNet chat buttons directly
mindflux-ci / build (push) Successful in 23s

This commit is contained in:
AliceDarkest
2026-07-14 16:27:43 +02:00
parent f9e6516124
commit f2ea8936c3
4 changed files with 30 additions and 17 deletions
+3
View File
@@ -7,6 +7,9 @@ Versionierung [semantisch](https://semver.org/lang/de/).
## [Unreleased] – 2026-07-14 · SysnaptiK Neural Rebrand ## [Unreleased] – 2026-07-14 · SysnaptiK Neural Rebrand
### Marke & Plattform ### Marke & Plattform
- **NeuralNet-Buttons direkt gebunden:** Kontakt- und Chat-Buttons erhalten nach
jedem Rendern eigene Handler. Damit öffnet eine Verbindung unabhängig von der
Ereignisweitergabe des umgebenden Panels zuverlässig den Nachrichtenbereich.
- **NeuralNet-Chat öffnet sofort:** Der Klick auf eine Verbindung schaltet das - **NeuralNet-Chat öffnet sofort:** Der Klick auf eine Verbindung schaltet das
Gespräch samt Eingabefeld nun unabhängig vom anschließenden Verlaufsabruf frei; Gespräch samt Eingabefeld nun unabhängig vom anschließenden Verlaufsabruf frei;
Chat-Aktionen sind explizit als Buttons markiert. Chat-Aktionen sind explizit als Buttons markiert.
+1
View File
@@ -490,6 +490,7 @@ Der Verdacht „Profilbutton fehlt / Einstellungen nicht im Profil / irgendwas i
> zurückziehen) und private Nachrichten nach bestätigter Verbindung sind umgesetzt. > zurückziehen) und private Nachrichten nach bestätigter Verbindung sind umgesetzt.
> Leere Erfolgsantworten des API-Backends werden im Client robust verarbeitet. > Leere Erfolgsantworten des API-Backends werden im Client robust verarbeitet.
> Der Gesprächsbereich öffnet unmittelbar beim Auswählen einer bestätigten Verbindung. > Der Gesprächsbereich öffnet unmittelbar beim Auswählen einer bestätigten Verbindung.
> Die dynamisch gerenderten Kontakt- und Chat-Aktionen werden direkt gebunden.
> Blockieren, Melden/Moderation, Duelle und Lernlobby bleiben die nächsten Ausbauschritte. > Blockieren, Melden/Moderation, Duelle und Lernlobby bleiben die nächsten Ausbauschritte.
> Ersetzt den `/soziales`-Platzhalter („Straßen? Wo wir hingehen, brauchen wir keine Straßen!"). Ziel: User können sich befreunden, intern miteinander schreiben, gemeinsam lernen und Achievements vergleichen – **vollständig selbst gehostet, ohne einen einzigen externen Dienst**, und DSGVO-konform von Grund auf. > Ersetzt den `/soziales`-Platzhalter („Straßen? Wo wir hingehen, brauchen wir keine Straßen!"). Ziel: User können sich befreunden, intern miteinander schreiben, gemeinsam lernen und Achievements vergleichen – **vollständig selbst gehostet, ohne einen einzigen externen Dienst**, und DSGVO-konform von Grund auf.
+25 -16
View File
@@ -36,6 +36,7 @@
q('[data-nn-connections]').innerHTML = data.connections.length ? data.connections.map(function (name) { q('[data-nn-connections]').innerHTML = data.connections.length ? data.connections.map(function (name) {
return item(name, '<button type="button" data-action="chat" data-user="' + esc(name) + '" class="' + (selected === name ? 'active' : '') + '">Chat</button>'); return item(name, '<button type="button" data-action="chat" data-user="' + esc(name) + '" class="' + (selected === name ? 'active' : '') + '">Chat</button>');
}).join('') : '<span class="mf-small-hint">Noch keine Verbindungen.</span>'; }).join('') : '<span class="mf-small-hint">Noch keine Verbindungen.</span>';
bindConnectionActions();
} }
async function refresh() { async function refresh() {
var data = await api('/overview'); var data = await api('/overview');
@@ -60,6 +61,30 @@
q('[data-nn-partner]').textContent = user; q('[data-nn-partner]').textContent = user;
q('[data-nn-messages]').innerHTML = '<p class="mf-small-hint">Nachrichten werden geladen …</p>'; q('[data-nn-messages]').innerHTML = '<p class="mf-small-hint">Nachrichten werden geladen …</p>';
} }
async function selectChat(user) {
openChat(user);
try { await loadChat(); } catch (error) { message(error.message); }
}
function bindConnectionActions() {
q('[data-nn-incoming]').querySelectorAll('[data-action]').forEach(function (button) {
button.onclick = async function () {
try {
if (button.dataset.action === 'accept') await api('/requests/' + encodeURIComponent(button.dataset.user) + '/accept', 'POST');
if (button.dataset.action === 'decline') await api('/requests/' + encodeURIComponent(button.dataset.user) + '/decline', 'POST');
await refresh();
} catch (error) { message(error.message); }
};
});
q('[data-nn-outgoing]').querySelectorAll('[data-action]').forEach(function (button) {
button.onclick = async function () {
try { await api('/requests/' + encodeURIComponent(button.dataset.user), 'DELETE'); await refresh(); }
catch (error) { message(error.message); }
};
});
q('[data-nn-connections]').querySelectorAll('[data-action="chat"]').forEach(function (button) {
button.onclick = function () { selectChat(button.dataset.user); };
});
}
function message(text) { function message(text) {
var hint = q('.nn-head p'); var hint = q('.nn-head p');
hint.textContent = text; hint.textContent = text;
@@ -76,22 +101,6 @@
} catch (error) { message(error.message); } } catch (error) { message(error.message); }
refresh(); refresh();
}; };
q('.nn-sidebar').onclick = async function (event) {
var button = event.target.closest('[data-action]');
if (!button) return;
var user = button.dataset.user, action = button.dataset.action;
try {
if (action === 'chat') {
openChat(user);
try { await loadChat(); } catch (error) { message(error.message); }
return;
}
if (action === 'accept') await api('/requests/' + encodeURIComponent(user) + '/accept', 'POST');
if (action === 'decline') await api('/requests/' + encodeURIComponent(user) + '/decline', 'POST');
if (action === 'cancel') await api('/requests/' + encodeURIComponent(user), 'DELETE');
await refresh();
} catch (error) { message(error.message); }
};
q('[data-nn-compose]').onsubmit = async function (event) { q('[data-nn-compose]').onsubmit = async function (event) {
event.preventDefault(); event.preventDefault();
try { try {
+1 -1
View File
@@ -4,7 +4,7 @@
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>NeuralNet – SysnaptiK Neural</title> <title>NeuralNet – SysnaptiK Neural</title>
<link rel="stylesheet" href="/css/theme.css?v=3"><link rel="stylesheet" href="/css/neuralnet.css?v=1"> <link rel="stylesheet" href="/css/theme.css?v=3"><link rel="stylesheet" href="/css/neuralnet.css?v=1">
<script src="/js/theme.js?v=3"></script><script src="/js/neuralnet.js?v=3" defer></script> <script src="/js/theme.js?v=3"></script><script src="/js/neuralnet.js?v=4" defer></script>
</head> </head>
<body> <body>
<div class="mf-theme-float"><button class="mf-theme"></button></div> <div class="mf-theme-float"><button class="mf-theme"></button></div>