116 lines
3.1 KiB
JavaScript
116 lines
3.1 KiB
JavaScript
/** Guest TUI dashboard. Raw JS: list + detail, resize-aware. */
|
|
|
|
async function run(ctx) {
|
|
if (!ctx.tui || !ctx.tui.isTTY()) {
|
|
ctx.console.error('tui-dashboard: needs a TTY')
|
|
ctx.exitCode = 1
|
|
return
|
|
}
|
|
|
|
const items = [
|
|
{
|
|
title: 'corestore',
|
|
desc: 'A namespaced collection of hypercores. Corestore manages many cores under one storage root.'
|
|
},
|
|
{
|
|
title: 'hyperswarm',
|
|
desc: 'Find and connect to peers by topic. Hole-punching and connection management.'
|
|
},
|
|
{
|
|
title: 'hypercore',
|
|
desc: 'A secure append-only log — the primitive everything is built on.'
|
|
},
|
|
{
|
|
title: 'hyperdrive',
|
|
desc: 'A distributed filesystem on hypercore and hyperbee. Replicated peer to peer.'
|
|
},
|
|
{
|
|
title: 'ctx.tui',
|
|
desc: 'Bare OS guest TUI on ctx. Raw JS, session streams, Fish suspend, VFS filepicker.'
|
|
}
|
|
]
|
|
|
|
function wrap(text, w) {
|
|
const out = []
|
|
for (const para of String(text).split('\n')) {
|
|
let line = ''
|
|
for (const word of para.split(' ')) {
|
|
if (line && line.length + 1 + word.length > w) {
|
|
out.push(line)
|
|
line = word
|
|
} else {
|
|
line = line ? line + ' ' + word : word
|
|
}
|
|
}
|
|
out.push(line)
|
|
}
|
|
return out.join('\n')
|
|
}
|
|
|
|
const LIST_W = 18
|
|
const app = {
|
|
list: ctx.tui.list.create({ items: items, height: 10, width: LIST_W }),
|
|
detail: ctx.tui.viewport.create({ width: 40, height: 10 }),
|
|
width: 80,
|
|
height: 24,
|
|
init: function () {
|
|
this._sync()
|
|
return null
|
|
},
|
|
_sync: function () {
|
|
const item = this.list.selectedItem()
|
|
this.detail.setContent(
|
|
item ? wrap(item.desc, this.detail.width || 40) : ''
|
|
)
|
|
this.detail.gotoTop()
|
|
},
|
|
_layout: function () {
|
|
const bodyH = Math.max(3, this.height - 5)
|
|
this.list.height = bodyH
|
|
this.detail.height = bodyH
|
|
this.detail.width = Math.max(10, this.width - LIST_W - 8)
|
|
this._sync()
|
|
},
|
|
update: function (msg) {
|
|
if (ctx.tui.key.matches(msg, 'q', 'ctrl+c')) return [this, ctx.tui.quit]
|
|
if (msg && msg.type === 'resize') {
|
|
this.width = msg.width
|
|
this.height = msg.height
|
|
this._layout()
|
|
}
|
|
const [list, lcmd] = this.list.update(msg)
|
|
this.list = list
|
|
this._sync()
|
|
const [detail, dcmd] = this.detail.update(msg)
|
|
this.detail = detail
|
|
return [this, lcmd || dcmd]
|
|
},
|
|
view: function () {
|
|
const left = ctx.tui
|
|
.style()
|
|
.border(ctx.tui.style.borders.rounded)
|
|
.width(LIST_W + 2)
|
|
.render(this.list.view())
|
|
const right = ctx.tui
|
|
.style()
|
|
.border(ctx.tui.style.borders.rounded)
|
|
.width(this.detail.width || 40)
|
|
.render(this.detail.view())
|
|
const body = ctx.tui.style.joinHorizontal(
|
|
ctx.tui.style.position.top,
|
|
left,
|
|
' ',
|
|
right
|
|
)
|
|
return (
|
|
ctx.tui.style().bold(true).render('dashboard') +
|
|
'\n' +
|
|
body +
|
|
'\n↑/↓ select · pgup/pgdn scroll · / filter · q quit'
|
|
)
|
|
}
|
|
}
|
|
|
|
await ctx.tui.run(app)
|
|
}
|