feat: add projects showcase and Lux-powered static file server
- Add website/serve.lux: static file server using HttpServer effect - Demonstrates serving the Lux website with Lux itself - Handles index files, clean URLs, and 404 responses - Add website/projects/index.html: example projects showcase - Features 6 real project cards (REST API, Todo App, JSON Parser, etc.) - Highlights Task Manager API demonstrating all 3 killer features - Links to full source code in the repository - Update examples sidebar with Projects section Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
456
website/projects/index.html
Normal file
456
website/projects/index.html
Normal file
@@ -0,0 +1,456 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Projects - Lux</title>
|
||||
<meta name="description" content="Real-world example projects demonstrating Lux's capabilities.">
|
||||
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>✨</text></svg>">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;600&family=Playfair+Display:wght@400;600;700&family=Source+Serif+4:opsz,wght@8..60,400;8..60,500;8..60,600&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="../static/style.css">
|
||||
<style>
|
||||
.projects-container {
|
||||
max-width: 1100px;
|
||||
margin: 0 auto;
|
||||
padding: var(--space-xl) var(--space-lg);
|
||||
}
|
||||
|
||||
.projects-header {
|
||||
text-align: center;
|
||||
margin-bottom: var(--space-2xl);
|
||||
}
|
||||
|
||||
.projects-header p {
|
||||
font-size: 1.1rem;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.projects-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
|
||||
gap: var(--space-lg);
|
||||
}
|
||||
|
||||
.project-card {
|
||||
background: var(--bg-glass);
|
||||
border: 1px solid var(--border-subtle);
|
||||
border-radius: 12px;
|
||||
padding: var(--space-lg);
|
||||
transition: border-color 0.3s ease, transform 0.2s ease;
|
||||
}
|
||||
|
||||
.project-card:hover {
|
||||
border-color: var(--border-gold);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.project-card h2 {
|
||||
font-size: 1.25rem;
|
||||
margin-bottom: var(--space-sm);
|
||||
text-align: left;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-sm);
|
||||
}
|
||||
|
||||
.project-card h2 .icon {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.project-card .description {
|
||||
color: var(--text-secondary);
|
||||
margin-bottom: var(--space-md);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.project-card .features {
|
||||
margin-bottom: var(--space-md);
|
||||
}
|
||||
|
||||
.project-card .features h3 {
|
||||
font-size: 0.85rem;
|
||||
color: var(--text-muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
margin-bottom: var(--space-xs);
|
||||
}
|
||||
|
||||
.project-card .features ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.project-card .features li {
|
||||
color: var(--text-secondary);
|
||||
font-size: 0.9rem;
|
||||
padding: 0.2rem 0;
|
||||
}
|
||||
|
||||
.project-card .features li::before {
|
||||
content: "\2022";
|
||||
color: var(--gold);
|
||||
margin-right: var(--space-xs);
|
||||
}
|
||||
|
||||
.project-card .code-preview {
|
||||
background: var(--code-bg);
|
||||
border: 1px solid var(--code-border);
|
||||
border-radius: 6px;
|
||||
padding: var(--space-md);
|
||||
margin-bottom: var(--space-md);
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.project-card .code-preview pre {
|
||||
font-family: var(--font-code);
|
||||
font-size: 0.85rem;
|
||||
line-height: 1.5;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.project-card .actions {
|
||||
display: flex;
|
||||
gap: var(--space-sm);
|
||||
}
|
||||
|
||||
.project-card .actions a {
|
||||
padding: var(--space-xs) var(--space-md);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.showcase-section {
|
||||
margin-top: var(--space-3xl);
|
||||
padding-top: var(--space-2xl);
|
||||
border-top: 1px solid var(--border-subtle);
|
||||
}
|
||||
|
||||
.showcase-section h2 {
|
||||
text-align: center;
|
||||
margin-bottom: var(--space-xl);
|
||||
}
|
||||
|
||||
.showcase-card {
|
||||
background: linear-gradient(135deg, var(--bg-tertiary) 0%, var(--bg-secondary) 100%);
|
||||
border: 1px solid var(--border-gold);
|
||||
border-radius: 16px;
|
||||
padding: var(--space-xl);
|
||||
margin-bottom: var(--space-xl);
|
||||
}
|
||||
|
||||
.showcase-card h3 {
|
||||
font-size: 1.5rem;
|
||||
color: var(--gold);
|
||||
margin-bottom: var(--space-md);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.showcase-card p {
|
||||
color: var(--text-secondary);
|
||||
margin-bottom: var(--space-lg);
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.showcase-features {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: var(--space-lg);
|
||||
margin-bottom: var(--space-xl);
|
||||
}
|
||||
|
||||
.showcase-feature {
|
||||
background: var(--bg-glass);
|
||||
border-radius: 8px;
|
||||
padding: var(--space-md);
|
||||
}
|
||||
|
||||
.showcase-feature h4 {
|
||||
color: var(--gold);
|
||||
font-size: 1rem;
|
||||
margin-bottom: var(--space-xs);
|
||||
}
|
||||
|
||||
.showcase-feature p {
|
||||
color: var(--text-muted);
|
||||
font-size: 0.9rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.showcase-code {
|
||||
background: var(--code-bg);
|
||||
border: 1px solid var(--code-border);
|
||||
border-radius: 8px;
|
||||
padding: var(--space-lg);
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.showcase-code pre {
|
||||
font-family: var(--font-code);
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<nav>
|
||||
<a href="/" class="logo">Lux</a>
|
||||
<ul class="nav-links" id="nav-links">
|
||||
<li><a href="/install">Install</a></li>
|
||||
<li><a href="/tour/">Tour</a></li>
|
||||
<li><a href="/examples/">Examples</a></li>
|
||||
<li><a href="/docs/">Docs</a></li>
|
||||
<li><a href="/play">Play</a></li>
|
||||
<li><a href="https://git.qrty.ink/blu/lux" class="nav-source">Source</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<main class="projects-container">
|
||||
<header class="projects-header">
|
||||
<h1>Example Projects</h1>
|
||||
<p>Real-world applications demonstrating Lux's unique capabilities. Clone these to learn by doing.</p>
|
||||
</header>
|
||||
|
||||
<div class="projects-grid">
|
||||
<div class="project-card">
|
||||
<h2><span class="icon">API</span> REST API</h2>
|
||||
<p class="description">
|
||||
A full REST API for task management with JSON responses, routing, and CRUD operations.
|
||||
</p>
|
||||
<div class="features">
|
||||
<h3>Demonstrates</h3>
|
||||
<ul>
|
||||
<li>HttpServer effect</li>
|
||||
<li>Pattern matching for routing</li>
|
||||
<li>JSON serialization</li>
|
||||
<li>Effect tracking</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="code-preview">
|
||||
<pre><code><span class="kw">fn</span> <span class="fn">router</span>(req): Response <span class="kw">with</span> {<span class="ef">Http</span>} =
|
||||
<span class="kw">match</span> (req.method, req.path) {
|
||||
(<span class="st">"GET"</span>, <span class="st">"/"</span>) => httpOk(welcome),
|
||||
(<span class="st">"GET"</span>, <span class="st">"/tasks"</span>) => httpOk(tasks),
|
||||
_ => httpNotFound(<span class="st">"404"</span>)
|
||||
}</code></pre>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<a href="https://git.qrty.ink/blu/lux/src/branch/master/projects/rest-api" class="btn btn-primary">View Code</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="project-card">
|
||||
<h2><span class="icon">TODO</span> Todo App</h2>
|
||||
<p class="description">
|
||||
A command-line todo application showcasing algebraic data types and pattern matching.
|
||||
</p>
|
||||
<div class="features">
|
||||
<h3>Demonstrates</h3>
|
||||
<ul>
|
||||
<li>ADTs for data modeling</li>
|
||||
<li>Pattern matching</li>
|
||||
<li>Recursive list operations</li>
|
||||
<li>Console effect</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="code-preview">
|
||||
<pre><code><span class="kw">type</span> <span class="ty">Priority</span> =
|
||||
| <span class="ty">Low</span>
|
||||
| <span class="ty">Medium</span>
|
||||
| <span class="ty">High</span>
|
||||
|
||||
<span class="kw">type</span> <span class="ty">TodoItem</span> =
|
||||
| <span class="ty">TodoItem</span>(Int, String, Bool, Priority)</code></pre>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<a href="https://git.qrty.ink/blu/lux/src/branch/master/projects/todo-app" class="btn btn-primary">View Code</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="project-card">
|
||||
<h2><span class="icon">JSON</span> JSON Parser</h2>
|
||||
<p class="description">
|
||||
A recursive descent JSON parser demonstrating ADTs for AST representation.
|
||||
</p>
|
||||
<div class="features">
|
||||
<h3>Demonstrates</h3>
|
||||
<ul>
|
||||
<li>ADTs for AST</li>
|
||||
<li>Recursive parsing</li>
|
||||
<li>String manipulation</li>
|
||||
<li>Pure functions</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="code-preview">
|
||||
<pre><code><span class="kw">type</span> <span class="ty">JsonValue</span> =
|
||||
| <span class="ty">JsonNull</span>
|
||||
| <span class="ty">JsonBool</span>(Bool)
|
||||
| <span class="ty">JsonNumber</span>(Int)
|
||||
| <span class="ty">JsonString</span>(String)
|
||||
| <span class="ty">JsonArray</span>(List<JsonValue>)
|
||||
| <span class="ty">JsonObject</span>(List<(String, JsonValue)>)</code></pre>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<a href="https://git.qrty.ink/blu/lux/src/branch/master/projects/json-parser" class="btn btn-primary">View Code</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="project-card">
|
||||
<h2><span class="icon">GAME</span> Guessing Game</h2>
|
||||
<p class="description">
|
||||
A simple number guessing game demonstrating effects for randomness and I/O.
|
||||
</p>
|
||||
<div class="features">
|
||||
<h3>Demonstrates</h3>
|
||||
<ul>
|
||||
<li>Random effect</li>
|
||||
<li>Console I/O</li>
|
||||
<li>Recursive game loop</li>
|
||||
<li>User input handling</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="code-preview">
|
||||
<pre><code><span class="kw">fn</span> <span class="fn">playGame</span>(): Unit
|
||||
<span class="kw">with</span> {<span class="ef">Console</span>, <span class="ef">Random</span>} = {
|
||||
<span class="kw">let</span> secret = Random.int(<span class="num">1</span>, <span class="num">100</span>)
|
||||
Console.print(<span class="st">"Guess a number!"</span>)
|
||||
guessLoop(secret, <span class="num">0</span>)
|
||||
}</code></pre>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<a href="https://git.qrty.ink/blu/lux/src/branch/master/projects/guessing-game" class="btn btn-primary">View Code</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="project-card">
|
||||
<h2><span class="icon">MD</span> Markdown Converter</h2>
|
||||
<p class="description">
|
||||
Convert Markdown to HTML using pattern matching and string processing.
|
||||
</p>
|
||||
<div class="features">
|
||||
<h3>Demonstrates</h3>
|
||||
<ul>
|
||||
<li>String manipulation</li>
|
||||
<li>Pattern matching</li>
|
||||
<li>Pure transformation</li>
|
||||
<li>List processing</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="code-preview">
|
||||
<pre><code><span class="kw">fn</span> <span class="fn">convertLine</span>(line: String): String =
|
||||
<span class="kw">if</span> startsWith(line, <span class="st">"# "</span>) <span class="kw">then</span>
|
||||
<span class="st">"<h1>"</span> + rest(line, <span class="num">2</span>) + <span class="st">"</h1>"</span>
|
||||
<span class="kw">else if</span> startsWith(line, <span class="st">"- "</span>) <span class="kw">then</span>
|
||||
<span class="st">"<li>"</span> + rest(line, <span class="num">2</span>) + <span class="st">"</li>"</span>
|
||||
<span class="kw">else</span> <span class="st">"<p>"</span> + line + <span class="st">"</p>"</span></code></pre>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<a href="https://git.qrty.ink/blu/lux/src/branch/master/projects/markdown-converter" class="btn btn-primary">View Code</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="project-card">
|
||||
<h2><span class="icon">CALC</span> Mini Interpreter</h2>
|
||||
<p class="description">
|
||||
A tiny expression interpreter demonstrating language implementation patterns.
|
||||
</p>
|
||||
<div class="features">
|
||||
<h3>Demonstrates</h3>
|
||||
<ul>
|
||||
<li>ADTs for AST</li>
|
||||
<li>Recursive evaluation</li>
|
||||
<li>Environment handling</li>
|
||||
<li>Interpreter patterns</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="code-preview">
|
||||
<pre><code><span class="kw">type</span> <span class="ty">Expr</span> =
|
||||
| <span class="ty">Num</span>(Int)
|
||||
| <span class="ty">Add</span>(Expr, Expr)
|
||||
| <span class="ty">Mul</span>(Expr, Expr)
|
||||
| <span class="ty">Var</span>(String)
|
||||
| <span class="ty">Let</span>(String, Expr, Expr)</code></pre>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<a href="https://git.qrty.ink/blu/lux/src/branch/master/projects/mini-interpreter" class="btn btn-primary">View Code</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Featured Showcase -->
|
||||
<section class="showcase-section">
|
||||
<h2>Featured: Task Manager API</h2>
|
||||
<div class="showcase-card">
|
||||
<h3>A Complete Showcase of Lux's Unique Features</h3>
|
||||
<p>This comprehensive example demonstrates all three of Lux's killer features working together.</p>
|
||||
|
||||
<div class="showcase-features">
|
||||
<div class="showcase-feature">
|
||||
<h4>1. Algebraic Effects</h4>
|
||||
<p>Every side effect is explicit in function signatures. No hidden I/O.</p>
|
||||
</div>
|
||||
<div class="showcase-feature">
|
||||
<h4>2. Behavioral Types</h4>
|
||||
<p>Compile-time guarantees: <code>is pure</code>, <code>is total</code>, <code>is idempotent</code>.</p>
|
||||
</div>
|
||||
<div class="showcase-feature">
|
||||
<h4>3. Schema Evolution</h4>
|
||||
<p>Versioned types with automatic migration. Data structures evolve safely.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="showcase-code">
|
||||
<pre><code><span class="cm">// Task v1: Original data model</span>
|
||||
<span class="kw">type</span> <span class="ty">Task</span> <span class="cm">@v1</span> {
|
||||
id: String,
|
||||
title: String,
|
||||
done: Bool
|
||||
}
|
||||
|
||||
<span class="cm">// Task v2: Added priority field with migration</span>
|
||||
<span class="kw">type</span> <span class="ty">Task</span> <span class="cm">@v2</span> {
|
||||
id: String,
|
||||
title: String,
|
||||
done: Bool,
|
||||
priority: String,
|
||||
|
||||
<span class="cm">// Old tasks get "medium" priority by default</span>
|
||||
<span class="kw">from</span> <span class="cm">@v1</span> = {
|
||||
id: old.id,
|
||||
title: old.title,
|
||||
done: old.done,
|
||||
priority: <span class="st">"medium"</span>
|
||||
}
|
||||
}
|
||||
|
||||
<span class="cm">// Pure, total, idempotent business logic</span>
|
||||
<span class="kw">fn</span> <span class="fn">validateTitle</span>(title: String): <span class="ty">Result</span><String, String>
|
||||
<span class="kw">is</span> <span class="ty">pure</span>, <span class="ty">total</span> =
|
||||
<span class="kw">if</span> String.length(title) == <span class="num">0</span> <span class="kw">then</span>
|
||||
Err(<span class="st">"Title cannot be empty"</span>)
|
||||
<span class="kw">else</span>
|
||||
Ok(title)</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="actions" style="margin-top: var(--space-lg);">
|
||||
<a href="https://git.qrty.ink/blu/lux/src/branch/master/examples/showcase/task_manager.lux" class="btn btn-primary">View Full Code</a>
|
||||
<a href="/tour/06-effects-intro.html" class="btn btn-secondary">Learn About Effects</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Get Started -->
|
||||
<section class="showcase-section" style="text-align: center;">
|
||||
<h2>Build Your Own</h2>
|
||||
<p style="margin-bottom: var(--space-lg); color: var(--text-secondary);">Ready to start building with Lux?</p>
|
||||
<div style="display: flex; gap: var(--space-md); justify-content: center; flex-wrap: wrap;">
|
||||
<a href="/install" class="btn btn-primary">Install Lux</a>
|
||||
<a href="/tour/" class="btn btn-secondary">Take the Tour</a>
|
||||
<a href="/examples/" class="btn btn-tertiary">Browse Examples</a>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user