@enigmax/dashboard 0.1.43 → 0.1.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/index.html +57 -7
- package/package.json +1 -1
package/assets/index.html
CHANGED
|
@@ -354,6 +354,19 @@
|
|
|
354
354
|
/* Usage view provider/account pickers. */
|
|
355
355
|
.useg-pick { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--muted); }
|
|
356
356
|
.useg-pick select { width: auto; min-width: 170px; }
|
|
357
|
+
/* Icon dropdown: a native <select> can't render icons in its <option>s, so the provider
|
|
358
|
+
picker is a custom listbox - the logo shows on the button AND inside every option. */
|
|
359
|
+
.dd { position: relative; }
|
|
360
|
+
.dd-btn { display: inline-flex; align-items: center; gap: 8px; min-width: 170px; background: var(--surface2); color: var(--text); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 6px 10px; font-size: 12px; font-family: var(--mono); cursor: pointer; }
|
|
361
|
+
.dd-btn:hover { border-color: #2f3744; }
|
|
362
|
+
.dd-btn .dd-label { flex: 1; text-align: left; }
|
|
363
|
+
.dd-btn .dd-caret { width: 13px; height: 13px; flex: 0 0 auto; color: var(--muted); }
|
|
364
|
+
.dd-ic { display: inline-flex; align-items: center; }
|
|
365
|
+
.dd-ic svg { width: 14px; height: 14px; display: block; }
|
|
366
|
+
.dd-menu { position: absolute; top: calc(100% + 4px); left: 0; min-width: 100%; margin: 0; padding: 4px; list-style: none; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-sm); box-shadow: var(--shadow-2); z-index: 50; }
|
|
367
|
+
.dd-opt { display: flex; align-items: center; gap: 8px; padding: 6px 8px; border-radius: 6px; font-size: 12px; color: var(--text); white-space: nowrap; cursor: pointer; }
|
|
368
|
+
.dd-opt:hover, .dd-opt:focus { background: var(--surface2); outline: none; }
|
|
369
|
+
.dd-opt.sel { color: var(--accent); }
|
|
357
370
|
/* Icon picker: clickable app cards (a native <select> can't render SVG in options). */
|
|
358
371
|
.modal-picker { display: flex; flex-direction: column; gap: 8px; margin-top: 14px; }
|
|
359
372
|
.pick-card {
|
|
@@ -507,7 +520,12 @@
|
|
|
507
520
|
</div>
|
|
508
521
|
</div>
|
|
509
522
|
<div class="useg-controls" style="display:flex;gap:14px;flex-wrap:wrap;align-items:center;margin-bottom:16px">
|
|
510
|
-
<
|
|
523
|
+
<div class="useg-pick"><span>Provider</span>
|
|
524
|
+
<div class="dd" id="uProviderDD">
|
|
525
|
+
<button type="button" class="dd-btn" aria-haspopup="listbox" aria-expanded="false"><span class="dd-ic"></span><span class="dd-label"></span><svg class="dd-caret" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="6 9 12 15 18 9"></polyline></svg></button>
|
|
526
|
+
<ul class="dd-menu" role="listbox" aria-label="Provider" hidden></ul>
|
|
527
|
+
</div>
|
|
528
|
+
</div>
|
|
511
529
|
<label class="useg-pick" id="uAccountWrap"><span>Account</span><select id="uAccount" class="modal-input"></select></label>
|
|
512
530
|
</div>
|
|
513
531
|
<div class="panel" id="usagePanel" style="display:none">
|
|
@@ -1886,12 +1904,44 @@ export {
|
|
|
1886
1904
|
try { await fetch("/api/plan", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ key, value: Number(value) }) }); refreshAll(true); }
|
|
1887
1905
|
catch { /* leave as-is */ }
|
|
1888
1906
|
}
|
|
1907
|
+
// Accessible icon dropdown (a native <select> can't render icons in its <option>s). The
|
|
1908
|
+
// button shows the selected entry's icon + label; the listbox shows every entry with its
|
|
1909
|
+
// icon. entries: [{ value, label, icon }]; getVal()/onPick(value) bind it to state.
|
|
1910
|
+
function iconDropdown(rootId, entries, getVal, onPick) {
|
|
1911
|
+
const root = $(rootId), btn = root.querySelector(".dd-btn"), menu = root.querySelector(".dd-menu");
|
|
1912
|
+
const btnIc = btn.querySelector(".dd-ic"), btnLabel = btn.querySelector(".dd-label");
|
|
1913
|
+
const opts = () => [...menu.querySelectorAll(".dd-opt")];
|
|
1914
|
+
const render = () => {
|
|
1915
|
+
const cur = getVal(), e = entries.find((x) => x.value === cur) || entries[0];
|
|
1916
|
+
btnIc.innerHTML = e.icon || ""; btnLabel.textContent = e.label;
|
|
1917
|
+
menu.innerHTML = entries.map((x) => '<li class="dd-opt' + (x.value === cur ? " sel" : "")
|
|
1918
|
+
+ '" role="option" tabindex="-1" data-val="' + esc(x.value) + '" aria-selected="' + (x.value === cur)
|
|
1919
|
+
+ '"><span class="dd-ic">' + (x.icon || "") + "</span><span>" + esc(x.label) + "</span></li>").join("");
|
|
1920
|
+
};
|
|
1921
|
+
const close = () => { menu.hidden = true; btn.setAttribute("aria-expanded", "false"); };
|
|
1922
|
+
const open = () => { menu.hidden = false; btn.setAttribute("aria-expanded", "true"); (menu.querySelector(".sel") || opts()[0]) && (menu.querySelector(".sel") || opts()[0]).focus(); };
|
|
1923
|
+
const pick = (li) => { close(); btn.focus(); if (li && li.dataset.val) onPick(li.dataset.val); };
|
|
1924
|
+
btn.addEventListener("click", (e) => { e.stopPropagation(); menu.hidden ? open() : close(); });
|
|
1925
|
+
btn.addEventListener("keydown", (e) => { if (e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") { e.preventDefault(); open(); } });
|
|
1926
|
+
menu.addEventListener("click", (e) => pick(e.target.closest(".dd-opt")));
|
|
1927
|
+
menu.addEventListener("keydown", (e) => {
|
|
1928
|
+
const list = opts(), i = list.indexOf(document.activeElement);
|
|
1929
|
+
if (e.key === "Escape") { e.preventDefault(); close(); btn.focus(); }
|
|
1930
|
+
else if (e.key === "ArrowDown") { e.preventDefault(); (list[i + 1] || list[0]).focus(); }
|
|
1931
|
+
else if (e.key === "ArrowUp") { e.preventDefault(); (list[i - 1] || list[list.length - 1]).focus(); }
|
|
1932
|
+
else if (e.key === "Enter" || e.key === " ") { e.preventDefault(); pick(document.activeElement); }
|
|
1933
|
+
});
|
|
1934
|
+
document.addEventListener("click", close);
|
|
1935
|
+
render();
|
|
1936
|
+
return { render };
|
|
1937
|
+
}
|
|
1938
|
+
let providerDD = null;
|
|
1889
1939
|
function wireUsage() {
|
|
1890
|
-
//
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1940
|
+
// The provider picker is a custom icon dropdown; the account one stays a native select.
|
|
1941
|
+
providerDD = iconDropdown("uProviderDD",
|
|
1942
|
+
Object.entries(USAGE_PROVIDERS).map(([k, v]) => ({ value: k, label: v.label, icon: agentSvg(k) })),
|
|
1943
|
+
() => usageProvider,
|
|
1944
|
+
(val) => { if (val === usageProvider) return; usageProvider = val; usageAccount = "__all__"; applyUsageView(); loadProviderStatus(); });
|
|
1895
1945
|
$("uAccount").addEventListener("change", () => { usageAccount = $("uAccount").value; applyUsageView(); });
|
|
1896
1946
|
const el = $("uWindows");
|
|
1897
1947
|
el.addEventListener("click", (e) => {
|
|
@@ -2002,7 +2052,7 @@ export {
|
|
|
2002
2052
|
// measurable local store; the others show an honest "no local usage" panel instead.
|
|
2003
2053
|
function applyUsageView() {
|
|
2004
2054
|
const p = USAGE_PROVIDERS[usageProvider] || USAGE_PROVIDERS.claude;
|
|
2005
|
-
|
|
2055
|
+
if (providerDD) providerDD.render();
|
|
2006
2056
|
$("usageTitle").textContent = p.label + " Usage";
|
|
2007
2057
|
const link = $("usageViewLink");
|
|
2008
2058
|
link.href = p.viewHref; link.textContent = p.viewLabel + " ->";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@enigmax/dashboard",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.44",
|
|
4
4
|
"description": "Local browser dashboard UI for enigma: the static page and chart assets enigma serves on its loopback dashboard (savings, real tool usage, in-browser settings). Installed on demand by enigma-cli; not a runtime dependency.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|