@t8n/ui
v1.2.0
Published
A lightweight HTML templating engine for TitanPL with file caching and variable interpolation.
Readme
# @titanpl/ui
A **minimal, explicit UI extension for TitanPL** that lets you render HTML and inject CSS **in a single render call** — with **no static routes**, **no magic**, and **full control**.
This extension is designed for **action-based routing** and **runtime-first** TitanPL apps.
---
## ✨ Features
- `t.ui.render()` → render HTML + CSS in one call
- `t.ui.load()` → preload templates for reuse
- `t.ui.css()` → load CSS manually if needed
- Simple templating: `tpl{{ var }}`
- Explicit CSS injection (no hidden parsing)
- Memory + persistent (`ls`) caching
- Zero static file server
- Zero extra routes
- One extension, one mental model
---
## 📦 Installation
```bash
npm install @titanpl/uiTitanPL automatically loads the extension at runtime.
📁 Project Structure
app/
├─ actions/
│ └─ hello.js
├─ static/
│ ├─ app.html
│ └─ styles.cssAll paths are relative to app/.
🧠 Core Idea
TitanPL does nothing implicitly.
- HTML is rendered only when you call
t.ui.render()ort.ui.load() - CSS is injected only if you explicitly request it
- You decide where CSS goes in HTML
🧩 Template Syntax
Variables
tpl{{ name }}CSS injection point
tpl{{ css }}🚀 Usage
1️⃣ HTML Template
app/static/app.html
<!DOCTYPE html>
<html>
<head>
tpl{{ css }}
</head>
<body>
<h1>tpl{{ name }}</h1>
</body>
</html>2️⃣ CSS File
app/static/styles.css
body {
background-color: black;
height: 100vh;
}
h1 {
color: rgb(32, 215, 215);
}3️⃣ One-Shot Render (Recommended)
export const hello = () => {
return t.ui.render(
"static/app.html",
{ name: "Titan" },
{ css: "static/styles.css" }
);
};✔ HTML rendered ✔ CSS injected ✔ Single response ✔ No static routes
4️⃣ Multiple CSS Files
return t.ui.render(
"static/app.html",
{ name: "Titan" },
{ css: ["static/base.css", "static/theme.css"] }
);CSS files are injected in order.
🔁 Preloading Templates with t.ui.load()
Use this for high-traffic routes.
const page = t.ui.load("static/app.html");
export const hello = () => {
return page(
{ name: "Titan" },
{ css: "static/styles.css" }
);
};Why use load()?
- Template read once
- Faster per request
- Cleaner route code
🎯 Manual CSS Loading (Optional)
If you want full control:
export const hello = () => {
return t.ui.render("static/app.html", {
name: "Titan",
css: t.ui.css("static/styles.css")
});
};🧠 API Reference
t.ui.render(htmlPath, data?, options?)
Render HTML once with optional CSS.
t.ui.render(
"static/app.html",
{ name: "Titan" },
{ css: "static/styles.css" }
);t.ui.load(htmlPath)
Preload template and return a reusable renderer.
const page = t.ui.load("static/app.html");
page(data, options);t.ui.css(cssPath)
Load CSS and return a <style> block.
t.ui.css("static/styles.css");t.ui.clearCache()
Clear all cached HTML and CSS files.
t.ui.clearCache();🧠 Mental Model (Important)
t.ui.render() → returns an HTML response
tpl{{ css }} → where styles are injected
tpl{{ var }} → template variables
YOU → control compositionNo implicit behavior. No auto static serving. No hidden parsing.
❌ What This Extension Does NOT Do
- ❌ No static file server
- ❌ No
<link>interception - ❌ No auto CSS loading
- ❌ No HTML AST parsing
- ❌ No framework magic
This is intentional.
✅ Why This Fits TitanPL
- Runtime-first
- Predictable
- Explicit IO
- Action-based routing friendly
- Production-safe
- Easy to debug
🛣️ Possible Extensions (Future)
t.ui.js()for inline JS- Layouts / partials
- Scoped CSS
- Dot-path vars (
tpl{{ user.name }}) - HTML escaping / raw blocks
