Files
gott/wwwroot/js/app.js
T
Meleki be29984b25 feat: Einzelne Nachrichten als Link teilen
Backend:
- SharedMessageRecord Model + shared_messages DB-Tabelle
- SharedEndpoint: POST /api/messages/{id}/share, GET /api/shared/{token},
  GET /api/shared (Liste), DELETE /api/shared/{token}
- Auth-Ausnahme für GET /api/shared/{token} (öffentlich ohne Login)
- DB-Methoden: CreateSharedMessage, GetSharedMessage, GetChainMessagesUpTo

Frontend:
- Share-Button (fa-share-alt) an jeder Nachricht
- Kontextmenü: Einzelnachricht oder mit Thread-Kontext teilen
- Link wird automatisch in Zwischenablage kopiert
- Öffentliche Shared-Page (#shared/{token}) ohne Login
- Markdown-Rendering in der geteilten Ansicht
- CSS für Share-Button, Share-Menü und Shared-Page
2026-03-04 23:34:00 +01:00

105 lines
2.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ── Global State ──
var currentUser = null;
var currentSettings = null;
const SETTINGS_DEFAULTS = {
pageWidth: 900,
toolCallDisplay: 'modifications',
chainMetaDisplay: 'sometimes',
showDeletedMessages: false
};
function loadSettings() {
return Object.assign({}, SETTINGS_DEFAULTS, currentSettings);
}
async function saveSettings(settings) {
currentSettings = settings;
applySettings();
try { await apiSaveSettings(settings); } catch (_) {}
}
function applySettings() {
var s = loadSettings();
document.documentElement.style.setProperty('--page-width', s.pageWidth + 'px');
}
// ── App Init ──
document.addEventListener('DOMContentLoaded', async () => {
// Auth-Check: Eingeloggt?
const { page, id } = parseHash();
// Shared-Page braucht kein Login
if (page === 'shared') {
await navigateTo('shared', { id }, { replace: true });
return;
}
var user = await apiMe();
if (!user) {
await navigateTo('login', {}, { replace: true });
return;
}
currentUser = user;
currentSettings = await apiGetSettings();
applySettings();
loadClaudeStatus();
var target = page === 'login' ? 'dashboard' : page;
await navigateTo(target, { id }, { replace: true });
});
async function loadClaudeStatus() {
const statusBar = document.getElementById('claudeStatusBar');
if (!statusBar) return;
// Schließen-Button
const closeBtn = statusBar.querySelector('.status-close');
if (closeBtn) {
closeBtn.addEventListener('click', () => { statusBar.hidden = true; });
}
try {
const res = await fetch('https://status.claude.com/api/v2/status.json');
if (!res.ok) return;
const data = await res.json();
const indicator = data.status?.indicator || 'none';
const description = data.status?.description || '';
if (indicator === 'none') return;
statusBar.classList.add(`status-${indicator}`);
statusBar.querySelector('.status-text').textContent = description;
statusBar.hidden = false;
} catch {
// Status-Abruf fehlgeschlagen – still ignorieren
}
}
// Browser Zurück/Vor-Button
window.addEventListener('popstate', async (e) => {
var page, id;
if (e.state && e.state.page) {
page = e.state.page;
id = e.state.params ? e.state.params.id : null;
} else {
const parsed = parseHash();
page = parsed.page;
id = parsed.id;
}
// Login- und Shared-Seite immer erlauben, alles andere nur wenn eingeloggt
if (page !== 'login' && page !== 'shared') {
var user = await apiMe();
if (!user) {
await navigateTo('login', {}, { replace: true });
return;
}
}
await navigateTo(page, { id }, { replace: true });
});