Meldungen entschlackt, Bild-Modalbox, neues Muster, kleinere Trade-Schrift, M15 eingeklappt (v=207)

Fuenf User-Vorgaben in einem Durchgang.

(1) HYPERLIQUID + MUSTER + TRAILING AUS DER MELDUNGEN-KARTE. Die drei Divs sind
ENTFERNT, nicht nur versteckt; die Render-Bloecke bleiben stehen (null-sicher),
damit ein Zurueckholen eine reine HTML-Aenderung ist. Backend rechnet
unveraendert weiter (hl_ctx, patterns_tf, trail_info stehen im Snapshot).
Stufe F bekam eine dokumentierte Ausnahmeliste - sonst haette sie drei
Dauer-Treffer gemeldet, und eine Pruefung mit Dauer-Treffern wird ignoriert.

⚠⚠ DABEI ZWEI ECHTE ABSTUERZE GEFUNDEN - und der Weg dahin ist der Punkt.
`hl-note` wurde ueber das Auffang-`$` geholt; nach dem Entfernen des Elements
griffen ZWEI Zweige ungeschuetzt auf `hlEl.classList` zu. Im Browser ein
TypeError mitten im Render = das GESAMTE Dashboard friert auf Altwerten ein.
Die Render-Probe blieb zunaechst GRUEN - ihr eigener blinder Fleck: die
DOM-Attrappe lieferte fuer JEDE ID ein Element, `$streng` konnte darin also NIE
`null` zurueckgeben. Genau der Fall, fuer den es `$streng` gibt, war ungeprueft.
Behoben: die Attrappe kennt jetzt die echten IDs aus index.html
(`getElementById: id => HTML_IDS.has(id) ? el() : null`) - und meldete die
beiden Zweige im selben Lauf. Danach beide Waechter ergaenzt.

(2) BILD-MODALBOX. Klick auf ein Chartmuster oeffnet es gross.
⚠⚠ BEWUSST OHNE BIBLIOTHEK: ein Lightbox-Paket waere 15-40 KB plus ein zweites
Bedienkonzept fuer ~30 Zeilen Code. Das Dashboard laeuft nur ueber WireGuard,
ein CDN ist gar nicht erreichbar; das Projekt hat aus demselben Grund Tailwind
abgelehnt und am 05.08. die vendorte lightweight-charts (164 KB) entfernt.
Delegierter Klick auf `document`, weil die Kacheln bei JEDEM Render neu erzeugt
werden - ein Handler am <img> waere nach dem naechsten Snapshot weg.
Grosse Fassung (1408 px, ~133 KB) liegt getrennt unter muster/gross/ und wird
ERST beim Klick geladen; die Kachel bleibt bei 25 KB. Esc und Klick auf den
Hintergrund schliessen.

(3) NEUES BILD gescannt: "Inverse Tasse+Henkel.jpg". `inv_cup` hatte bis dahin
ausdruecklich KEIN Bild ("lieber keins als ein falsches") - jetzt zugeordnet.
Damit 16 Muster, keins ohne Datei, keine Datei ohne Zuordnung.

(4) SCHRIFT IN DER TRADE-LEISTE um 2 px (bezogen auf die 18-px-Referenz)
verkleinert - 4 Regeln: Ueberschrift, Feldbeschriftungen, Werte/Eingaben,
Knoepfe.
⚠ Erster Versuch nahm alles zwischen `.tb-title{` und `.mg-row` und traf 80
Regeln statt 4 - die halbe Oberflaeche. Zurueckgesetzt und namentlich
aufgezaehlt. Ein Zeilenbereich ist kein Selektor.

(5) M15-KARTE PER DEFAULT EINGEKLAPPT. Das `open` am ersten <details> ist weg.
⚠ Zusaetzlich der localStorage-Schluessel gebumpt (oil_m15_akk -> oil_m15_akk2):
bei jedem, der die Karte je aufgeklappt hatte, stand dort `true`, und das
gewinnt gegen den neuen Default. Ein neuer Schluessel setzt genau EINMAL
zurueck; danach merkt sich die Karte die eigene Wahl wie bisher.

