feat: EasyMDE-Editor für Persona und Session-Kontext

- profile-page.js: #profilePersona textarea → EasyMDE mit Toolbar und Dark-Theme
- session-page.js: #sessionContext textarea → EasyMDE mit Toolbar und Dark-Theme
- form.css: Override-Styles für EasyMDE in Formularen (height: auto, border-radius)
- base.css: ul margin-left für korrekte Listen-Einrückung
- Beide Editoren: sauberes Cleanup via toTextArea() in destroy()
- Nutzt bestehende fe-mde-wrap Styles aus file-explorer.css
This commit is contained in:
Meleki committed 2026-03-05 20:24:30 +01:00
1 parent 9140c4fcc7
commit df68843e82
5 files changed
+73 -6

No files matched your search

+1 -1
View File
@@ -34,7 +34,7 @@
- [x] Chat: Es werden momentan alle Tool-Calls angezeigt - die Anzeige soll individuell in den Einstellungen gemacht werden können. Auswahl aus drei Stufen: "Alle anzeigen" / "Nur Modifikationen" (file änderungen, memory änderungen, etc.) / "Verstecken" - [x] Chat: Es werden momentan alle Tool-Calls angezeigt - die Anzeige soll individuell in den Einstellungen gemacht werden können. Auswahl aus drei Stufen: "Alle anzeigen" / "Nur Modifikationen" (file änderungen, memory änderungen, etc.) / "Verstecken"
- [x] Browser: "Zurück"-Taste soll auf den vorherigen location.hash wechseln - [x] Browser: "Zurück"-Taste soll auf den vorherigen location.hash wechseln
- [x] File Explorer: CodeMirror lässt sich horizontal nicht scroll - [x] File Explorer: CodeMirror lässt sich horizontal nicht scroll
- [ ] Chat: Datum und Uhrzeit bei den Nachrichten anzeigen (Format: dd.MM.yyyy HH:mm:ss) - [x] Chat: Datum und Uhrzeit bei den Nachrichten anzeigen (Format: dd.MM.yyyy HH:mm:ss)
- [x] Dashboard: Menu-Dropdown bei Cards sind abgeschnitten wenn die Card-Höhe nicht ausreicht (logisch, weil das Menu-Dropdown ein Child von der Card ist) - [x] Dashboard: Menu-Dropdown bei Cards sind abgeschnitten wenn die Card-Höhe nicht ausreicht (logisch, weil das Menu-Dropdown ein Child von der Card ist)
- [ ] Auto-scrolling deaktivieren, wenn man weiterhoch gescrollt hat, und er wieder fortsetzen wenn man ganz nach unten gescrollt hat - [ ] Auto-scrolling deaktivieren, wenn man weiterhoch gescrollt hat, und er wieder fortsetzen wenn man ganz nach unten gescrollt hat
- [x] Anstelle von `[Bild: ...]`-Platzhalter direkt das gesendete Bild anzeigen - [x] Anstelle von `[Bild: ...]`-Platzhalter direkt das gesendete Bild anzeigen
+4
View File
@@ -118,3 +118,7 @@ a {
a:hover { a:hover {
text-decoration: underline; text-decoration: underline;
} }
ul {
margin-left: 1.5em;
}
+23
View File
@@ -407,3 +407,26 @@ label.skill-item {
gap: var(--badge-spacing); gap: var(--badge-spacing);
cursor: pointer; cursor: pointer;
} }
/* ── EasyMDE in Formularen ── */
/* Nutzt fe-mde-wrap Styles aus file-explorer.css für Dark-Theme,
überschreibt aber die Fullscreen-Layout-Regeln für den Formular-Kontext. */
.form .fe-mde-wrap {
display: block;
flex: none;
height: auto;
overflow: visible;
}
.form .fe-mde-wrap .CodeMirror {
height: auto !important;
border: var(--border-width) solid var(--f2-border) !important;
border-top: none !important;
border-radius: 0 0 var(--border-radius) var(--border-radius) !important;
padding: var(--box-padding) !important;
}
.form .fe-mde-wrap .editor-toolbar {
border-radius: var(--border-radius) var(--border-radius) 0 0 !important;
}
+24 -3
View File
@@ -1,5 +1,7 @@
// ── Profile Page ── // ── Profile Page ──
var _profileMde = null;
registerPage('profile', { registerPage('profile', {
async init() { async init() {
var profile = await apiGetProfile(); var profile = await apiGetProfile();
@@ -11,6 +13,21 @@ registerPage('profile', {
var saveBtn = document.getElementById('profileSaveBtn'); var saveBtn = document.getElementById('profileSaveBtn');
var messageDiv = document.getElementById('profileMessage'); var messageDiv = document.getElementById('profileMessage');
// EasyMDE für Persona
_profileMde = new EasyMDE({
element: personaInput,
initialValue: profile.persona || '',
toolbar: ['bold', 'italic', 'heading', '|', 'unordered-list', 'ordered-list', '|', 'link', 'code', '|', 'preview'],
status: false,
spellChecker: false,
autoDownloadFontAwesome: false,
minHeight: '150px',
placeholder: 'Beschreibe dich selbst – Name, Rolle, Präferenzen, Kommunikationsstil...',
previewClass: ['editor-preview', 'markdown']
});
_profileMde.codemirror.setOption('theme', 'default');
_profileMde.codemirror.getWrapperElement().closest('.EasyMDEContainer').classList.add('fe-mde-wrap');
var currentPwInput = document.getElementById('profileCurrentPassword'); var currentPwInput = document.getElementById('profileCurrentPassword');
var newPwInput = document.getElementById('profileNewPassword'); var newPwInput = document.getElementById('profileNewPassword');
var confirmPwInput = document.getElementById('profileConfirmPassword'); var confirmPwInput = document.getElementById('profileConfirmPassword');
@@ -22,7 +39,6 @@ registerPage('profile', {
// Felder befüllen // Felder befüllen
usernameInput.value = profile.username || ''; usernameInput.value = profile.username || '';
displayNameInput.value = profile.displayName || ''; displayNameInput.value = profile.displayName || '';
personaInput.value = profile.persona || '';
// Profil speichern // Profil speichern
saveBtn.addEventListener('click', async function() { saveBtn.addEventListener('click', async function() {
@@ -33,7 +49,7 @@ registerPage('profile', {
try { try {
var updated = await apiUpdateProfile({ var updated = await apiUpdateProfile({
displayName: displayNameInput.value.trim(), displayName: displayNameInput.value.trim(),
persona: personaInput.value.trim() persona: _profileMde.value().trim()
}); });
// currentUser aktualisieren // currentUser aktualisieren
@@ -108,5 +124,10 @@ registerPage('profile', {
navigateTo('login'); navigateTo('login');
}); });
}, },
destroy() {} destroy() {
if (_profileMde) {
_profileMde.toTextArea();
_profileMde = null;
}
}
}); });
+21 -2
View File
@@ -2,6 +2,7 @@
let _sessionImageData = null; let _sessionImageData = null;
let _sessionPasteHandler = null; let _sessionPasteHandler = null;
let _sessionContextMde = null;
registerPage('session', { registerPage('session', {
async init(params) { async init(params) {
@@ -36,7 +37,6 @@ registerPage('session', {
titleEl.textContent = session.name || 'Unbenannt'; titleEl.textContent = session.name || 'Unbenannt';
nameEl.value = session.name || ''; nameEl.value = session.name || '';
descEl.value = session.description || ''; descEl.value = session.description || '';
contextEl.value = session.context || '';
workspaceEl.value = session.workspace || ''; workspaceEl.value = session.workspace || '';
_sessionImageData = session.image || null; _sessionImageData = session.image || null;
deleteBtn.hidden = false; deleteBtn.hidden = false;
@@ -52,6 +52,21 @@ registerPage('session', {
deleteBtn.hidden = true; deleteBtn.hidden = true;
} }
// EasyMDE für Kontext
_sessionContextMde = new EasyMDE({
element: contextEl,
initialValue: (session && session.context) || '',
toolbar: ['bold', 'italic', 'heading', '|', 'unordered-list', 'ordered-list', '|', 'link', 'code', '|', 'preview'],
status: false,
spellChecker: false,
autoDownloadFontAwesome: false,
minHeight: '120px',
placeholder: 'Zusätzlicher Kontext für den System-Prompt (optional)',
previewClass: ['editor-preview', 'markdown']
});
_sessionContextMde.codemirror.setOption('theme', 'default');
_sessionContextMde.codemirror.getWrapperElement().closest('.EasyMDEContainer').classList.add('fe-mde-wrap');
// Befehl hinzufügen // Befehl hinzufügen
addCommandBtn.addEventListener('click', () => createCommandRow(commandsList)); addCommandBtn.addEventListener('click', () => createCommandRow(commandsList));
@@ -131,7 +146,7 @@ registerPage('session', {
description: descEl.value.trim(), description: descEl.value.trim(),
image: _sessionImageData, image: _sessionImageData,
agentId: agentSelect.value || null, agentId: agentSelect.value || null,
context: contextEl.value || null, context: _sessionContextMde.value().trim() || null,
workspace: workspaceEl.value.trim() || null, workspace: workspaceEl.value.trim() || null,
customCommands: commands customCommands: commands
}; };
@@ -166,6 +181,10 @@ registerPage('session', {
}); });
}, },
destroy() { destroy() {
if (_sessionContextMde) {
_sessionContextMde.toTextArea();
_sessionContextMde = null;
}
if (_sessionPasteHandler) { if (_sessionPasteHandler) {
document.removeEventListener('paste', _sessionPasteHandler); document.removeEventListener('paste', _sessionPasteHandler);
_sessionPasteHandler = null; _sessionPasteHandler = null;