blumefi 2.6.0 → 2.6.1
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/cli.js +50 -22
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -16,6 +16,8 @@ const c = {
|
|
|
16
16
|
yellow: s => `\x1b[33m${s}\x1b[39m`,
|
|
17
17
|
red: s => `\x1b[31m${s}\x1b[39m`,
|
|
18
18
|
white: s => `\x1b[97m${s}\x1b[39m`,
|
|
19
|
+
cyan: s => `\x1b[36m${s}\x1b[39m`,
|
|
20
|
+
brightGreen: s => `\x1b[92m${s}\x1b[39m`,
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
function progressBar(pct, width = 16) {
|
|
@@ -1098,7 +1100,7 @@ async function cmdPadSearch(query) {
|
|
|
1098
1100
|
}
|
|
1099
1101
|
}
|
|
1100
1102
|
|
|
1101
|
-
function renderTokenTable(tokens, total, chain, filter) {
|
|
1103
|
+
function renderTokenTable(tokens, total, chain, filter, frame = 0) {
|
|
1102
1104
|
const lines = []
|
|
1103
1105
|
if (!tokens.length) {
|
|
1104
1106
|
lines.push(c.dim(` No tokens found (${chain}, filter: ${filter})`))
|
|
@@ -1136,12 +1138,28 @@ function renderTokenTable(tokens, total, chain, filter) {
|
|
|
1136
1138
|
|
|
1137
1139
|
for (const t of tokens) {
|
|
1138
1140
|
const pct = Math.min(t.progress || 0, 100)
|
|
1139
|
-
const
|
|
1140
|
-
const
|
|
1141
|
-
|
|
1141
|
+
const hot = pct >= 75 && !t.graduated
|
|
1142
|
+
const pulse = hot && frame % 2 === 0
|
|
1143
|
+
|
|
1144
|
+
let bar, pctStr, status, indicator
|
|
1145
|
+
if (hot) {
|
|
1146
|
+
pctStr = `${Math.round(pct)}%`
|
|
1147
|
+
const barFn = pulse ? c.brightGreen : c.green
|
|
1148
|
+
const clamped = Math.max(0, Math.min(pct, 100))
|
|
1149
|
+
const filled = Math.round((clamped / 100) * 16)
|
|
1150
|
+
const empty = 16 - filled
|
|
1151
|
+
bar = barFn('█'.repeat(filled)) + c.dim('░'.repeat(empty)) + ' ' + (pulse ? c.bold(c.brightGreen(pctStr)) : c.bold(c.yellow(pctStr)))
|
|
1152
|
+
indicator = pulse ? ' ▲' : ''
|
|
1153
|
+
status = pulse ? c.bold(c.brightGreen('Hot')) : c.yellow('Active')
|
|
1154
|
+
} else {
|
|
1155
|
+
pctStr = `${Math.round(pct)}%`
|
|
1156
|
+
bar = progressBar(pct) + ' ' + (pct >= 100 ? c.green(pctStr) : c.yellow(pctStr))
|
|
1157
|
+
indicator = ''
|
|
1158
|
+
status = t.graduated ? c.green('Graduated') : c.yellow('Active')
|
|
1159
|
+
}
|
|
1142
1160
|
|
|
1143
1161
|
const row =
|
|
1144
|
-
padRight(c.bold(t.symbol || '???'), cols.symbol) +
|
|
1162
|
+
padRight(c.bold(t.symbol || '???') + indicator, cols.symbol) +
|
|
1145
1163
|
padRight((t.name || '—').slice(0, 18), cols.name) +
|
|
1146
1164
|
padLeft(fmtPrice(t.price), cols.price) + ' ' +
|
|
1147
1165
|
padLeft(fmtNum(t.marketCap), cols.mcap) + ' ' +
|
|
@@ -1186,7 +1204,8 @@ async function cmdPadTokens() {
|
|
|
1186
1204
|
}
|
|
1187
1205
|
|
|
1188
1206
|
// Live dashboard mode
|
|
1189
|
-
const
|
|
1207
|
+
const FETCH_INTERVAL = 5000 // fetch new data every 5s
|
|
1208
|
+
const RENDER_INTERVAL = 500 // redraw for animation every 500ms
|
|
1190
1209
|
const hideCursor = () => process.stdout.write('\x1b[?25l')
|
|
1191
1210
|
const showCursor = () => process.stdout.write('\x1b[?25h')
|
|
1192
1211
|
const clearScreen = () => process.stdout.write('\x1b[2J\x1b[H')
|
|
@@ -1203,30 +1222,39 @@ async function cmdPadTokens() {
|
|
|
1203
1222
|
|
|
1204
1223
|
hideCursor()
|
|
1205
1224
|
|
|
1225
|
+
let cachedTokens = [], cachedTotal = 0, lastFetch = 0, fetchError = null, frame = 0
|
|
1226
|
+
|
|
1206
1227
|
while (running) {
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1228
|
+
// Fetch new data if stale
|
|
1229
|
+
const now = Date.now()
|
|
1230
|
+
if (now - lastFetch >= FETCH_INTERVAL) {
|
|
1231
|
+
try {
|
|
1232
|
+
const data = await apiFetch(`/pad/tokens?chain=${chain}&filter=${filter}&sort=${sort}&limit=${limit}&offset=0`)
|
|
1233
|
+
cachedTokens = data.tokens || data.data || []
|
|
1234
|
+
cachedTotal = data.total || cachedTokens.length
|
|
1235
|
+
fetchError = null
|
|
1236
|
+
} catch (err) {
|
|
1237
|
+
fetchError = err.message
|
|
1238
|
+
}
|
|
1239
|
+
lastFetch = Date.now()
|
|
1215
1240
|
}
|
|
1216
1241
|
|
|
1242
|
+
// Render current frame
|
|
1217
1243
|
clearScreen()
|
|
1218
1244
|
console.log('')
|
|
1219
|
-
|
|
1245
|
+
if (fetchError && !cachedTokens.length) {
|
|
1246
|
+
console.log(c.red(` Error fetching data: ${fetchError}`) + '\n' + c.dim(' Will retry...'))
|
|
1247
|
+
} else {
|
|
1248
|
+
console.log(renderTokenTable(cachedTokens, cachedTotal, chain, filter, frame))
|
|
1249
|
+
}
|
|
1220
1250
|
|
|
1221
|
-
const
|
|
1222
|
-
const
|
|
1251
|
+
const ts = new Date().toLocaleTimeString('en-US', { hour12: false })
|
|
1252
|
+
const nextFetchIn = Math.max(0, Math.ceil((FETCH_INTERVAL - (Date.now() - lastFetch)) / 1000))
|
|
1223
1253
|
console.log('')
|
|
1224
|
-
console.log(c.dim(` Updated ${ts} · Refreshing in ${
|
|
1254
|
+
console.log(c.dim(` Updated ${ts} · Refreshing in ${nextFetchIn}s · Ctrl+C to exit`))
|
|
1225
1255
|
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
await new Promise(r => setTimeout(r, 100))
|
|
1229
|
-
}
|
|
1256
|
+
frame++
|
|
1257
|
+
await new Promise(r => setTimeout(r, RENDER_INTERVAL))
|
|
1230
1258
|
}
|
|
1231
1259
|
}
|
|
1232
1260
|
|
package/package.json
CHANGED