Pipeline A-G gruen, 97 Tests, 14 render*-Funktionen (Fixture UND leerer
Snapshot), deployt und am ausgelieferten HTML/JS verifiziert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Axel Hocks
2026-08-20 22:27:18 +02:00
co-authored by Claude Opus 5
parent 06024dd0c1
commit 71abb49cf7
23 changed files with 155 additions and 21 deletions
+67 -7
View File
@@ -748,9 +748,19 @@ function renderKontext(snap) {
trN.textContent = trTxt || "";
trN.classList.toggle("hidden", !trTxt);
}
const hlEl = $("hl-note");
// ⚠ `$streng`, nicht das Auffang-`$`: das Element ist am 2026-08-20 auf
// User-Wunsch aus der Meldungen-Karte ENTFERNT. Mit dem Auffang-`$` liefe
// der Block ins Leere und meldete bei jedem Laden eine Konsolen-Warnung —
// ein Dauer-Fehlalarm fuer einen gewollten Zustand.
const hlEl = $streng("hl-note");
const h = snap && snap.hl_ctx;
if (h && h.premium != null) {
// ⚠⚠ `hlEl` MUSS mitgeprueft werden. Das Element ist am 2026-08-20 auf
// User-Wunsch entfernt worden; ohne diese Bedingung wirft `hlEl.classList`
// einen TypeError — und der bricht den GESAMTEN Render ab (Dashboard
// friert auf Altwerten ein). Die else-Zweige hatten den Waechter, der
// Hauptzweig nicht. Gefunden von der Render-Probe, nachdem deren eigener
// blinder Fleck behoben war (die Attrappe gab fuer JEDE ID ein Element).
if (hlEl && h && h.premium != null) {
const fr = (h.funding != null) ? (h.funding * 100).toFixed(4) + " %" : "—";
const oi = (h.open_interest != null)
? (h.open_interest / 1e6).toFixed(2) + " Mio" : "—";
@@ -761,8 +771,8 @@ function renderKontext(snap) {
+ "der Perp notiert über dem Index, Longs zahlen. ⚠ Gemessen über 5.095 "
+ "Funding-Stundenwerte (7 Monate) gegen den CFD: kein belastbarer "
+ "Prognosewert.";
} else {
hlEl.classList.add("hidden");
} else if (hlEl) {
hlEl.classList.add("hidden");
}
}
@@ -1013,6 +1023,49 @@ function renderCone(cn) {
// ⚠ Bilder mit `loading="lazy"`: die 15 Vorlagen liegen verkleinert bei ~25 KB
// (Originale 436611 KB), aber über WireGuard soll nur geladen werden, was
// wirklich sichtbar ist.
// ══ BILD-MODALBOX für die Chartmuster (User-Wunsch 2026-08-20) ═════════════
// ⚠⚠ BEWUSST OHNE BIBLIOTHEK — Begründung im Markup (`#bildbox`). Kurz: ein
// Lightbox-Paket wäre 1540 KB plus ein zweites Bedienkonzept, das Dashboard
// läuft nur über WireGuard (kein CDN erreichbar), und das Projekt hat aus
// demselben Grund Tailwind abgelehnt und die vendorte Chart-Bibliothek
// entfernt. Was hier fehlt, sind ~30 Zeilen.
// ⚠ Delegierter Klick auf `document`: die Kacheln werden bei JEDEM Render neu
// erzeugt (`innerHTML = …`). Ein Handler direkt am `<img>` wäre nach dem
// nächsten Snapshot weg — genau die Sorte Fehler, die nur sporadisch auffällt.
function bildboxOeffnen(bild, text) {
const box = $streng("bildbox"), img = $streng("bildbox-img");
if (!box || !img) return;
// Grosse Fassung (~133 KB) erst JETZT laden, nicht mit dem Dashboard.
img.src = `muster/gross/${bild}.jpg`;
img.alt = text || "";
const t = $streng("bildbox-txt");
if (t) t.textContent = text || "";
box.classList.remove("hidden");
}
function bildboxSchliessen() {
const box = $streng("bildbox");
if (box) box.classList.add("hidden");
}
document.addEventListener("click", (e) => {
const t = e.target;
if (t && t.classList && t.classList.contains("pt-img") && t.dataset
&& t.dataset.bild) {
bildboxOeffnen(t.dataset.bild, t.dataset.txt || t.alt || "");
return;
}
// Klick auf den Hintergrund ODER den Schliessen-Knopf schliesst.
const box = $streng("bildbox");
if (box && !box.classList.contains("hidden")
&& (t === box || (t && t.id === "bildbox-zu"))) {
bildboxSchliessen();
}
});
document.addEventListener("keydown", (e) => {
if (e.key === "Escape") bildboxSchliessen();
});
function renderPatternsTF(d) {
const el = $streng("pt-tfgrid");
if (!el) return;
@@ -1028,7 +1081,9 @@ function renderPatternsTF(d) {
const arr = m.dir === "bull" ? "▲" : m.dir === "bear" ? "▼" : "◆";
const best = m.status === "confirmed";
const bild = m.bild
? `<img class="pt-img" src="muster/${m.bild}.jpg" alt="${m.name}" loading="lazy">`
? `<img class="pt-img" src="muster/${m.bild}.jpg" alt="${m.name}" `
+ `data-bild="${m.bild}" data-txt="${tf} · ${m.name}" loading="lazy" `
+ `title="Klicken öffnet das Bild in voller Größe.">`
: `<div class="pt-img leer">kein Bild</div>`;
const q = (m.quality != null ? m.quality : 0).toFixed(2);
return `<div class="pt-tfcell${best ? " best" : ""}">`
@@ -2405,7 +2460,12 @@ async function setMgGlobal() {
// Ein zugeklapptes <details> ist nur nicht sichtbar - `textContent` wird
// weiter gesetzt, und die naechste Oeffnung zeigt den aktuellen Stand.
{
const KEY = "oil_m15_akk";
// ⚠⚠ SCHLUESSEL GEBUMPT (2026-08-20). Der Default ist jetzt
// "eingeklappt" — aber im `localStorage` steht bei jedem, der die Karte je
// aufgeklappt hatte, noch `true`, und das gewinnt gegen den neuen Default.
// Ein neuer Schluessel setzt genau EINMAL zurueck; danach merkt sich die
// Karte die eigene Wahl wie bisher.
const KEY = "oil_m15_akk2";
let stand = {};
try { stand = JSON.parse(localStorage.getItem(KEY) || "{}"); } catch (e) { stand = {}; }
document.querySelectorAll("details.m15-akk").forEach(el => {
@@ -2459,7 +2519,7 @@ async function closeSlot(slot, label, pnl) {
// und der Browser zeigte Altes. Statt das jedes Mal von Hand zu diagnostizieren,
// sagt die Seite es jetzt selbst.
// ⚠ Bewusst SICHTBAR statt nur Konsole: die Konsole sieht am Handy niemand.
const _JS_V = "205";
const _JS_V = "207";
{
const htmlV = document.body && document.body.dataset
? document.body.dataset.htmlV : null;