This commit is contained in:
@@ -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.
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user