Themes
A theme owns the entire visual representation - the palette (per-role ANSI style
codes), the glyphs (marker, caret, scroll indicators, separators - each a
Unicode/ASCII pair) and how every row is composed. DefaultTheme implements all
of it with a neutral base; a concrete theme extends it and overrides only what it
changes. The ThemeManager turns a theme name into an instance.
Built-in themes
Five themes ship built-in, each selectable by name:
use DrevOps\Tui\Builder\Form;
Form::create('My form')->theme('midnight')/* ... */;
| Name | Palette |
|---|---|
default | Cyan accents on a neutral base - the out-of-the-box look. |
midnight | Violet accents, green values, pink highlights. |
frost | Arctic frost-blue accents, sage values, sand highlights. |
ember | Burnt-orange accents, olive values, gold highlights. |
mono | Hue-free - bold weight, grey levels and reverse video, for maximum compatibility. |
The curated themes use 256-colour palettes; every one renders across all widgets and degrades to plain text when colour is off. An unknown theme name fails loudly
- a typo never silently falls back to the default.
Each adapts to the terminal background - here the dark palette (left) and the light palette (right):
midnight
frost
ember
mono
Dark and light
Dark and light are not separate themes but a mode display option that every
theme honours. When a form sets no theme (or the explicit 'auto' sentinel), the
interactive TUI picks the mode from the actual terminal background: it queries the
background colour over OSC 11, falls back to the COLORFGBG environment variable,
and settles on dark when neither answers.
Form::create('My form')->theme('frost', ['mode' => 'light']); // force light
Form::create('My form')->theme('frost'); // auto-detect
Writing a theme
A custom theme subclasses DefaultTheme and overrides only what it changes -
every role it does not mention keeps working, including the dark/light mode. The
quickest way to recolour is the palette seam: five per-role style accessors the
appearance atoms read.
use DrevOps\Tui\Theme\DefaultTheme;
class AquaTheme extends DefaultTheme {
protected function accentSgr(): string { return $this->isDark ? '1;38;5;44' : '1;38;5;24'; }
protected function valueSgr(): string { return $this->isDark ? '38;5;80' : '38;5;30'; }
}
accentSgr() drives the title, the highlighted row, the marker, the radio dot
and the caret; valueSgr(), indicatorSgr(), matchSgr() and borderSgr()
colour the remaining roles. For finer control, override an individual appearance
atom (title(), marker(), caret()…) or a render*() method to change how an
element is laid out.
Lowest friction: a form names the class directly, with no registration:
$form = Form::create('My form')->theme('\App\AquaTheme')/* ... */;
Or register a short alias with ThemeManager::register('aqua', AquaTheme::class),
then ->theme('aqua'). The playground's ocean
theme goes
further, overriding many atoms and render*() methods for a distinct look with a
start banner: