<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Language Guide</title>
<meta name="description" content="A programming language that compiles to HTML, CSS, and JavaScript. Build SPAs and static sites with built-in components, reactivity, routing, i18n, and animations.">
<link rel="stylesheet" href="../styles.css">
</head>
<body>
<div id="app">
<div class="wf-row">
<div class="wf-container wf-animate-fadeIn">
<div class="wf-spacer"></div>
<h1 class="wf-heading wf-heading--h1">Language Guide</h1>
<p class="wf-text wf-text--muted">Learn the core concepts of WebFluent.</p>
<div class="wf-spacer"></div>
<h2 class="wf-heading wf-heading--h2">Pages</h2>
<p class="wf-text">Pages are top-level route targets. Each page defines a URL path and contains the UI tree for that route.</p>
<div class="wf-spacer"></div>
<div class="wf-card wf-card--outlined">
<div class="wf-card__body">
<code class="wf-code">Page Home (path: "/", title: "Home") {
Container {
Heading("Welcome", h1)
Text("This is the home page.")
}
}</code>
</div>
</div>
<div class="wf-spacer"></div>
<p class="wf-text wf-text--bold">Page attributes:</p>
<table class="wf-table">
<thead>
<td>Attribute</td>
<td>Type</td>
<td>Description</td>
</thead>
<tr>
<td>path</td>
<td>String</td>
<td>URL route for this page (required)</td>
</tr>
<tr>
<td>title</td>
<td>String</td>
<td>Document title</td>
</tr>
<tr>
<td>guard</td>
<td>Expression</td>
<td>Navigation guard — redirects if false</td>
</tr>
<tr>
<td>redirect</td>
<td>String</td>
<td>Redirect target when guard fails</td>
</tr>
</table>
<div class="wf-spacer"></div>
<hr class="wf-divider">
<div class="wf-spacer"></div>
<h2 class="wf-heading wf-heading--h2">Components</h2>
<p class="wf-text">Reusable UI blocks that accept props and can have internal state.</p>
<div class="wf-spacer"></div>
<div class="wf-card wf-card--outlined">
<div class="wf-card__body">
<code class="wf-code">Component UserCard (name: String, role: String, active: Bool = true) {
Card(elevated) {
Row(align: center, gap: md) {
Avatar(initials: "U", primary)
Stack {
Text(name, bold)
Text(role, muted)
}
if active {
Badge("Active", success)
}
}
}
}
// Usage
UserCard(name: "Monzer", role: "Developer")</code>
</div>
</div>
<div class="wf-spacer"></div>
<p class="wf-text wf-text--muted">Props support types: String, Number, Bool, List, Map. Optional props use ?, defaults use =.</p>
<div class="wf-spacer"></div>
<hr class="wf-divider">
<div class="wf-spacer"></div>
<h2 class="wf-heading wf-heading--h2">State and Reactivity</h2>
<p class="wf-text">State is declared with the state keyword. It is reactive — any UI that reads it updates automatically when it changes.</p>
<div class="wf-spacer"></div>
<div class="wf-card wf-card--outlined">
<div class="wf-card__body">
<code class="wf-code">Page Counter (path: "/counter") {
state count = 0
Container {
Text("Count: {count}")
Button("+1", primary) { count = count + 1 }
Button("-1") { count = count - 1 }
}
}</code>
</div>
</div>
<div class="wf-spacer"></div>
<p class="wf-text wf-text--bold">Derived state:</p>
<div class="wf-card wf-card--outlined">
<div class="wf-card__body">
<code class="wf-code">state items = [{name: "A", price: 3}, {name: "B", price: 2}]
derived total = items.map(i => i.price).sum()
derived isEmpty = items.length == 0</code>
</div>
</div>
<div class="wf-spacer"></div>
<hr class="wf-divider">
<div class="wf-spacer"></div>
<h2 class="wf-heading wf-heading--h2">Events</h2>
<p class="wf-text">Event handlers are declared with on:event or via shorthand blocks on buttons.</p>
<div class="wf-spacer"></div>
<div class="wf-card wf-card--outlined">
<div class="wf-card__body">
<code class="wf-code">Button("Submit") {
on:click {
submitForm()
}
}
Input(text, placeholder: "Search...") {
on:input {
searchQuery = value
}
on:keydown {
if key == "Enter" {
performSearch()
}
}
}
// Shorthand: block on Button defaults to on:click
Button("Save") { save() }</code>
</div>
</div>
<div class="wf-spacer"></div>
<p class="wf-text wf-text--muted">Supported events: on:click, on:submit, on:input, on:change, on:focus, on:blur, on:keydown, on:keyup, on:mouseover, on:mouseout, on:mount, on:unmount</p>
<div class="wf-spacer"></div>
<hr class="wf-divider">
<div class="wf-spacer"></div>
<h2 class="wf-heading wf-heading--h2">Control Flow</h2>
<p class="wf-text wf-text--bold">Conditionals:</p>
<div class="wf-card wf-card--outlined">
<div class="wf-card__body">
<code class="wf-code">if isLoggedIn {
Text("Welcome back!")
} else if isGuest {
Text("Hello, guest")
} else {
Button("Log In") { navigate("/login") }
}</code>
</div>
</div>
<div class="wf-spacer"></div>
<p class="wf-text wf-text--bold">Loops:</p>
<div class="wf-card wf-card--outlined">
<div class="wf-card__body">
<code class="wf-code">for user in users {
UserCard(name: user.name, role: user.role)
}
// With index
for item, index in items {
Text("{index + 1}. {item}")
}</code>
</div>
</div>
<div class="wf-spacer"></div>
<p class="wf-text wf-text--bold">Show/Hide (keeps element in DOM, toggles visibility):</p>
<div class="wf-card wf-card--outlined">
<div class="wf-card__body">
<code class="wf-code">show isExpanded {
Card { Text("Expanded content") }
}</code>
</div>
</div>
<div class="wf-spacer"></div>
<hr class="wf-divider">
<div class="wf-spacer"></div>
<h2 class="wf-heading wf-heading--h2">Stores</h2>
<p class="wf-text">Stores hold shared state accessible from any page or component.</p>
<div class="wf-spacer"></div>
<div class="wf-card wf-card--outlined">
<div class="wf-card__body">
<code class="wf-code">Store CartStore {
state items = []
derived total = items.map(i => i.price * i.quantity).sum()
derived count = items.length
action addItem(product: Map) {
items.push({ id: product.id, name: product.name, price: product.price, quantity: 1 })
}
action removeItem(id: Number) {
items = items.filter(i => i.id != id)
}
}
// Usage in a page
Page Cart (path: "/cart") {
use CartStore
Text("Total: ${CartStore.total}")
Button("Clear") { CartStore.clear() }
}</code>
</div>
</div>
<div class="wf-spacer"></div>
<hr class="wf-divider">
<div class="wf-spacer"></div>
<h2 class="wf-heading wf-heading--h2">Routing</h2>
<p class="wf-text">SPA routing is declared in the App file.</p>
<div class="wf-spacer"></div>
<div class="wf-card wf-card--outlined">
<div class="wf-card__body">
<code class="wf-code">App {
Navbar {
Navbar.Brand { Text("My App", heading) }
Navbar.Links {
Link(to: "/") { Text("Home") }
Link(to: "/about") { Text("About") }
}
}
Router {
Route(path: "/", page: Home)
Route(path: "/about", page: About)
Route(path: "/user/:id", page: UserProfile)
Route(path: "*", page: NotFound)
}
}
// Programmatic navigation
Button("Go Home") { navigate("/") }
// Dynamic routes access params
Page UserProfile (path: "/user/:id") {
Text("User ID: {params.id}")
}</code>
</div>
</div>
<div class="wf-spacer"></div>
<hr class="wf-divider">
<div class="wf-spacer"></div>
<h2 class="wf-heading wf-heading--h2">Data Fetching</h2>
<p class="wf-text">Built-in async data loading with automatic loading, error, and success states.</p>
<div class="wf-spacer"></div>
<div class="wf-card wf-card--outlined">
<div class="wf-card__body">
<code class="wf-code">fetch users from "/api/users" {
loading {
Spinner()
}
error (err) {
Alert("Failed to load users", danger)
}
success {
for user in users {
UserCard(name: user.name, role: user.role)
}
}
}
// With options
fetch result from "/api/submit" (method: "POST", body: { name: name, email: email }) {
success {
Alert("Saved!", success)
}
}</code>
</div>
</div>
<div class="wf-spacer"></div>
<div class="wf-row">
<button class="wf-btn wf-btn--primary">
Components Reference
</button>
<button class="wf-btn">
Styling Guide
</button>
</div>
<div class="wf-spacer"></div>
</div>
</div>
</div>
<script src="../app.js"></script>
</body>
</html>