eklavya 1.9.2 → 1.9.4
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
|
@@ -34,14 +34,15 @@
|
|
|
34
34
|
--vd-300: #79D5C4; /* accent on ink — 10.33:1 */
|
|
35
35
|
--vd-400: #3FB8A3;
|
|
36
36
|
--vd-500: #199688;
|
|
37
|
-
--vd-600: #0E6E66;
|
|
38
|
-
--vd-700: #0A5751;
|
|
37
|
+
--vd-600: #0E6E66;
|
|
38
|
+
--vd-700: #0A5751; /* accent on paper — 7.20:1 on the ground, 5.10:1 on a tint */
|
|
39
39
|
--vd-800: #07403C;
|
|
40
40
|
--vd-900: #052E2B;
|
|
41
41
|
|
|
42
42
|
/* ---------- SEMANTIC (real errors and warnings only) ----------
|
|
43
|
-
Kept off the accent hue so state never reads as branding.
|
|
44
|
-
|
|
43
|
+
Kept off the accent hue so state never reads as branding. Both are
|
|
44
|
+
redefined per ground below: an orange that carries on ink is 2.3:1 on
|
|
45
|
+
cream, which fails as text and as a chart fill alike. */
|
|
45
46
|
--error: #E5484D;
|
|
46
47
|
--info: #4A9EFF;
|
|
47
48
|
|
|
@@ -128,7 +129,7 @@
|
|
|
128
129
|
|
|
129
130
|
--ink: #EAE7E1; /* primary text */
|
|
130
131
|
--dim: #A29C93; /* secondary */
|
|
131
|
-
--faint: #
|
|
132
|
+
--faint: #8B857B; /* captions, micro-labels — 4.89:1 on ink */
|
|
132
133
|
--faint-2: #565249; /* disabled, placeholder */
|
|
133
134
|
|
|
134
135
|
--line: #26262a; /* hairline */
|
|
@@ -142,6 +143,8 @@
|
|
|
142
143
|
--glow: rgba(25,150,136,.22); /* the terminal's halo */
|
|
143
144
|
--glow-low: rgba(25,150,136,.10);
|
|
144
145
|
--shot-op: .28; /* the arrow scene, as ambient art */
|
|
146
|
+
--warning: #E8920C;
|
|
147
|
+
--code-bg: var(--mass); /* the well behind a code block */
|
|
145
148
|
--shadow-lg: 0 12px 28px rgba(0,0,0,.45);
|
|
146
149
|
--ring: 0 0 0 2px var(--bg), 0 0 0 4px var(--spot);
|
|
147
150
|
}
|
|
@@ -153,13 +156,13 @@
|
|
|
153
156
|
|
|
154
157
|
--ink: #16150f;
|
|
155
158
|
--dim: #57534a;
|
|
156
|
-
--faint: #
|
|
159
|
+
--faint: #635E52; /* 5.04:1 on --panel, the darkest ground it sits on */
|
|
157
160
|
--faint-2: #a09a8c;
|
|
158
161
|
|
|
159
162
|
--line: #e3dfd4;
|
|
160
163
|
--line-2: #cec8b9;
|
|
161
164
|
|
|
162
|
-
--spot: var(--vd-
|
|
165
|
+
--spot: var(--vd-700);
|
|
163
166
|
--spot-ink: #ffffff;
|
|
164
167
|
--spot-soft: color-mix(in srgb, var(--spot) 10%, transparent);
|
|
165
168
|
|
|
@@ -169,6 +172,11 @@
|
|
|
169
172
|
--glow: rgba(14,110,102,.10);
|
|
170
173
|
--glow-low: rgba(14,110,102,.05);
|
|
171
174
|
--shot-op: .5;
|
|
175
|
+
--warning: #7A4B00; /* 5.21:1 on --mass */
|
|
176
|
+
/* A syntax theme's dimmest token (comments) lands at 3.9:1 on --mass. The
|
|
177
|
+
well is lightened rather than the theme repainted, which lifts every
|
|
178
|
+
token at once; the frame's border is what still reads it as a block. */
|
|
179
|
+
--code-bg: #EDEAE2;
|
|
172
180
|
--shadow-lg: 0 12px 28px rgba(22,21,15,.10);
|
|
173
181
|
--ring: 0 0 0 2px var(--bg), 0 0 0 4px var(--spot);
|
|
174
182
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eklavya",
|
|
3
3
|
"displayName": "Eklavya",
|
|
4
|
-
"version": "1.9.
|
|
4
|
+
"version": "1.9.4",
|
|
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