Tutorial: Quellenverwaltung mit Cursor-Demo und Tooltip-Anzeige
Quellen-Modal-Step (22) ist jetzt eine interaktive Demo: - Wartet bis Quellen per API geladen sind (max 3s) - Cursor faehrt zum ersten Info-Icon einer Quelle - Tooltip wird manuell erzeugt und zeigt Typ, Sprache, Ausrichtung - Tooltip bleibt 3s sichtbar, dann Cursor weiter zu: - "+ Quelle" Button wird gehighlightet (neue Quellen hinzufuegen) - "Ausschliessen" Button der ersten Quelle wird gehighlightet - Alle Funktionen werden in der Bubble-Beschreibung erklaert Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dieser Commit ist enthalten in:
@@ -764,7 +764,7 @@
|
|||||||
<script src="/static/js/api_network.js?v=20260316a"></script>
|
<script src="/static/js/api_network.js?v=20260316a"></script>
|
||||||
<script src="/static/js/network-graph.js?v=20260316a"></script>
|
<script src="/static/js/network-graph.js?v=20260316a"></script>
|
||||||
<script src="/static/js/app_network.js?v=20260316a"></script>
|
<script src="/static/js/app_network.js?v=20260316a"></script>
|
||||||
<script src="/static/js/tutorial.js?v=20260316i"></script>
|
<script src="/static/js/tutorial.js?v=20260316j"></script>
|
||||||
<script src="/static/js/chat.js?v=20260316f"></script>
|
<script src="/static/js/chat.js?v=20260316f"></script>
|
||||||
<script>document.addEventListener("DOMContentLoaded",function(){Chat.init();Tutorial.init()});</script>
|
<script>document.addEventListener("DOMContentLoaded",function(){Chat.init();Tutorial.init()});</script>
|
||||||
|
|
||||||
|
|||||||
@@ -929,19 +929,19 @@ const Tutorial = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// 22 - Quellen Modal
|
// 22 - Quellen Modal (mit Cursor-Demo)
|
||||||
{
|
{
|
||||||
id: 'sources-modal',
|
id: 'sources-modal',
|
||||||
target: '#modal-sources .modal',
|
target: '#modal-sources .modal',
|
||||||
title: 'Quellen verwalten',
|
title: 'Quellen verwalten',
|
||||||
text: 'Die Quellenverwaltung zeigt alle konfigurierten Nachrichtenquellen. '
|
text: 'Die Quellenverwaltung zeigt alle konfigurierten Nachrichtenquellen.<br><br>'
|
||||||
+ 'Hier sehen Sie für jede Quelle:<br><br>'
|
+ '<strong>Info-Symbol (i)</strong> - Zeigt Typ, Sprache und Ausrichtung der Quelle<br>'
|
||||||
+ '<strong>Name und URL</strong> - Die Quellbezeichnung und Adresse<br>'
|
+ '<strong>Kategorie-Badge</strong> - Farbige Kennzeichnung der Quellkategorie<br>'
|
||||||
+ '<strong>Kategorie</strong> - Nachrichtenagentur, Qualitätszeitung, etc.<br>'
|
+ '<strong>Ausschlie\u00dfen</strong> - Quelle f\u00fcr einzelne Lagen sperren<br>'
|
||||||
+ '<strong>Sprache</strong> - Deutsch, Englisch oder Mehrsprachig<br>'
|
+ '<strong>+ Quelle</strong> - Neue Quellen per URL hinzuf\u00fcgen<br><br>'
|
||||||
+ '<strong>Status</strong> - Aktiv oder deaktiviert<br><br>'
|
+ 'Beobachten Sie, wie die Quellendetails angezeigt werden:',
|
||||||
+ 'Sie können Quellen auch für einzelne Lagen ausschließen, ohne sie global zu deaktivieren.',
|
|
||||||
position: 'left',
|
position: 'left',
|
||||||
|
disableNav: true,
|
||||||
onEnter: function() {
|
onEnter: function() {
|
||||||
var overlay = document.getElementById('modal-sources');
|
var overlay = document.getElementById('modal-sources');
|
||||||
if (overlay && !overlay.classList.contains('active')) {
|
if (overlay && !overlay.classList.contains('active')) {
|
||||||
@@ -950,6 +950,10 @@ const Tutorial = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (overlay) overlay.style.zIndex = '9002';
|
if (overlay) overlay.style.zIndex = '9002';
|
||||||
|
// Warten bis Quellen geladen, dann Demo starten
|
||||||
|
Tutorial._stepTimeout(function() {
|
||||||
|
Tutorial._simulateSourcesDemo();
|
||||||
|
}, 1500);
|
||||||
},
|
},
|
||||||
onExit: function() {
|
onExit: function() {
|
||||||
var overlay = document.getElementById('modal-sources');
|
var overlay = document.getElementById('modal-sources');
|
||||||
@@ -957,6 +961,10 @@ const Tutorial = {
|
|||||||
overlay.classList.remove('active');
|
overlay.classList.remove('active');
|
||||||
overlay.style.zIndex = '';
|
overlay.style.zIndex = '';
|
||||||
}
|
}
|
||||||
|
// Tooltip entfernen falls manuell erzeugt
|
||||||
|
var tip = document.getElementById('tutorial-tooltip');
|
||||||
|
if (tip) tip.remove();
|
||||||
|
Tutorial._clearSubHighlights();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// 23 - Chat
|
// 23 - Chat
|
||||||
@@ -1903,6 +1911,92 @@ const Tutorial = {
|
|||||||
this._enableNavAfterDemo();
|
this._enableNavAfterDemo();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
// Quellenverwaltung-Demo: Info-Icon hover + Tooltip zeigen
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
async _simulateSourcesDemo() {
|
||||||
|
this._demoRunning = true;
|
||||||
|
|
||||||
|
// Warten bis Quellen geladen sind
|
||||||
|
var attempts = 0;
|
||||||
|
while (attempts < 10) {
|
||||||
|
var infoIcon = document.querySelector('#sources-list .info-icon');
|
||||||
|
if (infoIcon) break;
|
||||||
|
await this._wait(300);
|
||||||
|
attempts++;
|
||||||
|
}
|
||||||
|
|
||||||
|
var infoIcon = document.querySelector('#sources-list .info-icon');
|
||||||
|
if (!infoIcon) {
|
||||||
|
this._demoRunning = false;
|
||||||
|
this._enableNavAfterDemo();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Cursor zum ersten Info-Icon
|
||||||
|
var rect = infoIcon.getBoundingClientRect();
|
||||||
|
var targetX = rect.left + rect.width / 2;
|
||||||
|
var targetY = rect.top + rect.height / 2;
|
||||||
|
|
||||||
|
this._showCursor(targetX - 80, targetY - 60, 'default');
|
||||||
|
await this._wait(300);
|
||||||
|
await this._animateCursor(targetX - 80, targetY - 60, targetX, targetY, 600);
|
||||||
|
await this._wait(200);
|
||||||
|
|
||||||
|
// 2. Info-Icon highlighten
|
||||||
|
this._highlightSub('#sources-list .info-icon');
|
||||||
|
|
||||||
|
// 3. Tooltip manuell anzeigen (da pointer-events blockiert sind)
|
||||||
|
var tooltipText = infoIcon.getAttribute('data-tooltip') || '';
|
||||||
|
if (tooltipText) {
|
||||||
|
var tooltip = document.createElement('div');
|
||||||
|
tooltip.id = 'tutorial-tooltip';
|
||||||
|
tooltip.style.cssText = 'position:fixed;z-index:9999;background:var(--bg-card);color:var(--text-primary);'
|
||||||
|
+ 'border:1px solid var(--accent);border-radius:var(--radius);padding:8px 12px;font-size:12px;'
|
||||||
|
+ 'line-height:1.5;max-width:250px;white-space:pre-line;box-shadow:var(--shadow-md);'
|
||||||
|
+ 'pointer-events:none;';
|
||||||
|
tooltip.textContent = tooltipText;
|
||||||
|
document.body.appendChild(tooltip);
|
||||||
|
|
||||||
|
// Tooltip unter dem Icon positionieren
|
||||||
|
tooltip.style.left = Math.max(8, rect.left - 20) + 'px';
|
||||||
|
tooltip.style.top = (rect.bottom + 8) + 'px';
|
||||||
|
}
|
||||||
|
|
||||||
|
await this._wait(3000);
|
||||||
|
|
||||||
|
// 4. Tooltip entfernen
|
||||||
|
var tip = document.getElementById('tutorial-tooltip');
|
||||||
|
if (tip) tip.remove();
|
||||||
|
this._clearSubHighlights();
|
||||||
|
|
||||||
|
// 5. Zum "+ Quelle" Button
|
||||||
|
var addBtn = document.querySelector('.sources-toolbar-actions .btn-primary');
|
||||||
|
if (addBtn) {
|
||||||
|
var addRect = addBtn.getBoundingClientRect();
|
||||||
|
await this._animateCursor(targetX, targetY, addRect.left + addRect.width / 2, addRect.top + addRect.height / 2, 500);
|
||||||
|
this._highlightSub('.sources-toolbar-actions .btn-primary');
|
||||||
|
await this._wait(2000);
|
||||||
|
this._clearSubHighlights();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. Zum "Ausschlie\u00dfen" Button der ersten Quelle
|
||||||
|
var excludeBtn = document.querySelector('#sources-list .source-group-actions .btn-secondary');
|
||||||
|
if (excludeBtn) {
|
||||||
|
var exRect = excludeBtn.getBoundingClientRect();
|
||||||
|
var prevRect = addBtn ? addBtn.getBoundingClientRect() : rect;
|
||||||
|
await this._animateCursor(prevRect.left + prevRect.width / 2, prevRect.top + prevRect.height / 2,
|
||||||
|
exRect.left + exRect.width / 2, exRect.top + exRect.height / 2, 500);
|
||||||
|
this._highlightSub('#sources-list .source-group-actions .btn-secondary');
|
||||||
|
await this._wait(2000);
|
||||||
|
this._clearSubHighlights();
|
||||||
|
}
|
||||||
|
|
||||||
|
this._hideCursor();
|
||||||
|
this._demoRunning = false;
|
||||||
|
this._enableNavAfterDemo();
|
||||||
|
},
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
// Keyboard
|
// Keyboard
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
|
|||||||
In neuem Issue referenzieren
Einen Benutzer sperren