Skip to contentEnma

CLIs

There is no CSS in a terminal, but Enma's rules carry over. A CLI built this way feels like the rest of Manish's tools: calm, precise, numbers first.

The rules

  • One accent color for the single most important thing: the result, or the prompt waiting for input. Everything else uses the terminal's default color.
  • Secondary text is dim, not gray-colored. Use the dim attribute (\x1b[2m) so it works on light and dark terminals.
  • Numbers are right-aligned in tables, with units: "1,284 files", "3.2 MB", "42s".
  • Status is a word or symbol plus color, never color alone: "✔ Done", "✖ Failed", "! 3 warnings".
  • Respect the environment: honour NO_COLOR, print plain output when stdout is not a TTY, offer --json for scripts, and show spinners only on a TTY.
  • Voice: verbs first, sentence case, the outcome, no exclamation marks: "Deployed to production in 42s".

A tiny helper

ts
// ui.ts: Enma for the terminal, no dependencies
const useColor = process.stdout.isTTY && !('NO_COLOR' in process.env);
const paint = (code: string) => (text: string) => (useColor ? `\x1b[${code}m${text}\x1b[0m` : text);

/** The one accent, per theme: Graphite's lime, Ember's amber. */
export const accent = paint('38;2;212;255;58');
export const dim = paint('2');
export const ok = (text: string) => `${paint('32')('✔')} ${text}`;
export const fail = (text: string) => `${paint('31')('✖')} ${text}`;

/** Right-aligns the last column, the way Enma tables align numbers. */
export function table(rows: [string, string][]) {
  const width = Math.max(...rows.map(([label]) => label.length));
  const valueWidth = Math.max(...rows.map(([, value]) => value.length));
  return rows.map(([label, value]) => `${label.padEnd(width)}  ${value.padStart(valueWidth)}`).join('\n');
}
ts
console.log(ok(`Deployed to ${accent('production')} in 42s`));
console.log(
  table([
    ['Files', '1,284'],
    ['Size', '3.2 MB'],
    ['Cache hits', '96%'],
  ]),
);
console.log(dim('Run with --json for machine-readable output.'));

The 24-bit color is Graphite's dark accent from enma/tokens (color.graphite.dark.accent); import it instead of hard-coding when the CLI already depends on Enma.

↑ ↓ to move, Enter to open, Esc to close

Keyboard shortcuts

Open the command palette
Ctrl then K
Search
/
Show keyboard shortcuts
?
Close the top overlay
Esc
Go to Home
G then H
Go to Themes
G then T
Go to Playground
G then P
Go to Components
G then C
Go to Guides
G then G
Go to Samples
G then S