Build your first app
This tutorial walks through building a system monitoring dashboard. By the end you'll have gauges, a process table, log output, and keyboard navigation between panels.
What we're building- CPU and memory usage gauges- A process list table- A log viewer with auto-scroll- Tab to switch between panels, q to quit
Step 1: create the project
TYPESCRIPT
$ npx create-termui-app my-dashboard
$ cd my-dashboard
$ npm install @termuijs/widgets @termuijs/tss @termuijs/dataStep 2: set up a theme
Create src/theme.tss with your dashboard color palette:
TYPESCRIPT
@theme dashboard {
--primary: #00ff88;
--secondary: #00d4ff;
--bg: #0a0a0f;
--border: #2a2a45;
--text: #e8e8f0;
--dim: #55557a;
}
Box {
border-color: var(--border);
}
Box:focused {
border-color: var(--primary);
}
Text {
color: var(--text);
}
Text.dim {
color: var(--dim);
}Then load it in your app entry point:
TYPESCRIPT
import { ThemeEngine } from '@termuijs/tss'
import { readFileSync } from 'node:fs'
const engine = new ThemeEngine()
engine.load(readFileSync('./src/theme.tss', 'utf8'))
engine.setTheme('dashboard')Step 3: build the layout
Build the widget tree and immediately mount the app so the screen is live while data loads:
TYPESCRIPT
import { App } from '@termuijs/core'
import { Box, Text, ProgressBar, Table } from '@termuijs/widgets'
// Header
const header = new Box({ padding: 1, border: 'single' })
header.addChild(new Text('System Dashboard', { bold: true }))
// Gauge panel
const gaugePanel = new Box({ flexDirection: 'column', padding: 1 })
const cpuBar = new ProgressBar({ width: 25, label: 'CPU' })
const memBar = new ProgressBar({ width: 25, label: 'MEM' })
gaugePanel.addChild(cpuBar)
gaugePanel.addChild(memBar)
// Process panel
const processPanel = new Box({ flexGrow: 1, padding: 1, border: 'single' })
processPanel.addChild(new Text('Processes', { dim: true, className: 'dim' }))
// Log panel
const logPanel = new Box({ height: 8, padding: 1, border: 'single' })
logPanel.addChild(new Text('Logs', { dim: true, className: 'dim' }))
// Assemble the layout
const content = new Box({ flexDirection: 'row', flexGrow: 1 })
content.addChild(gaugePanel)
content.addChild(new Box({ flexDirection: 'column', flexGrow: 1 }, [processPanel, logPanel]))
const root = new Box({ flexDirection: 'column' })
root.addChild(header)
root.addChild(content)
// Apply theme to the tree
engine.onChange(() => {
root.applyStyles(engine.resolveStyle('Box'))
app.requestRender()
})
root.applyStyles(engine.resolveStyle('Box'))
// Mount. app is now live
const app = new App(root, { fullscreen: true })
await app.mount()Step 4: add real data
Start the data polling loop after app.mount() resolves:
TYPESCRIPT
import { cpu, memory } from '@termuijs/data'
setInterval(async () => {
const cpuInfo = await cpu()
const memInfo = await memory()
cpuBar.setValue(cpuInfo.total / 100)
memBar.setValue(memInfo.usedPercent / 100)
app.requestRender()
}, 1000)Step 5: add keyboard navigation
TYPESCRIPT
app.events.on('key', (event) => {
if (event.key === 'tab') focusNext()
if (event.key === 'q') app.exit()
})Next steps
Was this page helpful?