x12i-downloads 0.2.0 → 0.2.2
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/README.md +4 -2
- package/app/admin/page.tsx +2 -1
- package/app/globals.css +336 -142
- package/app/layout.tsx +2 -5
- package/app/page.tsx +17 -16
- package/components/cumulative-chart.tsx +166 -55
- package/components/downloads-dashboard.tsx +106 -30
- package/lib/config.ts +16 -0
- package/lib/insights.mjs +1 -1
- package/lib/npm-client.ts +21 -82
- package/lib/npm-stats-live.ts +16 -1
- package/lib/npm-stats-shared.ts +2 -1
- package/package.json +5 -3
- package/public/x12i-stats.json +15 -15
- package/scripts/build-verified.sh +5 -0
- package/scripts/install-ci.sh +11 -3
- package/scripts/remote-d1.mjs +12 -7
- package/tests/rendered-html.test.mjs +12 -1
- package/tests/stats-refresh.test.mjs +7 -6
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# @x12i Total Downloads
|
|
2
2
|
|
|
3
|
+
This is the `x12i-downloads` package in the x12i-stats monorepo (`packages/x12i-stats`). Run the commands below from this directory, or from the repo root with `npm run <script> -w x12i-downloads`.
|
|
4
|
+
|
|
3
5
|
A React dashboard that counts cumulative npm downloads of every package the `@x12i` org has ever published, since March 20, 2026.
|
|
4
6
|
|
|
5
7
|
Live: https://stats.x12i.com (also https://x12i-downloads.ami-3ad.workers.dev)
|
|
@@ -10,7 +12,7 @@ Live: https://stats.x12i.com (also https://x12i-downloads.ami-3ad.workers.dev)
|
|
|
10
12
|
- `packages` remembers every package ever discovered. Each run counts the union of known packages and npm's current org listing, so a package that leaves the listing keeps counting.
|
|
11
13
|
- `package_daily` stores per-package daily downloads. A stored day is only ever raised, never lowered or deleted, so the total cannot go down when npm revises or drops data.
|
|
12
14
|
- A new total is refused (the published one is held) if it would be lower; `stats_history` keeps one row per published day.
|
|
13
|
-
- npm publishes day D on D+1 at the earliest, sometimes stalls for days, and sometimes skips days for every package. Days npm reports as 0 for every package are estimated, through yesterday: each package gets the average of its last 7 days with downloads (within the 30 days before npm's last counted day), as an integer. "Skipped" days are ones npm moved past; "pending" days are after npm's latest counted day. Estimates are computed at publish time and never stored in `package_daily`, so npm's real counts replace them as soon as npm publishes or backfills those days.
|
|
15
|
+
- npm publishes day D on D+1 at the earliest, sometimes stalls for days, and sometimes skips days for every package. Days npm reports as 0 for every package are estimated, through yesterday: each package gets the average of its last 7 days with downloads (within the 30 days before npm's last counted day), as an integer, and the day's sum is capped at the org's real average over the 7 days npm counted before it (so sparse packages and org-wide sweep days don't inflate it). "Skipped" days are ones npm moved past; "pending" days are after npm's latest counted day. Estimates are computed at publish time and never stored in `package_daily`, so npm's real counts replace them as soon as npm publishes or backfills those days. If real counts arrive lower than the estimates, the total is held until real downloads catch up.
|
|
14
16
|
|
|
15
17
|
## Refresh schedule
|
|
16
18
|
|
|
@@ -92,7 +94,7 @@ npm test
|
|
|
92
94
|
## Main source files
|
|
93
95
|
|
|
94
96
|
- `lib/npm-stats-live.ts` — refresh state machine and SQL (shared by Worker and local runner)
|
|
95
|
-
- `lib/npm-client.ts` —
|
|
97
|
+
- `lib/npm-client.ts` — download-range client with a fetch budget. Org discovery goes through `@x12i/npm-core`
|
|
96
98
|
- `migrations/` — D1 / SQLite schema
|
|
97
99
|
- `lib/insights.mjs` — analytics SDK (leaders, movers, concentration, anomalies, lifecycle, report rendering)
|
|
98
100
|
- `lib/sqlite-d1.mjs` — D1-compatible adapter over `node:sqlite`
|
package/app/admin/page.tsx
CHANGED
|
@@ -279,7 +279,8 @@ export default function AdminPage() {
|
|
|
279
279
|
<h2>Estimated days ({estimatedDays.length})</h2>
|
|
280
280
|
<p className="muted small">
|
|
281
281
|
Days npm reports as 0 for every package. Each package is estimated as the average of its last 7 days
|
|
282
|
-
with downloads (within 30 days)
|
|
282
|
+
with downloads (within 30 days), and each day is capped at the org's real average over the 7 days npm
|
|
283
|
+
counted before it. npm's real counts replace these whenever npm publishes them.
|
|
283
284
|
</p>
|
|
284
285
|
<div className="admin-table-wrap">
|
|
285
286
|
<table className="admin-table">
|
package/app/globals.css
CHANGED
|
@@ -1,17 +1,41 @@
|
|
|
1
1
|
@import "tailwindcss";
|
|
2
2
|
|
|
3
3
|
:root {
|
|
4
|
-
|
|
4
|
+
color-scheme: dark;
|
|
5
|
+
--background: #0b1222;
|
|
5
6
|
--surface: #111c30;
|
|
6
|
-
--
|
|
7
|
-
--
|
|
8
|
-
--
|
|
9
|
-
--muted
|
|
7
|
+
--card: #0f1a2e;
|
|
8
|
+
--surface-border: #22304a;
|
|
9
|
+
--foreground: #f1f5f9;
|
|
10
|
+
--muted: #a3b2c7;
|
|
11
|
+
--muted-dark: #8293ab;
|
|
10
12
|
--accent: #38bdf8;
|
|
13
|
+
--accent-strong: #7dd3fc;
|
|
11
14
|
--accent-soft: rgba(56, 189, 248, 0.12);
|
|
12
|
-
--grid: #
|
|
15
|
+
--grid: #26344d;
|
|
16
|
+
--command-bg: rgba(8, 15, 30, 0.6);
|
|
13
17
|
--danger: #f87171;
|
|
14
|
-
--
|
|
18
|
+
--shadow: 0 28px 80px rgba(2, 6, 23, 0.45);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/* Light theme for the downloads card only; the stats admin page stays dark. */
|
|
22
|
+
@media (prefers-color-scheme: light) {
|
|
23
|
+
:root:has(.dashboard-shell) {
|
|
24
|
+
color-scheme: light;
|
|
25
|
+
--background: #eef2f7;
|
|
26
|
+
--surface: #ffffff;
|
|
27
|
+
--card: #ffffff;
|
|
28
|
+
--surface-border: #dde3ec;
|
|
29
|
+
--foreground: #0f172a;
|
|
30
|
+
--muted: #475569;
|
|
31
|
+
--muted-dark: #5b6b82;
|
|
32
|
+
--accent: #0b7ea8;
|
|
33
|
+
--accent-strong: #075c7c;
|
|
34
|
+
--accent-soft: rgba(11, 126, 168, 0.1);
|
|
35
|
+
--grid: #e3e8f0;
|
|
36
|
+
--command-bg: #f5f7fb;
|
|
37
|
+
--shadow: 0 24px 60px rgba(15, 23, 42, 0.08);
|
|
38
|
+
}
|
|
15
39
|
}
|
|
16
40
|
|
|
17
41
|
* {
|
|
@@ -26,9 +50,7 @@ html {
|
|
|
26
50
|
body {
|
|
27
51
|
min-height: 100vh;
|
|
28
52
|
margin: 0;
|
|
29
|
-
background:
|
|
30
|
-
radial-gradient(circle at 50% 0%, rgba(56, 189, 248, 0.08), transparent 32rem),
|
|
31
|
-
var(--background);
|
|
53
|
+
background: var(--background);
|
|
32
54
|
color: var(--foreground);
|
|
33
55
|
font-family: var(--font-geist-sans), Inter, ui-sans-serif, system-ui, sans-serif;
|
|
34
56
|
}
|
|
@@ -40,144 +62,159 @@ select {
|
|
|
40
62
|
font: inherit;
|
|
41
63
|
}
|
|
42
64
|
|
|
65
|
+
.sr {
|
|
66
|
+
position: absolute;
|
|
67
|
+
width: 1px;
|
|
68
|
+
height: 1px;
|
|
69
|
+
overflow: hidden;
|
|
70
|
+
clip: rect(0 0 0 0);
|
|
71
|
+
white-space: nowrap;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/* ── Card ──────────────────────────────────────────────── */
|
|
75
|
+
|
|
43
76
|
.dashboard-shell {
|
|
44
77
|
display: grid;
|
|
45
78
|
min-height: 100vh;
|
|
46
79
|
place-items: center;
|
|
47
|
-
padding: 2rem;
|
|
80
|
+
padding: 2rem 1rem;
|
|
48
81
|
}
|
|
49
82
|
|
|
50
83
|
.dashboard-card {
|
|
51
|
-
width: min(100%,
|
|
52
|
-
|
|
84
|
+
width: min(100%, 41rem);
|
|
85
|
+
padding: 2.25rem 2.25rem 2rem;
|
|
53
86
|
border: 1px solid var(--surface-border);
|
|
54
|
-
border-radius: 1.
|
|
55
|
-
background:
|
|
56
|
-
box-shadow:
|
|
57
|
-
backdrop-filter: blur(16px);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
.dashboard-content {
|
|
61
|
-
padding: 2.25rem 2.5rem 2.5rem;
|
|
87
|
+
border-radius: 1.5rem;
|
|
88
|
+
background: var(--card);
|
|
89
|
+
box-shadow: var(--shadow);
|
|
62
90
|
text-align: center;
|
|
63
91
|
}
|
|
64
92
|
|
|
65
|
-
.
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
font-weight: 700;
|
|
70
|
-
letter-spacing: 0.18em;
|
|
71
|
-
text-transform: uppercase;
|
|
93
|
+
.intro {
|
|
94
|
+
display: grid;
|
|
95
|
+
justify-items: center;
|
|
96
|
+
gap: 0.75rem;
|
|
72
97
|
}
|
|
73
98
|
|
|
74
99
|
.title {
|
|
75
100
|
margin: 0;
|
|
76
|
-
|
|
77
|
-
font-
|
|
78
|
-
|
|
101
|
+
max-width: 20ch;
|
|
102
|
+
font-size: clamp(1.6rem, 5.4vw, 2.2rem);
|
|
103
|
+
font-weight: 800;
|
|
104
|
+
letter-spacing: -0.03em;
|
|
105
|
+
line-height: 1.12;
|
|
106
|
+
text-wrap: balance;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.title-break {
|
|
110
|
+
display: block;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.description {
|
|
114
|
+
max-width: 30rem;
|
|
115
|
+
margin: 0;
|
|
116
|
+
color: var(--muted);
|
|
117
|
+
font-size: 1rem;
|
|
118
|
+
line-height: 1.55;
|
|
119
|
+
text-wrap: balance;
|
|
79
120
|
}
|
|
80
121
|
|
|
81
122
|
.metric-block {
|
|
82
|
-
margin: 2.
|
|
123
|
+
margin: 2.25rem 0 0.5rem;
|
|
83
124
|
}
|
|
84
125
|
|
|
85
126
|
.total {
|
|
86
|
-
|
|
127
|
+
margin: 0;
|
|
87
128
|
color: var(--accent);
|
|
88
|
-
font-size: clamp(3.
|
|
129
|
+
font-size: clamp(3.25rem, 15vw, 5.75rem);
|
|
89
130
|
font-variant-numeric: tabular-nums;
|
|
90
|
-
font-weight:
|
|
91
|
-
letter-spacing: -0.
|
|
131
|
+
font-weight: 850;
|
|
132
|
+
letter-spacing: -0.045em;
|
|
92
133
|
line-height: 1;
|
|
134
|
+
white-space: nowrap;
|
|
93
135
|
}
|
|
94
136
|
|
|
95
|
-
.total-
|
|
96
|
-
color: var(--
|
|
97
|
-
font-size: clamp(2.25rem, 8vw, 3.5rem);
|
|
98
|
-
letter-spacing: -0.045em;
|
|
137
|
+
.total-placeholder {
|
|
138
|
+
color: var(--grid);
|
|
99
139
|
}
|
|
100
140
|
|
|
101
|
-
.
|
|
102
|
-
margin: 0.65rem 0 0;
|
|
141
|
+
.total-empty {
|
|
103
142
|
color: var(--muted-dark);
|
|
104
|
-
font-size: 0.875rem;
|
|
105
143
|
}
|
|
106
144
|
|
|
107
|
-
.metric-
|
|
145
|
+
.metric-label {
|
|
146
|
+
margin: 0.6rem 0 0;
|
|
108
147
|
color: var(--foreground);
|
|
148
|
+
font-size: 1rem;
|
|
109
149
|
font-weight: 700;
|
|
110
150
|
}
|
|
111
151
|
|
|
112
|
-
.metric-
|
|
113
|
-
margin: 0.
|
|
114
|
-
color: var(--muted
|
|
115
|
-
font-size: 0.
|
|
152
|
+
.metric-scope {
|
|
153
|
+
margin: 0.25rem 0 0;
|
|
154
|
+
color: var(--muted);
|
|
155
|
+
font-size: 0.875rem;
|
|
116
156
|
}
|
|
117
157
|
|
|
118
|
-
.status
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
justify-content: center;
|
|
123
|
-
gap: 0.5rem;
|
|
124
|
-
margin-top: 0.4rem;
|
|
125
|
-
color: var(--muted-dark);
|
|
126
|
-
font-size: 0.75rem;
|
|
158
|
+
.metric-status {
|
|
159
|
+
margin: 0.5rem 0 0;
|
|
160
|
+
color: var(--muted);
|
|
161
|
+
font-size: 0.8rem;
|
|
127
162
|
}
|
|
128
163
|
|
|
129
|
-
|
|
130
|
-
|
|
164
|
+
/* ── Chart ─────────────────────────────────────────────── */
|
|
165
|
+
|
|
166
|
+
.chart-frame {
|
|
167
|
+
margin: 2rem 0 0;
|
|
168
|
+
text-align: left;
|
|
131
169
|
}
|
|
132
170
|
|
|
133
|
-
.
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
animation: spin 0.85s linear infinite;
|
|
171
|
+
.chart-head {
|
|
172
|
+
display: flex;
|
|
173
|
+
flex-wrap: wrap;
|
|
174
|
+
align-items: baseline;
|
|
175
|
+
justify-content: space-between;
|
|
176
|
+
gap: 0.25rem 1rem;
|
|
177
|
+
margin-bottom: 0.6rem;
|
|
141
178
|
}
|
|
142
179
|
|
|
143
|
-
.
|
|
144
|
-
margin
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
background: transparent;
|
|
149
|
-
color: inherit;
|
|
150
|
-
cursor: pointer;
|
|
151
|
-
font-weight: 700;
|
|
180
|
+
.chart-title {
|
|
181
|
+
margin: 0;
|
|
182
|
+
color: var(--muted);
|
|
183
|
+
font-size: 0.78rem;
|
|
184
|
+
font-weight: 400;
|
|
152
185
|
}
|
|
153
186
|
|
|
154
|
-
.
|
|
155
|
-
|
|
156
|
-
|
|
187
|
+
.chart-readout {
|
|
188
|
+
margin: 0;
|
|
189
|
+
color: var(--muted);
|
|
190
|
+
font-size: 0.78rem;
|
|
191
|
+
font-variant-numeric: tabular-nums;
|
|
157
192
|
}
|
|
158
193
|
|
|
159
|
-
|
|
194
|
+
.chart-readout strong {
|
|
195
|
+
color: var(--foreground);
|
|
196
|
+
font-weight: 400;
|
|
197
|
+
}
|
|
160
198
|
|
|
161
|
-
.chart-
|
|
199
|
+
.chart-plot {
|
|
162
200
|
position: relative;
|
|
163
|
-
|
|
164
|
-
height: 16rem;
|
|
165
|
-
margin-top: 1rem;
|
|
201
|
+
height: 13.5rem;
|
|
166
202
|
}
|
|
167
203
|
|
|
168
|
-
.chart-
|
|
204
|
+
.chart-plot svg {
|
|
169
205
|
display: block;
|
|
170
206
|
width: 100%;
|
|
171
207
|
height: 100%;
|
|
172
208
|
overflow: visible;
|
|
209
|
+
cursor: crosshair;
|
|
210
|
+
outline: none;
|
|
211
|
+
touch-action: pan-y;
|
|
173
212
|
}
|
|
174
213
|
|
|
175
|
-
.chart-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
color: var(--muted-dark);
|
|
180
|
-
font-size: 0.8rem;
|
|
214
|
+
.chart-plot svg:focus-visible {
|
|
215
|
+
outline: 2px solid var(--accent);
|
|
216
|
+
outline-offset: 4px;
|
|
217
|
+
border-radius: 4px;
|
|
181
218
|
}
|
|
182
219
|
|
|
183
220
|
.chart-grid {
|
|
@@ -186,10 +223,8 @@ select {
|
|
|
186
223
|
vector-effect: non-scaling-stroke;
|
|
187
224
|
}
|
|
188
225
|
|
|
189
|
-
.chart-
|
|
190
|
-
fill:
|
|
191
|
-
font-size: 12px;
|
|
192
|
-
font-variant-numeric: tabular-nums;
|
|
226
|
+
.chart-area {
|
|
227
|
+
fill: url(#area-gradient);
|
|
193
228
|
}
|
|
194
229
|
|
|
195
230
|
.chart-line {
|
|
@@ -197,18 +232,192 @@ select {
|
|
|
197
232
|
stroke: var(--accent);
|
|
198
233
|
stroke-linecap: round;
|
|
199
234
|
stroke-linejoin: round;
|
|
200
|
-
stroke-width:
|
|
235
|
+
stroke-width: 2.5;
|
|
201
236
|
vector-effect: non-scaling-stroke;
|
|
202
|
-
/* Draw animation — uses a very large dasharray; the offset animates to 0 */
|
|
203
|
-
stroke-dasharray: 2000;
|
|
204
|
-
stroke-dashoffset: 2000;
|
|
205
|
-
animation: draw-line var(--anim-duration) ease-out forwards;
|
|
206
237
|
}
|
|
207
238
|
|
|
208
|
-
.chart-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
239
|
+
.chart-guide {
|
|
240
|
+
stroke: var(--muted-dark);
|
|
241
|
+
stroke-width: 1;
|
|
242
|
+
stroke-dasharray: 3 4;
|
|
243
|
+
vector-effect: non-scaling-stroke;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.chart-dot {
|
|
247
|
+
position: absolute;
|
|
248
|
+
width: 11px;
|
|
249
|
+
height: 11px;
|
|
250
|
+
border: 2px solid var(--card);
|
|
251
|
+
border-radius: 50%;
|
|
252
|
+
background: var(--accent);
|
|
253
|
+
box-shadow: 0 0 0 4px var(--accent-soft);
|
|
254
|
+
transform: translate(-50%, -50%);
|
|
255
|
+
pointer-events: none;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.chart-y-axis {
|
|
259
|
+
position: absolute;
|
|
260
|
+
inset: 0 auto 0 0;
|
|
261
|
+
width: calc(64 / 760 * 100%);
|
|
262
|
+
pointer-events: none;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.chart-y-axis span {
|
|
266
|
+
position: absolute;
|
|
267
|
+
right: 0.6rem;
|
|
268
|
+
transform: translateY(-50%);
|
|
269
|
+
color: var(--muted-dark);
|
|
270
|
+
font-size: 0.72rem;
|
|
271
|
+
font-variant-numeric: tabular-nums;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.chart-x-axis {
|
|
275
|
+
position: absolute;
|
|
276
|
+
right: 0;
|
|
277
|
+
bottom: 0;
|
|
278
|
+
left: 0;
|
|
279
|
+
height: 1.1rem;
|
|
280
|
+
pointer-events: none;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
.chart-x-axis span {
|
|
284
|
+
position: absolute;
|
|
285
|
+
bottom: 0;
|
|
286
|
+
transform: translateX(-50%);
|
|
287
|
+
color: var(--muted-dark);
|
|
288
|
+
font-size: 0.72rem;
|
|
289
|
+
white-space: nowrap;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/* ── Agent setup ───────────────────────────────────────── */
|
|
293
|
+
|
|
294
|
+
.setup {
|
|
295
|
+
display: grid;
|
|
296
|
+
justify-items: center;
|
|
297
|
+
gap: 0.55rem;
|
|
298
|
+
margin-top: 1.75rem;
|
|
299
|
+
padding-top: 1.5rem;
|
|
300
|
+
border-top: 1px solid var(--surface-border);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.setup-title {
|
|
304
|
+
margin: 0;
|
|
305
|
+
font-size: 1.05rem;
|
|
306
|
+
font-weight: 750;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.setup-description {
|
|
310
|
+
margin: 0;
|
|
311
|
+
color: var(--muted);
|
|
312
|
+
font-size: 0.92rem;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
.setup-row {
|
|
316
|
+
display: flex;
|
|
317
|
+
flex-wrap: wrap;
|
|
318
|
+
align-items: center;
|
|
319
|
+
justify-content: center;
|
|
320
|
+
gap: 0.6rem 1rem;
|
|
321
|
+
width: 100%;
|
|
322
|
+
margin-top: 0.35rem;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.setup-command {
|
|
326
|
+
display: flex;
|
|
327
|
+
flex: 0 1 25rem;
|
|
328
|
+
align-items: center;
|
|
329
|
+
gap: 0.6rem;
|
|
330
|
+
min-width: 0;
|
|
331
|
+
min-height: 2.75rem;
|
|
332
|
+
padding: 0.3rem 0.3rem 0.3rem 0.9rem;
|
|
333
|
+
border: 1px solid var(--surface-border);
|
|
334
|
+
border-radius: 0.7rem;
|
|
335
|
+
background: var(--command-bg);
|
|
336
|
+
text-align: left;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
.setup-prompt {
|
|
340
|
+
color: var(--muted-dark);
|
|
341
|
+
font-family: var(--font-geist-mono), ui-monospace, monospace;
|
|
342
|
+
font-size: 0.9rem;
|
|
343
|
+
user-select: none;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.setup-command code {
|
|
347
|
+
flex: 1;
|
|
348
|
+
min-width: 0;
|
|
349
|
+
color: var(--foreground);
|
|
350
|
+
font-family: var(--font-geist-mono), ui-monospace, monospace;
|
|
351
|
+
font-size: 0.9rem;
|
|
352
|
+
overflow-wrap: anywhere;
|
|
353
|
+
user-select: all;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
.setup-copy {
|
|
357
|
+
display: inline-flex;
|
|
358
|
+
min-width: 2.5rem;
|
|
359
|
+
height: 2.25rem;
|
|
360
|
+
flex: none;
|
|
361
|
+
align-items: center;
|
|
362
|
+
justify-content: center;
|
|
363
|
+
gap: 0.35rem;
|
|
364
|
+
padding: 0 0.55rem;
|
|
365
|
+
border: 0;
|
|
366
|
+
border-radius: 0.5rem;
|
|
367
|
+
background: transparent;
|
|
368
|
+
color: var(--muted);
|
|
369
|
+
cursor: pointer;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
.setup-copy:hover {
|
|
373
|
+
background: var(--accent-soft);
|
|
374
|
+
color: var(--foreground);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
.copy-feedback {
|
|
378
|
+
color: var(--accent);
|
|
379
|
+
font-size: 0.8rem;
|
|
380
|
+
font-weight: 700;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
.setup-copy:focus-visible,
|
|
384
|
+
.catalog-link:focus-visible {
|
|
385
|
+
outline: 2px solid var(--accent);
|
|
386
|
+
outline-offset: 3px;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
.catalog-link {
|
|
390
|
+
display: inline-flex;
|
|
391
|
+
min-height: 2.75rem;
|
|
392
|
+
align-items: center;
|
|
393
|
+
padding: 0 0.4rem;
|
|
394
|
+
border-radius: 0.5rem;
|
|
395
|
+
color: var(--accent);
|
|
396
|
+
font-size: 0.92rem;
|
|
397
|
+
font-weight: 700;
|
|
398
|
+
text-underline-offset: 4px;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
.catalog-link:hover {
|
|
402
|
+
color: var(--accent-strong);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
.setup-help {
|
|
406
|
+
margin: 0;
|
|
407
|
+
color: var(--muted);
|
|
408
|
+
font-size: 0.82rem;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
.setup-prompt-hint {
|
|
412
|
+
max-width: 30rem;
|
|
413
|
+
margin: 0.35rem 0 0;
|
|
414
|
+
color: var(--muted-dark);
|
|
415
|
+
font-size: 0.8rem;
|
|
416
|
+
line-height: 1.5;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
.setup-prompt-hint q {
|
|
420
|
+
color: var(--muted);
|
|
212
421
|
}
|
|
213
422
|
|
|
214
423
|
/* ── Admin ─────────────────────────────────────────────── */
|
|
@@ -414,63 +623,48 @@ select {
|
|
|
414
623
|
color: var(--danger);
|
|
415
624
|
}
|
|
416
625
|
|
|
417
|
-
/* ── Keyframes ────────────────────────────────────────── */
|
|
418
|
-
|
|
419
|
-
@keyframes spin {
|
|
420
|
-
to { transform: rotate(360deg); }
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
@keyframes draw-line {
|
|
424
|
-
to { stroke-dashoffset: 0; }
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
@keyframes fade-area {
|
|
428
|
-
0% { opacity: 0; }
|
|
429
|
-
40% { opacity: 0; }
|
|
430
|
-
100% { opacity: 1; }
|
|
431
|
-
}
|
|
432
|
-
|
|
433
626
|
/* ── Responsive ───────────────────────────────────────── */
|
|
434
627
|
|
|
435
628
|
@media (max-width: 640px) {
|
|
436
629
|
.dashboard-shell {
|
|
437
|
-
|
|
438
|
-
padding: 0;
|
|
630
|
+
padding: 0.75rem;
|
|
439
631
|
}
|
|
440
632
|
|
|
441
633
|
.dashboard-card {
|
|
442
|
-
|
|
443
|
-
border:
|
|
444
|
-
border-radius: 0;
|
|
634
|
+
padding: 1.6rem 1.15rem 1.25rem;
|
|
635
|
+
border-radius: 1.25rem;
|
|
445
636
|
}
|
|
446
637
|
|
|
447
|
-
.
|
|
448
|
-
|
|
638
|
+
.title {
|
|
639
|
+
font-size: clamp(1.55rem, 7.4vw, 1.75rem);
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
.description {
|
|
643
|
+
font-size: 0.95rem;
|
|
449
644
|
}
|
|
450
645
|
|
|
451
646
|
.metric-block {
|
|
452
|
-
margin-top:
|
|
647
|
+
margin-top: 1.9rem;
|
|
453
648
|
}
|
|
454
649
|
|
|
455
|
-
.chart-
|
|
456
|
-
height:
|
|
457
|
-
margin-top: 2rem;
|
|
650
|
+
.chart-plot {
|
|
651
|
+
height: 11.5rem;
|
|
458
652
|
}
|
|
459
|
-
}
|
|
460
653
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
654
|
+
.chart-x-axis .tick-wide-only {
|
|
655
|
+
display: none;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
.setup-row {
|
|
659
|
+
flex-direction: column;
|
|
660
|
+
align-items: stretch;
|
|
464
661
|
}
|
|
465
662
|
|
|
466
|
-
.
|
|
467
|
-
|
|
468
|
-
stroke-dashoffset: 0;
|
|
469
|
-
animation: none;
|
|
663
|
+
.setup-command {
|
|
664
|
+
flex-basis: auto;
|
|
470
665
|
}
|
|
471
666
|
|
|
472
|
-
.
|
|
473
|
-
|
|
474
|
-
animation: none;
|
|
667
|
+
.catalog-link {
|
|
668
|
+
justify-content: center;
|
|
475
669
|
}
|
|
476
670
|
}
|
package/app/layout.tsx
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { Metadata } from "next";
|
|
2
2
|
import { Geist, Geist_Mono } from "next/font/google";
|
|
3
|
-
import { PACKAGE_SCOPE } from "@/lib/config";
|
|
4
3
|
import "./globals.css";
|
|
5
4
|
|
|
6
5
|
const geistSans = Geist({
|
|
@@ -13,11 +12,9 @@ const geistMono = Geist_Mono({
|
|
|
13
12
|
subsets: ["latin"],
|
|
14
13
|
});
|
|
15
14
|
|
|
16
|
-
const scopeDisplay = PACKAGE_SCOPE.replace(/\/$/, "");
|
|
17
|
-
|
|
18
15
|
export const metadata: Metadata = {
|
|
19
|
-
title:
|
|
20
|
-
description:
|
|
16
|
+
title: "x12i · SDK ecosystem",
|
|
17
|
+
description: "The SDK ecosystem built for coding agents: reusable packages for data, intelligence, logic, presentation and tools. npm downloads across the x12i package catalog.",
|
|
21
18
|
other: {
|
|
22
19
|
"codex-preview": "development",
|
|
23
20
|
},
|