Palette-aware CSS component library for reports and desktop apps.
All colours are driven by def_colour_palette via get_palette().
from ObjCss import ObjCss
css_lib = ObjCss(self.DB)
css = css_lib.get_component_css()
# inject into your HTML template:
# <style>{css}</style>
To load specific components only:
css = css_lib.get_component_css(
"variables", "reset", "layout", "panel", "table"
)
For shared browser-cached CSS, use:
link = ObjCss.get_component_css_link()
This returns:
<link rel="stylesheet" href="/css/components.css">
The /css/components.css route serves the component stylesheet with
Cache-Control and ETag headers. get_css_max_age() controls the
cache duration by deployment mode: 60 seconds in DEV, 300 seconds in
UAT/STAGING, and 3600 seconds in production-like environments.
Every report page follows this skeleton:
<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{title}</title>
<style>{css}</style>
</head>
<body>
<div class="ax-wrap">
<div class="ax-header">
<div class="ax-pulse"></div>
<h1 class="ax-h1">Page Title</h1>
<span class="ax-muted ax-ml-auto">Subtitle</span>
</div>
<!-- content here -->
</div>
</body></html>
ax-wrap — centred container, max 1400px, full heightax-header — flex row with gap, wraps on small screensax-pulse — green animated dot (live indicator)ax-ml-auto — push element to the rightAll components use CSS custom properties. Override at :root
or let ObjCss generate them from the palette.
| Variable | Default | Purpose |
|---|---|---|
--ax-primary |
#6c5ce7 |
Brand colour |
--ax-secondary |
#1e2d3e |
Panel background |
--ax-accent |
#00aff0 |
Highlights, links, headings |
--ax-success |
#2abd89 |
OK/up states |
--ax-danger |
#d9534f |
Error/down states |
--ax-warning |
#f0ad4e |
Warning states |
--ax-info |
#0086f7 |
Info states |
--ax-light |
#f0f2f5 |
Light backgrounds |
--ax-dark |
#0f1923 |
Page background |
--ax-panel |
#1e2d3e |
Card/section background |
--ax-text |
#e0e0e0 |
Body text |
--ax-muted |
#888888 |
Secondary text, labels |
--ax-border |
#333333 |
Borders, dividers |
--ax-bg |
#0f1923 |
Page background |
--ax-font |
System stack | Font family |
--ax-radius |
6px |
Default border radius |
--ax-radius-sm |
3px |
Small radius (cells, bars) |
--ax-radius-lg |
10px |
Large radius (badges) |
--ax-gap |
10px |
Default spacing |
--ax-gap-sm |
6px |
Tight spacing |
--ax-gap-lg |
16px |
Loose spacing |
<h1 class="ax-h1">Main Title</h1>
<h2 class="ax-h2">SECTION TITLE</h2>
<h3 class="ax-h3">Subsection</h3>
<span class="ax-muted">Secondary text</span>
<span class="ax-small">Fine print</span>
<span class="ax-ip">10.0.10.20</span>
ax-h1 — 28px white, page titleax-h2 — 18px accent, uppercase, section headerax-h3 — 15px accent, subsectionax-muted — grey secondary textax-small — 12px grey fine printax-ip — 11px dark grey for IP addressesContainer for grouped content.
<div class="ax-panel">
<h2 class="ax-h2">Section Title</h2>
<!-- content -->
</div>
<!-- 2-column grid -->
<div class="ax-grid ax-grid-2">
<div class="ax-panel">Left</div>
<div class="ax-panel">Right</div>
</div>
<!-- 3-column grid -->
<div class="ax-grid ax-grid-3">...</div>
<!-- Auto-fit responsive grid (for metric cards) -->
<div class="ax-grid ax-grid-auto">...</div>
<!-- Single column -->
<div class="ax-grid ax-full">...</div>
Grids collapse to single column below 800px.
For dashboard overview metrics.
<div class="ax-kpi-row">
<div class="ax-kpi">
<div class="ax-kpi-val">42</div>
<div class="ax-kpi-lbl">Total Hosts</div>
</div>
<div class="ax-kpi ok">
<div class="ax-kpi-val">40</div>
<div class="ax-kpi-lbl">Hosts Up</div>
</div>
<div class="ax-kpi danger">
<div class="ax-kpi-val">2</div>
<div class="ax-kpi-lbl">Hosts Down</div>
</div>
</div>
Modifiers: ok (green), warn (yellow), danger (red).
For detail page metrics. Larger values than KPI.
<div class="ax-grid ax-grid-auto">
<div class="ax-metric">
<div class="val">4.2%</div>
<div class="lbl">CPU</div>
</div>
<div class="ax-metric warn">
<div class="val">72.1%</div>
<div class="lbl">Disk</div>
</div>
<div class="ax-metric danger">
<div class="val">91.3%</div>
<div class="lbl">Memory</div>
</div>
</div>
Modifiers: warn (yellow value), danger (red value).
<table class="ax-tbl">
<thead>
<tr>
<th>Host</th>
<th>Status</th>
<th>CPU</th>
</tr>
</thead>
<tbody>
<tr>
<td>mariadb</td>
<td>OK</td>
<td>4%</td>
</tr>
</tbody>
</table>
<table class="ax-tbl">
<tr>
<td class="ax-label">Description</td>
<td>Linux mariadb 6.17</td>
</tr>
<tr>
<td class="ax-label">Uptime</td>
<td>14d 3h</td>
</tr>
</table>
ax-label on the first td makes it grey, 160px wide.
<span class="ax-badge up">UP</span>
<span class="ax-badge down">DOWN</span>
<span class="ax-badge src">proxmox</span>
<span class="ax-badge warn">WARNING</span>
<a class="ax-btn" href="#">Back</a>
<button class="ax-btn-primary">Save</button>
<div class="ax-alert">
<strong>mariadb</strong> Disk 92%
</div>
<div class="ax-alert warn">
<strong>keycloak</strong> Load 8.5
</div>
<div class="ax-alert ok">
<strong>hypervisor</strong> Recovered
</div>
<div class="ax-bar">
<div class="ax-bar-fill ok" style="width:45%"></div>
</div>
<div class="ax-bar">
<div class="ax-bar-fill warn" style="width:72%"></div>
</div>
<div class="ax-bar">
<div class="ax-bar-fill danger" style="width:95%"></div>
</div>
Used for multi-host metric overviews.
<table class="ax-hm-tbl">
<thead>
<tr>
<th>Host</th>
<th>CPU</th>
<th>Disk</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div class="ax-hm-host">
<div class="ax-hm-dot up"></div>
Mariadb <span class="ax-ip">10.0.10.20</span>
</div>
</td>
<td><span class="ax-hm-cell g1">4%</span></td>
<td><span class="ax-hm-cell y2">72%</span></td>
</tr>
</tbody>
</table>
Heatmap cell severity classes:
| Class | Range | Colour |
|---|---|---|
g0 |
0-15% | Light green |
g1 |
15-30% | Green |
g2 |
30-50% | Bright green |
y1 |
50-65% | Yellow |
y2 |
65-80% | Orange |
r1 |
80-90% | Red |
r2 |
90-100% | Dark red |
na |
No data | Grey |
<input class="ax-input" type="text" placeholder="Search...">
<select class="ax-select">
<option>Option 1</option>
</select>
Create ObjReportMyreport.py and ObjReportMyreport.yaml
in factory.report/package.system/
In the Python class:
from ObjCss import ObjCss
class Report(ObjData.ObjData):
def Render(self, param1="", ...):
css = ObjCss(self.DB).get_component_css()
# ... build your content using ax-* classes
tpl = self.get_html("my_page")
return tpl.format(css=css, ...)
database:
queries:
my_query: |
SELECT ...
html:
my_page: |
<!DOCTYPE html>
<html><head>
<meta charset="utf-8">
<style>{css}</style>
</head>
<body>
<div class="ax-wrap">
<div class="ax-header">
<h1 class="ax-h1">My Report</h1>
</div>
<div class="ax-panel">
<h2 class="ax-h2">Data</h2>
{table_html}
</div>
</div>
</body></html>
When using ObjDesktopApp, the wrapper injects a base font-size: 18px
on html, body. ObjCss classes use relative sizing where possible
but some components use fixed px values for consistency.
The app wrapper also injects the _appShowDetail() and _appGoBack()
JS functions for click-through navigation between reports.
Change colours in def_colour_palette (database) and every report
updates on next render. No code changes needed.
UPDATE def_colour_palette
SET accent = '#ff6b6b'
WHERE PaletteName = 'gekkoridge'