@cr8rcho/alkahest 0.1.16 → 0.1.18
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/dist/assets/dashboard.html +103 -28
- package/package.json +1 -1
|
@@ -56,24 +56,53 @@
|
|
|
56
56
|
border-bottom: 1px solid var(--line);
|
|
57
57
|
background: var(--panel);
|
|
58
58
|
flex: 0 0 auto;
|
|
59
|
+
position: relative; /* anchor the Display dropdown above the graph */
|
|
60
|
+
z-index: 10;
|
|
59
61
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
#
|
|
62
|
+
/* All three toolbar buttons (Display, Fit, theme) share one chip style on --panel. */
|
|
63
|
+
.tbtn { display: inline-flex; align-items: center; justify-content: center; height: 32px; border-radius: 8px; background: var(--panel); border: 1px solid var(--line); color: var(--ink); cursor: pointer; padding: 0; }
|
|
64
|
+
.tbtn:hover { border-color: var(--accent); }
|
|
65
|
+
.tbtn svg { width: 16px; height: 16px; }
|
|
66
|
+
#fit-btn, #theme-toggle { width: 32px; }
|
|
65
67
|
[data-theme="dark"] #theme-toggle .i-sun { display: block; } [data-theme="dark"] #theme-toggle .i-moon { display: none; }
|
|
66
68
|
[data-theme="light"] #theme-toggle .i-sun { display: none; } [data-theme="light"] #theme-toggle .i-moon { display: block; }
|
|
67
|
-
/*
|
|
68
|
-
.toolbar-actions { display: inline-flex; align-items: center; gap: 8px; }
|
|
69
|
+
/* Action cluster pinned to the right: Display · Fit · theme */
|
|
70
|
+
.toolbar-actions { margin-left: auto; display: inline-flex; align-items: center; gap: 8px; }
|
|
69
71
|
.brand { font-weight: 700; letter-spacing: 0.3px; white-space: nowrap; }
|
|
70
72
|
.brand .sub { color: var(--muted); font-weight: 400; margin-left: 6px; }
|
|
71
73
|
.counts { color: var(--muted); white-space: nowrap; }
|
|
72
|
-
|
|
73
|
-
.
|
|
74
|
-
.
|
|
75
|
-
.
|
|
76
|
-
.
|
|
74
|
+
/* compact counts (mobile only): node-shape icons + number — ○ screen / ▢ resource, matching the legend */
|
|
75
|
+
.counts-min { display: none; }
|
|
76
|
+
.counts-min .cg { display: inline-flex; align-items: center; gap: 5px; }
|
|
77
|
+
.counts-min .cg + .cg { margin-left: 11px; }
|
|
78
|
+
.counts-min .nd { width: 9px; height: 9px; border: 1.5px solid var(--node-stroke); background: var(--node-fill); flex: 0 0 auto; }
|
|
79
|
+
.counts-min .nd.dot { border-radius: 50%; }
|
|
80
|
+
.counts-min .nd.sq { border-radius: 2px; background: var(--res-fill); }
|
|
81
|
+
|
|
82
|
+
/* ---- Display menu: edge filters + legend behind one button. Dropdown on desktop, bottom sheet on mobile. ---- */
|
|
83
|
+
.display-menu { position: relative; }
|
|
84
|
+
.display-btn { gap: 7px; padding: 0 11px; }
|
|
85
|
+
.display-label { font-size: 12px; }
|
|
86
|
+
.display-menu.open .display-btn { border-color: var(--accent); color: var(--accent); }
|
|
87
|
+
.display-backdrop { display: none; }
|
|
88
|
+
.display-pop {
|
|
89
|
+
position: absolute; top: calc(100% + 8px); right: 0; z-index: 30;
|
|
90
|
+
min-width: 210px; background: var(--panel-soft); border: 1px solid var(--line);
|
|
91
|
+
border-radius: 11px; padding: 12px 14px; box-shadow: 0 14px 36px rgba(0, 0, 0, 0.28);
|
|
92
|
+
display: none;
|
|
93
|
+
}
|
|
94
|
+
.display-menu.open .display-pop { display: block; }
|
|
95
|
+
.display-pop h3 { font-size: 10px; text-transform: uppercase; letter-spacing: 0.6px; color: var(--muted); margin: 0 0 8px; }
|
|
96
|
+
.display-pop h3.grp { margin-top: 13px; }
|
|
97
|
+
.disp-row { display: flex; align-items: center; gap: 8px; padding: 5px 0; cursor: pointer; white-space: nowrap; user-select: none; }
|
|
98
|
+
.disp-legend { display: flex; flex-direction: column; gap: 6px; color: var(--muted); }
|
|
99
|
+
.disp-legend > span { white-space: nowrap; }
|
|
100
|
+
.disp-row .sw, .disp-legend .sw { display: inline-block; width: 10px; height: 10px; border-radius: 50%; border: 1.5px solid var(--node-stroke); vertical-align: -1px; }
|
|
101
|
+
.disp-legend .sw { margin-right: 6px; }
|
|
102
|
+
.sw.res { border-radius: 2px; }
|
|
103
|
+
.disp-row .lkey, .disp-legend .lkey { display: inline-block; width: 22px; border-top: 2px solid var(--edge); vertical-align: 3px; }
|
|
104
|
+
.disp-legend .lkey { margin-right: 6px; }
|
|
105
|
+
.lkey.dot { border-top-style: dotted; } .lkey.dash { border-top-style: dashed; }
|
|
77
106
|
main { flex: 1 1 auto; display: flex; min-height: 0; position: relative; }
|
|
78
107
|
#graph { flex: 1 1 auto; min-width: 0; cursor: grab; touch-action: none; }
|
|
79
108
|
#graph:active { cursor: grabbing; }
|
|
@@ -117,9 +146,27 @@
|
|
|
117
146
|
/* ---- Mobile: on narrow screens, render the panel as a bottom sheet ---- */
|
|
118
147
|
@media (max-width: 640px) {
|
|
119
148
|
body { height: 100dvh; }
|
|
120
|
-
.toolbar { column-gap:
|
|
149
|
+
.toolbar { column-gap: 10px; padding: 8px 12px; font-size: 12px; flex-wrap: nowrap; }
|
|
121
150
|
.brand .sub { display: none; }
|
|
122
|
-
.
|
|
151
|
+
.counts-full { display: none; }
|
|
152
|
+
.counts-min { display: inline-flex; align-items: center; }
|
|
153
|
+
.display-label { display: none; } /* Display collapses to icon-only */
|
|
154
|
+
.display-btn { width: 32px; padding: 0; }
|
|
155
|
+
/* Display popover → bottom sheet, mirroring the #panel idiom */
|
|
156
|
+
.display-menu.open .display-backdrop { display: block; position: fixed; inset: 0; background: rgba(0, 0, 0, 0.35); z-index: 40; }
|
|
157
|
+
.display-pop {
|
|
158
|
+
position: fixed; left: 0; right: 0; bottom: 0; top: auto;
|
|
159
|
+
min-width: 0; width: 100%;
|
|
160
|
+
border-radius: 16px 16px 0 0; border-left: none; border-right: none; border-bottom: none;
|
|
161
|
+
box-shadow: 0 -8px 24px rgba(0, 0, 0, 0.45);
|
|
162
|
+
padding: 26px 18px 22px; z-index: 41;
|
|
163
|
+
transform: translateY(101%); transition: transform 0.24s ease;
|
|
164
|
+
display: block; /* always present; slid off-screen until open */
|
|
165
|
+
}
|
|
166
|
+
.display-menu.open .display-pop { transform: translateY(0); }
|
|
167
|
+
.display-pop::before { content: ""; position: absolute; top: 9px; left: 50%; width: 40px; height: 4px; margin-left: -20px; background: var(--line); border-radius: 2px; }
|
|
168
|
+
.disp-row { padding: 9px 0; font-size: 14px; }
|
|
169
|
+
.disp-legend { font-size: 13px; gap: 8px; }
|
|
123
170
|
#panel {
|
|
124
171
|
position: absolute;
|
|
125
172
|
left: 0; right: 0; bottom: 0;
|
|
@@ -156,20 +203,28 @@
|
|
|
156
203
|
<body>
|
|
157
204
|
<header class="toolbar">
|
|
158
205
|
<div class="brand">Alkahest<span class="sub">Product Map</span></div>
|
|
159
|
-
<div class="counts" id="counts"></div>
|
|
160
|
-
<label><input type="checkbox" id="t-trans" checked /> Navigate</label>
|
|
161
|
-
<label><input type="checkbox" id="t-calls" checked /> Call</label>
|
|
162
|
-
<div class="legend">
|
|
163
|
-
<span style="font-weight:700">▶ Start</span>
|
|
164
|
-
<span><span class="swatch" style="background: var(--node-fill); border: 1.5px solid var(--node-stroke)"></span>Screen</span>
|
|
165
|
-
<span><span class="swatch" style="background: var(--res-fill); border: 1.5px solid var(--node-stroke); border-radius: 2px"></span>Resource</span>
|
|
166
|
-
<span><span class="edge" style="border-color: var(--edge)"></span>Navigate</span>
|
|
167
|
-
<span><span class="edge" style="border-top-style: dotted; border-color: var(--edge)"></span>Contains</span>
|
|
168
|
-
<span><span class="edge" style="border-top-style: dashed; border-color: var(--edge)"></span>Call</span>
|
|
169
|
-
</div>
|
|
206
|
+
<div class="counts" id="counts"><span class="counts-full"></span><span class="counts-min"></span></div>
|
|
170
207
|
<div class="toolbar-actions">
|
|
171
|
-
<
|
|
172
|
-
|
|
208
|
+
<div class="display-menu" id="display-menu">
|
|
209
|
+
<button class="tbtn display-btn" id="display-btn" aria-haspopup="true" aria-expanded="false" aria-label="Display options" title="Display options"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="4" y1="8" x2="20" y2="8"/><circle cx="9" cy="8" r="2.4" fill="var(--panel)"/><line x1="4" y1="16" x2="20" y2="16"/><circle cx="15" cy="16" r="2.4" fill="var(--panel)"/></svg><span class="display-label">Display</span></button>
|
|
210
|
+
<div class="display-backdrop" id="display-backdrop"></div>
|
|
211
|
+
<div class="display-pop" id="display-pop" role="menu">
|
|
212
|
+
<h3>Show</h3>
|
|
213
|
+
<label class="disp-row"><input type="checkbox" id="t-trans" checked /><span class="lkey"></span>Navigate</label>
|
|
214
|
+
<label class="disp-row"><input type="checkbox" id="t-calls" checked /><span class="lkey dash"></span>Call</label>
|
|
215
|
+
<h3 class="grp">Legend</h3>
|
|
216
|
+
<div class="disp-legend">
|
|
217
|
+
<span style="font-weight:700">▶ Start</span>
|
|
218
|
+
<span><span class="sw"></span>Screen</span>
|
|
219
|
+
<span><span class="sw res"></span>Resource</span>
|
|
220
|
+
<span><span class="lkey"></span>Navigate</span>
|
|
221
|
+
<span><span class="lkey dot"></span>Contains</span>
|
|
222
|
+
<span><span class="lkey dash"></span>Call</span>
|
|
223
|
+
</div>
|
|
224
|
+
</div>
|
|
225
|
+
</div>
|
|
226
|
+
<button class="tbtn" id="fit-btn" aria-label="Fit to view" title="Fit to view"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 3H5a2 2 0 0 0-2 2v3M16 3h3a2 2 0 0 1 2 2v3M8 21H5a2 2 0 0 1-2-2v-3M16 21h3a2 2 0 0 0 2-2v-3"/></svg></button>
|
|
227
|
+
<button class="tbtn" id="theme-toggle" aria-label="Toggle theme" title="Toggle theme"><svg class="i-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"/></svg><svg class="i-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg></button>
|
|
173
228
|
</div>
|
|
174
229
|
</header>
|
|
175
230
|
<main>
|
|
@@ -264,10 +319,15 @@
|
|
|
264
319
|
{
|
|
265
320
|
const navCount = MAP.transitions.filter((t) => (t.kind || "navigate") === "navigate").length;
|
|
266
321
|
const containCount = MAP.transitions.length - navCount;
|
|
267
|
-
document.getElementById("counts")
|
|
322
|
+
const countsEl = document.getElementById("counts");
|
|
323
|
+
countsEl.querySelector(".counts-full").textContent =
|
|
268
324
|
MAP.screens.length + " screens · " + MAP.resources.length + " resources · " +
|
|
269
325
|
navCount + " navigate" + (containCount ? " · " + containCount + " contains" : "") +
|
|
270
326
|
" · " + MAP.calls.length + " calls";
|
|
327
|
+
// compact form for the mobile toolbar: ○{screens} ▢{resources} (node-shape icons)
|
|
328
|
+
countsEl.querySelector(".counts-min").innerHTML =
|
|
329
|
+
'<span class="cg"><span class="nd dot"></span>' + MAP.screens.length + "</span>" +
|
|
330
|
+
'<span class="cg"><span class="nd sq"></span>' + MAP.resources.length + "</span>";
|
|
271
331
|
}
|
|
272
332
|
|
|
273
333
|
// ====== force-directed layout (reference approach) ======
|
|
@@ -497,6 +557,21 @@
|
|
|
497
557
|
// ---- fit-to-view button ----
|
|
498
558
|
document.getElementById("fit-btn").addEventListener("click", fitToView);
|
|
499
559
|
|
|
560
|
+
// ---- Display menu (edge filters + legend): dropdown on desktop, bottom sheet on mobile ----
|
|
561
|
+
{
|
|
562
|
+
const menu = document.getElementById("display-menu");
|
|
563
|
+
const btn = document.getElementById("display-btn");
|
|
564
|
+
const close = () => { menu.classList.remove("open"); btn.setAttribute("aria-expanded", "false"); };
|
|
565
|
+
btn.addEventListener("click", (e) => {
|
|
566
|
+
e.stopPropagation();
|
|
567
|
+
const open = menu.classList.toggle("open");
|
|
568
|
+
btn.setAttribute("aria-expanded", open ? "true" : "false");
|
|
569
|
+
});
|
|
570
|
+
document.getElementById("display-backdrop").addEventListener("click", close);
|
|
571
|
+
document.addEventListener("click", (e) => { if (!menu.contains(e.target)) close(); });
|
|
572
|
+
document.addEventListener("keydown", (e) => { if (e.key === "Escape") close(); });
|
|
573
|
+
}
|
|
574
|
+
|
|
500
575
|
// ---- panel ----
|
|
501
576
|
const panel = document.getElementById("panel-body"); // content container (close button/handle are preserved)
|
|
502
577
|
const esc = (s) => String(s).replace(/[&<>]/g, (c) => ({ "&": "&", "<": "<", ">": ">" }[c]));
|