dashboard: fix gauge charts (install gauge.js, render after polls), force dark theme with white text and red/green accents, add icons
This commit is contained in:
+32
-35
@@ -80,32 +80,9 @@ const badgeCls = s => s === "buy" ? "bg-success-subtle text-success-emphasis bor
|
||||
: "bg-secondary-subtle text-secondary-emphasis border-secondary-subtle";
|
||||
|
||||
/* ── theme ────────────────────────────────────────────────────── */
|
||||
(function () {
|
||||
const KEY = "xau-theme";
|
||||
const sysDark = matchMedia("(prefers-color-scheme: dark)");
|
||||
const stored = () => localStorage.getItem(KEY);
|
||||
const apply = theme => {
|
||||
document.documentElement.setAttribute("data-bs-theme", theme);
|
||||
const btn = $("theme-toggle");
|
||||
if (!btn) return;
|
||||
const icon = btn.querySelector("i");
|
||||
if (theme === "dark") {
|
||||
btn.title = "Switch to light mode";
|
||||
if (icon) icon.className = "bi bi-sun-fill";
|
||||
} else {
|
||||
btn.title = "Switch to dark mode";
|
||||
if (icon) icon.className = "bi bi-moon-fill";
|
||||
}
|
||||
};
|
||||
apply(stored() || (sysDark.matches ? "dark" : "light"));
|
||||
sysDark.addEventListener("change", e => { if (!stored()) apply(e.matches ? "dark" : "light"); });
|
||||
const btn = $("theme-toggle");
|
||||
if (btn) btn.addEventListener("click", () => {
|
||||
const next = document.documentElement.getAttribute("data-bs-theme") === "dark" ? "light" : "dark";
|
||||
localStorage.setItem(KEY, next);
|
||||
apply(next);
|
||||
});
|
||||
})();
|
||||
// Dark theme is forced site-wide (owner decision 2026-08-16): dark
|
||||
// background, pure-white text, red/green data accents.
|
||||
document.documentElement.setAttribute("data-bs-theme", "dark");
|
||||
|
||||
/* ── hero ─────────────────────────────────────────────────────── */
|
||||
function renderHero() {
|
||||
@@ -176,29 +153,30 @@ function scoreBar(label, score) {
|
||||
const v = Math.max(-100, Math.min(100, score ?? 0));
|
||||
return `<div class="scorebar">
|
||||
<span class="lbl">${label}</span>
|
||||
<div class="gauge-container" style="height: 160px;" data-label="${label}" data-score="${v}"></div>
|
||||
<span class="val num">${v >= 0 ? "+" : ""}${v.toFixed(1)}</span>
|
||||
<div class="gauge-container" data-label="${label}" data-score="${v}"></div>
|
||||
<span class="val num ${v > 0 ? "text-success" : v < 0 ? "text-danger" : ""}">${v >= 0 ? "+" : ""}${v.toFixed(1)}</span>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function setupCard(ts) {
|
||||
if (!ts) return "";
|
||||
const dir = ts.direction === "BUY" ? "buy" : "sell";
|
||||
const dirIcon = ts.direction === "BUY" ? "bi-arrow-up-circle-fill" : "bi-arrow-down-circle-fill";
|
||||
const trail = (ts.trail_arm_r != null && ts.trail_dist_r != null)
|
||||
? `arm ${ts.trail_arm_r}R · dist ${ts.trail_dist_r}R` : "platform default";
|
||||
return `<div class="card border-signal sig-${dir} bg-body-tertiary">
|
||||
<div class="card-body py-2 px-3">
|
||||
<div class="d-flex align-items-baseline gap-2 mb-2">
|
||||
<span class="fw-bold text-signal sig-${dir}">${ts.direction}</span>
|
||||
<span class="fw-bold text-signal sig-${dir}"><i class="bi ${dirIcon} me-1"></i>${ts.direction}</span>
|
||||
<span class="small text-secondary font-monospace">${esc(ts.strategy || "")}</span>
|
||||
<span class="small text-secondary ms-auto font-monospace">R:R ${(+ts.risk_reward).toFixed(1)}</span>
|
||||
</div>
|
||||
<table class="table table-sm table-borderless mb-0">
|
||||
<tr><td class="text-secondary">Entry</td><td class="num">${fmt$(ts.entry)}</td>
|
||||
<td class="text-secondary ps-4">TP1</td><td class="num">${fmt$(ts.take_profit_1)}</td></tr>
|
||||
<tr><td class="text-secondary">Stop</td><td class="num">${fmt$(ts.stop_loss)}</td>
|
||||
<td class="text-secondary ps-4">TP2</td><td class="num">${fmt$(ts.take_profit_2)}</td></tr>
|
||||
<tr><td class="text-secondary">Trail</td><td class="num" colspan="3">${esc(trail)}</td></tr>
|
||||
<tr><td class="text-secondary"><i class="bi bi-box-arrow-in-right me-1"></i>Entry</td><td class="num">${fmt$(ts.entry)}</td>
|
||||
<td class="text-secondary ps-4"><i class="bi bi-flag-fill me-1 text-success"></i>TP1</td><td class="num text-success">${fmt$(ts.take_profit_1)}</td></tr>
|
||||
<tr><td class="text-secondary"><i class="bi bi-shield-x me-1 text-danger"></i>Stop</td><td class="num text-danger">${fmt$(ts.stop_loss)}</td>
|
||||
<td class="text-secondary ps-4"><i class="bi bi-flag-fill me-1 text-success"></i>TP2</td><td class="num text-success">${fmt$(ts.take_profit_2)}</td></tr>
|
||||
<tr><td class="text-secondary"><i class="bi bi-signpost-split me-1"></i>Trail</td><td class="num" colspan="3">${esc(trail)}</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>`;
|
||||
@@ -252,7 +230,25 @@ const tile = (k, v, cls = "") =>
|
||||
<span class="v ${cls}">${v}</span>
|
||||
</div></div></div>`;
|
||||
|
||||
const sec = (title, html) => html ? `<section class="mb-4"><h6 class="text-uppercase text-secondary small fw-bold mb-2 d-flex align-items-center gap-2"><span>${esc(title)}</span><span class="flex-fill border-bottom"></span></h6>${html}</section>` : "";
|
||||
const SEC_ICON = {
|
||||
"At a glance": "bi-speedometer2",
|
||||
"Trade setup": "bi-bullseye",
|
||||
"Why this signal": "bi-lightbulb",
|
||||
"Multi-timeframe confirmation": "bi-layers",
|
||||
"News context": "bi-newspaper",
|
||||
"AI panel (advisory)": "bi-robot",
|
||||
"Scan detail": "bi-clock-history",
|
||||
"Score": "bi-graph-up",
|
||||
"From the source": "bi-quote",
|
||||
"AI gold-impact summary": "bi-stars",
|
||||
"Timing": "bi-alarm",
|
||||
"Numbers": "bi-calculator"
|
||||
};
|
||||
const sec = (title, html) => {
|
||||
if (!html) return "";
|
||||
const icon = SEC_ICON[title];
|
||||
return `<section class="mb-4"><h6 class="text-uppercase text-secondary small fw-bold mb-2 d-flex align-items-center gap-2">${icon ? `<i class="bi ${icon} text-primary"></i>` : ""}<span>${esc(title)}</span><span class="flex-fill border-bottom"></span></h6>${html}</section>`;
|
||||
};
|
||||
|
||||
function indTable(src) {
|
||||
const rows = IND_ORDER.map(name => {
|
||||
@@ -748,6 +744,7 @@ async function poll() {
|
||||
if (snapChanged) {
|
||||
renderHero();
|
||||
renderCards();
|
||||
if (window.renderGauges) window.renderGauges();
|
||||
renderDetail();
|
||||
}
|
||||
if (newsChanged) {
|
||||
|
||||
Reference in New Issue
Block a user