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-Chat öffnet sofort:** Der Klick auf eine Verbindung schaltet das
|
||||||
|
Gespräch samt Eingabefeld nun unabhängig vom anschließenden Verlaufsabruf frei;
|
||||||
|
Chat-Aktionen sind explizit als Buttons markiert.
|
||||||
- **NeuralNet-Chat repariert:** Leere, erfolgreiche API-Antworten werden nicht mehr
|
- **NeuralNet-Chat repariert:** Leere, erfolgreiche API-Antworten werden nicht mehr
|
||||||
fälschlich als JSON gelesen. Kontaktaktionen aktualisieren die Oberfläche wieder
|
fälschlich als JSON gelesen. Kontaktaktionen aktualisieren die Oberfläche wieder
|
||||||
zuverlässig und bestätigte Verbindungen lassen sich direkt im Chat öffnen.
|
zuverlässig und bestätigte Verbindungen lassen sich direkt im Chat öffnen.
|
||||||
|
|||||||
@@ -489,6 +489,7 @@ Der Verdacht „Profilbutton fehlt / Einstellungen nicht im Profil / irgendwas i
|
|||||||
> ✅ **MVP-Stand 2026-07-14:** Opt-in, Kontaktanfragen (annehmen, ablehnen,
|
> ✅ **MVP-Stand 2026-07-14:** Opt-in, Kontaktanfragen (annehmen, ablehnen,
|
||||||
> 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.
|
||||||
> 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.
|
||||||
|
|||||||
@@ -28,13 +28,13 @@
|
|||||||
}
|
}
|
||||||
function render(data) {
|
function render(data) {
|
||||||
q('[data-nn-incoming]').innerHTML = data.incoming.length ? data.incoming.map(function (name) {
|
q('[data-nn-incoming]').innerHTML = data.incoming.length ? data.incoming.map(function (name) {
|
||||||
return item(name, '<button data-action="accept" data-user="' + esc(name) + '">Annehmen</button><button data-action="decline" data-user="' + esc(name) + '">Ablehnen</button>');
|
return item(name, '<button type="button" data-action="accept" data-user="' + esc(name) + '">Annehmen</button><button type="button" data-action="decline" data-user="' + esc(name) + '">Ablehnen</button>');
|
||||||
}).join('') : '<span class="mf-small-hint">Keine offenen Anfragen.</span>';
|
}).join('') : '<span class="mf-small-hint">Keine offenen Anfragen.</span>';
|
||||||
q('[data-nn-outgoing]').innerHTML = data.outgoing.length ? data.outgoing.map(function (name) {
|
q('[data-nn-outgoing]').innerHTML = data.outgoing.length ? data.outgoing.map(function (name) {
|
||||||
return item(name, '<button data-action="cancel" data-user="' + esc(name) + '">Zurückziehen</button>');
|
return item(name, '<button type="button" data-action="cancel" data-user="' + esc(name) + '">Zurückziehen</button>');
|
||||||
}).join('') : '<span class="mf-small-hint">Keine gesendeten Anfragen.</span>';
|
}).join('') : '<span class="mf-small-hint">Keine gesendeten Anfragen.</span>';
|
||||||
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 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>';
|
||||||
}
|
}
|
||||||
async function refresh() {
|
async function refresh() {
|
||||||
@@ -47,15 +47,19 @@
|
|||||||
async function loadChat() {
|
async function loadChat() {
|
||||||
if (!selected) return;
|
if (!selected) return;
|
||||||
var rows = await api('/messages/' + encodeURIComponent(selected));
|
var rows = await api('/messages/' + encodeURIComponent(selected));
|
||||||
q('[data-nn-empty]').hidden = true;
|
|
||||||
q('[data-nn-conversation]').hidden = false;
|
|
||||||
q('[data-nn-partner]').textContent = selected;
|
|
||||||
q('[data-nn-messages]').innerHTML = rows.map(function (message) {
|
q('[data-nn-messages]').innerHTML = rows.map(function (message) {
|
||||||
return '<article class="nn-message ' + (message.sender === me ? 'mine' : '') + '">' + esc(message.body) + '<small>' + esc(message.sender) + ' · ' + new Date(message.sentAt).toLocaleString('de-DE', { dateStyle: 'short', timeStyle: 'short' }) + '</small></article>';
|
return '<article class="nn-message ' + (message.sender === me ? 'mine' : '') + '">' + esc(message.body) + '<small>' + esc(message.sender) + ' · ' + new Date(message.sentAt).toLocaleString('de-DE', { dateStyle: 'short', timeStyle: 'short' }) + '</small></article>';
|
||||||
}).join('');
|
}).join('');
|
||||||
var box = q('[data-nn-messages]');
|
var box = q('[data-nn-messages]');
|
||||||
box.scrollTop = box.scrollHeight;
|
box.scrollTop = box.scrollHeight;
|
||||||
}
|
}
|
||||||
|
function openChat(user) {
|
||||||
|
selected = user;
|
||||||
|
q('[data-nn-empty]').hidden = true;
|
||||||
|
q('[data-nn-conversation]').hidden = false;
|
||||||
|
q('[data-nn-partner]').textContent = user;
|
||||||
|
q('[data-nn-messages]').innerHTML = '<p class="mf-small-hint">Nachrichten werden geladen …</p>';
|
||||||
|
}
|
||||||
function message(text) {
|
function message(text) {
|
||||||
var hint = q('.nn-head p');
|
var hint = q('.nn-head p');
|
||||||
hint.textContent = text;
|
hint.textContent = text;
|
||||||
@@ -77,7 +81,11 @@
|
|||||||
if (!button) return;
|
if (!button) return;
|
||||||
var user = button.dataset.user, action = button.dataset.action;
|
var user = button.dataset.user, action = button.dataset.action;
|
||||||
try {
|
try {
|
||||||
if (action === 'chat') { selected = user; await refresh(); await loadChat(); return; }
|
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 === 'accept') await api('/requests/' + encodeURIComponent(user) + '/accept', 'POST');
|
||||||
if (action === 'decline') await api('/requests/' + encodeURIComponent(user) + '/decline', 'POST');
|
if (action === 'decline') await api('/requests/' + encodeURIComponent(user) + '/decline', 'POST');
|
||||||
if (action === 'cancel') await api('/requests/' + encodeURIComponent(user), 'DELETE');
|
if (action === 'cancel') await api('/requests/' + encodeURIComponent(user), 'DELETE');
|
||||||
|
|||||||
@@ -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=2" defer></script>
|
<script src="/js/theme.js?v=3"></script><script src="/js/neuralnet.js?v=3" 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