- Rust 100%
|
|
||
|---|---|---|
| .agents/skills/qtml | ||
| .github/workflows | ||
| examples | ||
| qtml_build | ||
| qtml_core | ||
| qtml_lsp | ||
| qtml_macro | ||
| qtml_tailwind | ||
| .gitignore | ||
| AGENTS.md | ||
| Cargo.lock | ||
| Cargo.toml | ||
| LICENSE | ||
| README.md | ||
QTML
QTML is a QML-inspired template language for compiling server-rendered Rust templates into HTML with Tailwind classes.
The primary entry point is the render_qtml! macro from qtml_macro.
use qtml_macro::render_qtml;
let page = render_qtml!("ui/dashboard.qtml");
Format source with qtml_core before writing it back to disk:
use qtml_core::compiler::format_document;
let formatted = format_document(source)?;
Column {
spacing: 3
horizontal_alignment: center
Text {
text: "Welcome, {user_name}"
size: 2xl
weight: bold
}
Button {
text: "Save"
background: blue-600
color: white
padding: 3
border_radius: md
}
}
Imports always name the component or style namespace they introduce:
import "components/page_card.qtml" as PageCard
import style "styles/theme.qtml" as theme
Imports are local to the file that declares them. Components and style namespaces must be imported in every file that uses them; imports are not re-exported to parents or siblings.
Imported components declare inputs with property and read them with $:
property title: "Untitled"
Box {
Text { text: $title }
}
Transition utilities use normal properties:
Button {
transition: all
duration: 100
}
Use Rust boolean expressions to conditionally render QTML content. Branches
support else if and else:
if user.is_admin {
Text { text: "Admin access" }
} else if user.is_signed_in {
Text { text: "Standard access" }
} else {
Text { text: "Sign in" }
}
Use // for comments. Comments may appear anywhere whitespace is allowed:
// A reusable page heading.
Header1 {
text: "Dashboard" // Rendered as escaped text.
}
For page structure, QTML provides Header, Footer, Section, Article,
Nav, Aside, Text, and Span alongside Page, Box, Grid, Column, and
Row. Use OrderedList, UnorderedList, and ListItem for lists; use Details
and Summary for disclosures. Heading components run from Header1 through
Header6.
Style modules use the same .qtml extension and declare reusable values with var:
// ui/styles/theme.qtml
var background: #f8fafc
dark {
var background: #0f172a
}
Templates import a style module by its filename namespace:
import style "styles/theme.qtml" as theme
Page { background: $theme.background }
Generate the style definitions once in the application shell with
render_qtml_styles!("ui/styles/theme.qtml"). Dark overrides set CSS custom
properties under the dark class. Use a dark { ... } block in a component
for a local Tailwind dark-mode override.
See examples/counter, examples/task_app, and examples/theme for working applications.
Tailwind production builds
QTML generates Tailwind utility classes during Rust compilation, so production Tailwind builds need an extracted class list. Scan each template entrypoint before running Tailwind:
cargo run -p qtml_tailwind -- scan ui/home.qtml --output target/qtml-tailwind.txt
Add the generated file to Tailwind's sources. For Tailwind v4:
@import "tailwindcss";
@source "../target/qtml-tailwind.txt";
For Tailwind v3, include ./target/qtml-tailwind.txt in content. The scanner
follows imported QTML components and includes both branches of conditional
classes.
License
QTML is available under the MIT License.