eklavya 1.9.2 → 1.9.3
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.
|
@@ -4,95 +4,126 @@
|
|
|
4
4
|
<meta charset="utf-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
6
|
<title>Eklavya — learning progress</title>
|
|
7
|
-
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Crect width='24' height='24'
|
|
7
|
+
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Crect width='24' height='24' fill='%230E6E66'/%3E%3Cg fill='none' stroke='%23fff' stroke-width='1.8' stroke-linecap='round'%3E%3Cpath d='M7 5a11 11 0 0 1 0 14'/%3E%3Cpath d='M6 12h12'/%3E%3Cpath d='M14 9l3 3-3 3'/%3E%3C/g%3E%3C/svg%3E">
|
|
8
|
+
<script>
|
|
9
|
+
/* Ground selection, shared with the site: same localStorage key, same default.
|
|
10
|
+
Runs before the stylesheet so the page never paints one ground then swaps.
|
|
11
|
+
Ink is the default and an absent choice stays ink — deliberately not the
|
|
12
|
+
reader's OS setting, because this is a terminal tool. */
|
|
13
|
+
(function () {
|
|
14
|
+
window.eklavyaGround = {
|
|
15
|
+
read: function () {
|
|
16
|
+
try { return localStorage.getItem('eklavya-ground') === 'paper' ? 'paper' : 'ink'; }
|
|
17
|
+
catch (e) { return 'ink'; }
|
|
18
|
+
},
|
|
19
|
+
apply: function (mode) {
|
|
20
|
+
document.documentElement.setAttribute('data-mode', mode);
|
|
21
|
+
document.querySelectorAll('[data-ground]').forEach(function (b) {
|
|
22
|
+
b.setAttribute('aria-pressed', String(b.dataset.ground === mode));
|
|
23
|
+
});
|
|
24
|
+
return mode;
|
|
25
|
+
},
|
|
26
|
+
set: function (mode) {
|
|
27
|
+
try { localStorage.setItem('eklavya-ground', mode); } catch (e) {}
|
|
28
|
+
this.apply(mode);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
window.eklavyaGround.apply(window.eklavyaGround.read());
|
|
32
|
+
})();
|
|
33
|
+
</script>
|
|
8
34
|
<link rel="stylesheet" href="/tokens.css">
|
|
9
35
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
10
36
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
11
|
-
<link href="https://fonts.googleapis.com/css2?family=
|
|
37
|
+
<link href="https://fonts.googleapis.com/css2?family=Archivo:wght@600;800;900&family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
|
12
38
|
<style>
|
|
13
39
|
*, *::before, *::after { box-sizing: border-box; }
|
|
14
|
-
body { margin:0; font-family:var(--font-
|
|
15
|
-
font-size:
|
|
40
|
+
body { margin:0; font-family:var(--font-body); background:var(--bg); color:var(--ink);
|
|
41
|
+
font-size:14.5px; line-height:1.65;
|
|
42
|
+
background-image:
|
|
43
|
+
linear-gradient(var(--grid) 1px, transparent 1px),
|
|
44
|
+
linear-gradient(90deg, var(--grid) 1px, transparent 1px);
|
|
45
|
+
background-size:72px 72px; }
|
|
46
|
+
::selection { background:var(--spot); color:var(--spot-ink); }
|
|
16
47
|
.wrap { max-width:1140px; margin:0 auto; padding:0 var(--space-8); }
|
|
17
48
|
code, .mono { font-family:var(--font-mono); font-size:var(--text-sm); }
|
|
18
49
|
|
|
19
50
|
/* ---------- header ---------- */
|
|
20
|
-
header {
|
|
51
|
+
header { border-bottom:1px solid var(--line-2); padding:var(--space-8) 0 var(--space-10); }
|
|
21
52
|
.bar { display:flex; align-items:center; gap:var(--space-4); flex-wrap:wrap; }
|
|
22
|
-
.mark { width:
|
|
53
|
+
.mark { width:34px; height:34px; background:var(--spot); color:var(--spot-ink);
|
|
23
54
|
display:grid; place-items:center; flex:none; }
|
|
24
|
-
h1 { font-
|
|
25
|
-
|
|
55
|
+
h1 { font-family:var(--font-disp); font-size:26px; font-weight:var(--weight-extra);
|
|
56
|
+
letter-spacing:var(--tracking-tight); margin:0; }
|
|
57
|
+
.sub { color:var(--dim); font-size:var(--text-sm); margin:2px 0 0; }
|
|
26
58
|
.spacer { flex:1 1 auto; }
|
|
27
|
-
select { font:inherit; font-size:var(--text-sm); background:var(--
|
|
28
|
-
border:1px solid var(--
|
|
59
|
+
select { font:inherit; font-size:var(--text-sm); background:var(--panel); color:var(--ink);
|
|
60
|
+
border:1px solid var(--line-2); border-radius:0;
|
|
29
61
|
padding:var(--space-2) var(--space-3); }
|
|
30
62
|
select:focus-visible { outline:none; box-shadow:var(--ring); }
|
|
31
63
|
|
|
32
64
|
/* ---------- stat tiles ---------- */
|
|
33
65
|
.tiles { display:grid; grid-template-columns:repeat(4,1fr); gap:var(--space-4); margin-top:var(--space-6); }
|
|
34
|
-
.tile { background:var(--
|
|
66
|
+
.tile { background:var(--panel); border:1px solid var(--line-2); border-radius:0;
|
|
35
67
|
padding:var(--space-5); }
|
|
36
68
|
.tile .k { font-size:var(--text-xs); font-weight:var(--weight-bold); letter-spacing:.08em;
|
|
37
|
-
text-transform:uppercase; color:var(--
|
|
69
|
+
text-transform:uppercase; color:var(--dim); }
|
|
38
70
|
.tile .v { font-size:var(--text-3xl); font-weight:var(--weight-extra,800); letter-spacing:-.025em;
|
|
39
71
|
line-height:1.1; margin-top:var(--space-2); }
|
|
40
|
-
.tile .n { font-size:var(--text-sm); color:var(--
|
|
41
|
-
.good { color:var(--
|
|
72
|
+
.tile .n { font-size:var(--text-sm); color:var(--dim); margin-top:var(--space-1); }
|
|
73
|
+
.good { color:var(--spot); }
|
|
42
74
|
|
|
43
75
|
/* ---------- cards ---------- */
|
|
44
76
|
main { padding:var(--space-10) 0 var(--space-20); }
|
|
45
|
-
section { background:var(--
|
|
77
|
+
section { background:var(--panel); border:1px solid var(--line); border-radius:0;
|
|
46
78
|
padding:var(--space-6); margin-bottom:var(--space-6); }
|
|
47
79
|
h2 { font-size:var(--text-md); font-weight:var(--weight-bold); letter-spacing:-.01em; margin:0; }
|
|
48
|
-
.hint { color:var(--
|
|
80
|
+
.hint { color:var(--faint); font-size:var(--text-sm); margin:var(--space-1) 0 var(--space-5); }
|
|
49
81
|
.grid2 { display:grid; grid-template-columns:1fr 1fr; gap:var(--space-6); }
|
|
50
82
|
.grid2 > section { margin:0; }
|
|
51
83
|
|
|
52
84
|
/* ---------- tables ---------- */
|
|
53
85
|
table { width:100%; border-collapse:collapse; font-size:var(--text-sm); }
|
|
54
86
|
th { text-align:left; font-size:var(--text-xs); font-weight:var(--weight-bold); letter-spacing:.08em;
|
|
55
|
-
text-transform:uppercase; color:var(--
|
|
56
|
-
border-bottom:1px solid var(--
|
|
57
|
-
td { padding:var(--space-3) var(--space-3) var(--space-3) 0; border-bottom:1px solid var(--
|
|
87
|
+
text-transform:uppercase; color:var(--faint); padding:0 var(--space-3) var(--space-2) 0;
|
|
88
|
+
border-bottom:1px solid var(--line); white-space:nowrap; }
|
|
89
|
+
td { padding:var(--space-3) var(--space-3) var(--space-3) 0; border-bottom:1px solid var(--line);
|
|
58
90
|
vertical-align:top; }
|
|
59
91
|
tr:last-child td { border-bottom:none; }
|
|
60
92
|
.num { text-align:right; font-variant-numeric:tabular-nums; white-space:nowrap; }
|
|
61
93
|
.scroll { overflow-x:auto; }
|
|
62
94
|
|
|
63
95
|
/* ---------- meters (sequential, one hue) ---------- */
|
|
64
|
-
.meter { height:8px; border-radius:var(--radius-pill); background:var(--
|
|
96
|
+
.meter { height:8px; border-radius:var(--radius-pill); background:var(--mass); overflow:hidden;
|
|
65
97
|
min-width:80px; }
|
|
66
|
-
.meter > i { display:block; height:100%; background:var(--
|
|
98
|
+
.meter > i { display:block; height:100%; background:var(--spot); border-radius:var(--radius-pill); }
|
|
67
99
|
.meter.warn > i { background:var(--warning); }
|
|
68
100
|
|
|
69
101
|
/* ---------- chart ---------- */
|
|
70
|
-
.legend { display:flex; gap:var(--space-5); font-size:var(--text-sm); color:var(--
|
|
102
|
+
.legend { display:flex; gap:var(--space-5); font-size:var(--text-sm); color:var(--dim);
|
|
71
103
|
margin-bottom:var(--space-4); flex-wrap:wrap; }
|
|
72
104
|
.legend b { display:inline-block; width:10px; height:10px; border-radius:3px; margin-right:var(--space-2); }
|
|
73
105
|
.chart { position:relative; }
|
|
74
106
|
.chart svg { display:block; width:100%; height:200px; overflow:visible; }
|
|
75
|
-
.gridline { stroke:var(--
|
|
76
|
-
.axis { font-family:var(--font-mono); font-size:10px; fill:var(--
|
|
107
|
+
.gridline { stroke:var(--line); stroke-width:1; }
|
|
108
|
+
.axis { font-family:var(--font-mono); font-size:10px; fill:var(--faint-2); }
|
|
77
109
|
.hit { fill:transparent; cursor:pointer; }
|
|
78
110
|
.hit:hover + .col, .hit:focus-visible + .col { opacity:.75; }
|
|
79
111
|
.tip { position:absolute; pointer-events:none; opacity:0; transform:translate(-50%,-100%);
|
|
80
|
-
background:var(--
|
|
81
|
-
padding:var(--space-3); font-size:var(--text-xs); line-height:1.6; white-space:nowrap;
|
|
82
|
-
box-shadow:var(--shadow-md); transition:opacity var(--duration-fast) var(--ease); z-index:2; }
|
|
112
|
+
background:var(--panel); color:var(--ink); border-radius:0;
|
|
113
|
+
padding:var(--space-3); font-size:var(--text-xs); line-height:1.6; white-space:nowrap; transition:opacity var(--duration-fast) var(--ease); z-index:2; }
|
|
83
114
|
.tip.on { opacity:1; }
|
|
84
115
|
.tip .r { display:flex; justify-content:space-between; gap:var(--space-4); }
|
|
85
116
|
|
|
86
117
|
/* ---------- pills & misc ---------- */
|
|
87
118
|
.pill { display:inline-block; font-family:var(--font-mono); font-size:var(--text-xs);
|
|
88
|
-
padding:2px 8px; border-radius:var(--radius-pill); background:var(--
|
|
89
|
-
color:var(--
|
|
90
|
-
.pill.due { background:var(--
|
|
91
|
-
.pill.ok { background:var(--
|
|
92
|
-
.ctx { color:var(--
|
|
93
|
-
.slug { font-family:var(--font-mono); font-size:var(--text-xs); color:var(--
|
|
94
|
-
.empty { color:var(--
|
|
95
|
-
footer { color:var(--
|
|
119
|
+
padding:2px 8px; border-radius:var(--radius-pill); background:var(--mass);
|
|
120
|
+
color:var(--dim); white-space:nowrap; }
|
|
121
|
+
.pill.due { background:var(--mass); color:var(--warning); }
|
|
122
|
+
.pill.ok { background:var(--spot-soft); color:var(--spot); }
|
|
123
|
+
.ctx { color:var(--ink); }
|
|
124
|
+
.slug { font-family:var(--font-mono); font-size:var(--text-xs); color:var(--faint); }
|
|
125
|
+
.empty { color:var(--faint); font-size:var(--text-sm); }
|
|
126
|
+
footer { color:var(--faint); font-size:var(--text-sm); text-align:center; padding-bottom:var(--space-10); }
|
|
96
127
|
|
|
97
128
|
@media (max-width:900px) {
|
|
98
129
|
.tiles { grid-template-columns:repeat(2,1fr); }
|
|
@@ -104,6 +135,17 @@
|
|
|
104
135
|
.tile .v { font-size:var(--text-2xl); }
|
|
105
136
|
}
|
|
106
137
|
@media (prefers-reduced-motion:reduce) { * { transition:none !important; animation:none !important; } }
|
|
138
|
+
|
|
139
|
+
/* ---------- the ground toggle ---------- */
|
|
140
|
+
.ground { display:flex; border:1px solid var(--line-2); flex:none; }
|
|
141
|
+
.ground button {
|
|
142
|
+
font-family:var(--font-mono); font-size:11px; letter-spacing:.12em;
|
|
143
|
+
text-transform:uppercase; background:none; border:0; color:var(--faint);
|
|
144
|
+
padding:6px 11px; cursor:pointer; line-height:1.4;
|
|
145
|
+
transition:background var(--duration-fast) var(--ease), color var(--duration-fast) var(--ease);
|
|
146
|
+
}
|
|
147
|
+
.ground button:hover { color:var(--ink); }
|
|
148
|
+
.ground button[aria-pressed="true"] { background:var(--ink); color:var(--bg); }
|
|
107
149
|
</style>
|
|
108
150
|
</head>
|
|
109
151
|
<body>
|
|
@@ -111,7 +153,7 @@
|
|
|
111
153
|
<div class="wrap">
|
|
112
154
|
<div class="bar">
|
|
113
155
|
<div class="mark" aria-hidden="true">
|
|
114
|
-
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="
|
|
156
|
+
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"
|
|
115
157
|
stroke-linecap="round" stroke-linejoin="round">
|
|
116
158
|
<path d="M5 3a13 13 0 0 1 0 18"/><path d="M5 3l14 9L5 21"/><path d="M3 12h18"/><path d="M15 8l4 4-4 4"/>
|
|
117
159
|
</svg>
|
|
@@ -121,6 +163,10 @@
|
|
|
121
163
|
<p class="sub" id="sub">Loading…</p>
|
|
122
164
|
</div>
|
|
123
165
|
<div class="spacer"></div>
|
|
166
|
+
<div class="ground" role="group" aria-label="Colour ground">
|
|
167
|
+
<button type="button" data-ground="ink" aria-pressed="true">ink</button>
|
|
168
|
+
<button type="button" data-ground="paper" aria-pressed="false">paper</button>
|
|
169
|
+
</div>
|
|
124
170
|
<label class="sub" for="proj">Project</label>
|
|
125
171
|
<select id="proj"><option value="*">All projects</option></select>
|
|
126
172
|
</div>
|
|
@@ -133,9 +179,9 @@
|
|
|
133
179
|
<h2>Answers over the last 30 days</h2>
|
|
134
180
|
<p class="hint" id="chart-hint">Right, missed and skipped, per day.</p>
|
|
135
181
|
<div class="legend">
|
|
136
|
-
<span><b style="background:var(--
|
|
182
|
+
<span><b style="background:var(--spot)"></b>Right</span>
|
|
137
183
|
<span><b style="background:var(--warning)"></b>Missed</span>
|
|
138
|
-
<span><b style="background:var(--
|
|
184
|
+
<span><b style="background:var(--faint)"></b>Skipped</span>
|
|
139
185
|
</div>
|
|
140
186
|
<div class="chart"><div class="tip" id="tip"></div><svg id="chart" role="img"
|
|
141
187
|
aria-label="Daily answers, split into right, missed and skipped"></svg></div>
|
|
@@ -262,11 +308,11 @@ function renderChart() {
|
|
|
262
308
|
}
|
|
263
309
|
// Stack order is fixed: right at the base, then missed, then skipped on top.
|
|
264
310
|
// Segment colour never depends on rank, only on which measure it is.
|
|
265
|
-
const SEGMENTS = [['passed', 'var(--
|
|
311
|
+
const SEGMENTS = [['passed', 'var(--spot)'], ['missed', 'var(--warning)'], ['skipped', 'var(--faint)']];
|
|
266
312
|
const labelEvery = Math.max(1, Math.ceil(46 / step));
|
|
267
313
|
days.forEach((d, i) => {
|
|
268
314
|
const x = PAD_L + i * step + (step - bw) / 2;
|
|
269
|
-
let acc = 0, seg = '', topColor = 'var(--
|
|
315
|
+
let acc = 0, seg = '', topColor = 'var(--spot)';
|
|
270
316
|
for (const [key, color] of SEGMENTS) {
|
|
271
317
|
if (!d[key]) continue;
|
|
272
318
|
const h = (d[key] / max) * (H - PAD_B - 8);
|
|
@@ -403,5 +449,10 @@ fetch('/api/state').then((r) => r.json()).then((s) => {
|
|
|
403
449
|
addEventListener('resize', renderChart);
|
|
404
450
|
}).catch((e) => { $('sub').textContent = 'Could not read the database: ' + e.message; });
|
|
405
451
|
</script>
|
|
452
|
+
<script>
|
|
453
|
+
document.querySelectorAll('[data-ground]').forEach(function (b) {
|
|
454
|
+
b.addEventListener('click', function () { window.eklavyaGround.set(b.dataset.ground); });
|
|
455
|
+
});
|
|
456
|
+
</script>
|
|
406
457
|
</body>
|
|
407
458
|
</html>
|
package/dist/assets/tokens.css
CHANGED
|
@@ -128,7 +128,7 @@
|
|
|
128
128
|
|
|
129
129
|
--ink: #EAE7E1; /* primary text */
|
|
130
130
|
--dim: #A29C93; /* secondary */
|
|
131
|
-
--faint: #
|
|
131
|
+
--faint: #8B857B; /* captions, micro-labels — 4.89:1 on ink */
|
|
132
132
|
--faint-2: #565249; /* disabled, placeholder */
|
|
133
133
|
|
|
134
134
|
--line: #26262a; /* hairline */
|
|
@@ -153,7 +153,7 @@
|
|
|
153
153
|
|
|
154
154
|
--ink: #16150f;
|
|
155
155
|
--dim: #57534a;
|
|
156
|
-
--faint: #
|
|
156
|
+
--faint: #6E695E; /* 4.67:1 on paper */
|
|
157
157
|
--faint-2: #a09a8c;
|
|
158
158
|
|
|
159
159
|
--line: #e3dfd4;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eklavya",
|
|
3
3
|
"displayName": "Eklavya",
|
|
4
|
-
"version": "1.9.
|
|
4
|
+
"version": "1.9.3",
|
|
5
5
|
"description": "Learn while your agent works. Turns coding-agent generation time into adaptive, Socratic learning grounded in the code being written.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Ajay Kumar"
|
package/package.json
CHANGED