301 lines
18 KiB
HTML
301 lines
18 KiB
HTML
<!doctype html>
|
|
<html lang="en" data-theme="night" class="dark">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
|
<meta name="color-scheme" content="dark light">
|
|
<meta name="theme-color" content="#09090b" media="(prefers-color-scheme: dark)">
|
|
<meta name="theme-color" content="#fafafa" media="(prefers-color-scheme: light)">
|
|
|
|
<title>Examples — tui-pages</title>
|
|
<meta name="description" content="Three runnable TUI apps built with tui-pages: a default multi-page app, a canvas login form, and a keybindings modal. Clone, cargo run, learn.">
|
|
<link rel="icon" href="/static/img/favicon.svg" type="image/svg+xml">
|
|
<link rel="canonical" href="https://tui-pages.dev/examples.html">
|
|
|
|
<meta property="og:title" content="Examples — tui-pages">
|
|
<meta property="og:description" content="Three runnable TUI apps built with tui-pages. Clone, cargo run, learn.">
|
|
<meta property="og:image" content="/static/img/og-image.svg">
|
|
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin>
|
|
<link rel="preconnect" href="https://unpkg.com" crossorigin>
|
|
|
|
<link rel="preload" as="style" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap">
|
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap">
|
|
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<script>
|
|
tailwind.config = {
|
|
darkMode: 'class',
|
|
theme: { extend: {
|
|
fontFamily: {
|
|
sans: ['Inter', 'ui-sans-serif', 'system-ui', '-apple-system', 'Segoe UI', 'sans-serif'],
|
|
mono: ['"JetBrains Mono"', 'ui-monospace', 'SFMono-Regular', 'Menlo', 'Consolas', 'monospace'],
|
|
},
|
|
colors: { accent: { DEFAULT: '#b7410e', fg: '#fff5f0' } },
|
|
}},
|
|
};
|
|
</script>
|
|
|
|
<link href="https://cdn.jsdelivr.net/npm/daisyui@4.12.10/dist/full.min.css" rel="stylesheet" type="text/css" />
|
|
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/styles/github-dark-dimmed.min.css">
|
|
<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/highlight.min.js" defer></script>
|
|
<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/languages/rust.min.js" defer></script>
|
|
<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/languages/bash.min.js" defer></script>
|
|
<script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/languages/toml.min.js" defer></script>
|
|
|
|
<script src="https://unpkg.com/htmx.org@2.0.4" defer></script>
|
|
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.14.1/dist/cdn.min.js"></script>
|
|
<link rel="stylesheet" href="/static/css/site.css">
|
|
</head>
|
|
|
|
<body
|
|
x-data="{ theme: localStorage.getItem('tp-theme') || 'night' }"
|
|
x-init="
|
|
$watch('theme', t => {
|
|
localStorage.setItem('tp-theme', t);
|
|
document.documentElement.setAttribute('data-theme', t);
|
|
document.documentElement.classList.toggle('dark', t === 'night');
|
|
});
|
|
document.documentElement.setAttribute('data-theme', theme);
|
|
document.documentElement.classList.toggle('dark', theme === 'night');
|
|
"
|
|
class="min-h-screen bg-base-100 text-base-content antialiased"
|
|
>
|
|
|
|
<a href="#main" class="sr-only focus:not-sr-only focus:fixed focus:top-2 focus:left-2 focus:z-50 focus:px-3 focus:py-2 focus:bg-accent focus:text-accent-fg focus:rounded">Skip to content</a>
|
|
|
|
<!-- NAV (mirrors index.html, kept in sync manually for static) -->
|
|
<header class="tp-nav sticky top-0 z-40">
|
|
<nav class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 h-16 flex items-center gap-4">
|
|
<a href="/" class="flex items-center gap-2.5 group" aria-label="tui-pages home">
|
|
<span class="inline-flex items-center justify-center w-8 h-8 rounded-lg bg-accent/10 border border-accent/30 text-accent">
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
<polyline points="7 7 13 12 7 17"/>
|
|
<rect x="15" y="7" width="2.5" height="10" fill="currentColor" stroke="none"/>
|
|
</svg>
|
|
</span>
|
|
<span class="font-mono font-bold text-base tracking-tight text-zinc-100 group-hover:text-white transition-colors">tui-pages</span>
|
|
</a>
|
|
|
|
<ul class="hidden md:flex items-center gap-1 ml-4 text-sm">
|
|
<li><a href="/examples.html" class="px-3 py-1.5 text-white rounded-md bg-zinc-800/60" aria-current="page">Examples</a></li>
|
|
<li><a href="https://tui-pages.farmeris.sk" class="px-3 py-1.5 text-zinc-300 hover:text-white rounded-md hover:bg-zinc-800/50 transition-colors">Book</a></li>
|
|
<li><a href="https://docs.rs/tui-pages" class="px-3 py-1.5 text-zinc-300 hover:text-white rounded-md hover:bg-zinc-800/50 transition-colors">API</a></li>
|
|
<li><a href="https://gitlab.com/filipriec/tui-pages" class="px-3 py-1.5 text-zinc-300 hover:text-white rounded-md hover:bg-zinc-800/50 transition-colors">GitLab</a></li>
|
|
</ul>
|
|
|
|
<div class="ml-auto flex items-center gap-2">
|
|
<button type="button" @click="theme = (theme === 'night' ? 'winter' : 'night')"
|
|
:aria-label="theme === 'night' ? 'Switch to light theme' : 'Switch to dark theme'"
|
|
class="w-9 h-9 inline-flex items-center justify-center rounded-md border border-zinc-800 bg-zinc-900/50 text-zinc-300 hover:text-white hover:border-zinc-700 transition-colors">
|
|
<svg x-show="theme === 'night'" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"/></svg>
|
|
<svg x-show="theme !== 'night'" x-cloak width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
|
|
</button>
|
|
<a href="https://gitlab.com/filipriec/tui-pages" class="hidden sm:inline-flex items-center gap-1.5 h-9 px-3.5 rounded-md bg-accent text-accent-fg text-sm font-medium hover:bg-accent/90 transition-colors">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 21.5l3.7-11.4H8.3L12 21.5zM2.5 10.1L1 14.4c-.2.6 0 1.3.5 1.6L12 21.5 2.5 10.1zm19 0L21.5 14.4c.2.6 0 1.3-.5 1.6L12 21.5l10-11.4zM15.7 8.6L17.4 2.3c.1-.4-.4-.7-.7-.4L13 4.6c-.4.3-.9.3-1.3.3s-.9 0-1.3-.3L7 1.9c-.3-.3-.8 0-.7.4l1.7 6.3h7.7z"/></svg>
|
|
View source
|
|
</a>
|
|
</div>
|
|
</nav>
|
|
</header>
|
|
|
|
<main id="main">
|
|
|
|
<!-- Page header -->
|
|
<section class="tp-hero">
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 pt-16 pb-12">
|
|
<nav class="text-sm text-zinc-500 mb-6">
|
|
<a href="/" class="hover:text-zinc-300">Home</a>
|
|
<span class="mx-2 text-zinc-700">/</span>
|
|
<span class="text-zinc-300">Examples</span>
|
|
</nav>
|
|
<p class="text-sm font-medium text-accent uppercase tracking-widest">Examples</p>
|
|
<h1 class="mt-3 text-4xl sm:text-5xl font-bold tracking-tight text-zinc-50">
|
|
Rich examples out of the box.
|
|
</h1>
|
|
<p class="mt-4 text-lg text-zinc-300 max-w-2xl">
|
|
Each example is a standalone <code class="font-mono text-zinc-200">cargo</code> project under <code class="font-mono text-zinc-200">examples/</code> in the repo. Clone, run, read, fork.
|
|
</p>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- ============ Example 1: default ============ -->
|
|
<article id="default" class="py-20 scroll-mt-20">
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div class="grid lg:grid-cols-5 gap-10 items-start">
|
|
<div class="lg:col-span-3">
|
|
<div class="tp-card !p-2">
|
|
<div class="tp-terminal">
|
|
<img
|
|
src="/static/img/terminal-default.svg"
|
|
:src="theme === 'night' ? '/static/img/terminal-default.svg' : '/static/img/terminal-default-light.svg'"
|
|
alt="examples/default TUI screenshot"
|
|
class="block w-full h-auto"
|
|
loading="lazy" width="640" height="400">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="lg:col-span-2">
|
|
<div class="flex items-center gap-2">
|
|
<span class="tp-kbd">basic</span>
|
|
<span class="text-xs text-zinc-500 font-mono">no features</span>
|
|
</div>
|
|
<h2 class="mt-3 text-2xl sm:text-3xl font-bold tracking-tight text-zinc-50">examples/default</h2>
|
|
<p class="mt-3 text-zinc-300 leading-relaxed">
|
|
A multi-page app with a focusable list, page navigation, and quit. The minimal end-to-end example — the one to read first to understand the architecture.
|
|
</p>
|
|
|
|
|
|
|
|
<h3 class="mt-6 text-sm font-semibold uppercase tracking-widest text-zinc-400">What it shows</h3>
|
|
<ul class="mt-2 space-y-1.5 text-sm text-zinc-300">
|
|
<li class="flex gap-2"><span class="text-accent">▸</span> Multi-page routing with <code class="font-mono text-zinc-200">register_page</code></li>
|
|
<li class="flex gap-2"><span class="text-accent">▸</span> Focus list with movement (<span class="tp-kbd">j</span> <span class="tp-kbd">k</span>)</li>
|
|
<li class="flex gap-2"><span class="text-accent">▸</span> Default keymaps in action</li>
|
|
<li class="flex gap-2"><span class="text-accent">▸</span> Clean <code class="font-mono text-zinc-200">Runtime::run()</code> loop</li>
|
|
</ul>
|
|
|
|
<a href="https://gitlab.com/filipriec/tui-pages/-/tree/main/examples/default" class="mt-6 inline-flex items-center gap-1.5 text-sm text-zinc-300 hover:text-white">
|
|
Read source
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 5l7 7-7 7"/></svg>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</article>
|
|
|
|
<!-- ============ Example 2: canvas ============ -->
|
|
<article id="canvas" class="py-20 border-t border-zinc-800/40 bg-zinc-950/30 scroll-mt-20">
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div class="grid lg:grid-cols-5 gap-10 items-start">
|
|
<div class="lg:col-span-3 lg:order-2">
|
|
<div class="tp-card !p-2">
|
|
<div class="tp-terminal">
|
|
<img
|
|
src="/static/img/terminal-canvas.svg"
|
|
:src="theme === 'night' ? '/static/img/terminal-canvas.svg' : '/static/img/terminal-canvas-light.svg'"
|
|
alt="examples/canvas TUI screenshot"
|
|
class="block w-full h-auto"
|
|
loading="lazy" width="640" height="400">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="lg:col-span-2 lg:order-1">
|
|
<div class="flex items-center gap-2">
|
|
<span class="tp-kbd">canvas</span>
|
|
<span class="text-xs text-zinc-500 font-mono">+ratatui</span>
|
|
</div>
|
|
<h2 class="mt-3 text-2xl sm:text-3xl font-bold tracking-tight text-zinc-50">examples/canvas</h2>
|
|
<p class="mt-3 text-zinc-300 leading-relaxed">
|
|
A login form with validated inputs, a submit button, and a canvas-owned keymap. Demonstrates the <code class="font-mono text-zinc-200">canvas</code> feature flag: GUI renderers, suggestions, cursor style, validation, computed fields, textareas, and text inputs.
|
|
</p>
|
|
|
|
<h3 class="mt-6 text-sm font-semibold uppercase tracking-widest text-zinc-400">What it shows</h3>
|
|
<ul class="mt-2 space-y-1.5 text-sm text-zinc-300">
|
|
<li class="flex gap-2"><span class="text-accent">▸</span> Field-level focus with <span class="tp-kbd">tab</span> / <span class="tp-kbd">shift+tab</span></li>
|
|
<li class="flex gap-2"><span class="text-accent">▸</span> Cursor style + blinking caret from canvas</li>
|
|
<li class="flex gap-2"><span class="text-accent">▸</span> Submit button as a focusable element</li>
|
|
<li class="flex gap-2"><span class="text-accent">▸</span> Validation wiring (sketch in <code class="font-mono text-zinc-200">examples/canvas</code>)</li>
|
|
</ul>
|
|
|
|
<a href="https://gitlab.com/filipriec/tui-pages/-/tree/main/examples/canvas" class="mt-6 inline-flex items-center gap-1.5 text-sm text-zinc-300 hover:text-white">
|
|
Read source
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 5l7 7-7 7"/></svg>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</article>
|
|
|
|
<!-- ============ Example 3: keybindings ============ -->
|
|
<article id="keybindings" class="py-20 scroll-mt-20">
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div class="grid lg:grid-cols-5 gap-10 items-start">
|
|
<div class="lg:col-span-3">
|
|
<div class="tp-card !p-2">
|
|
<div class="tp-terminal">
|
|
<img
|
|
src="/static/img/terminal-keybindings.svg"
|
|
:src="theme === 'night' ? '/static/img/terminal-keybindings.svg' : '/static/img/terminal-keybindings-light.svg'"
|
|
alt="examples/keybindings TUI screenshot"
|
|
class="block w-full h-auto"
|
|
loading="lazy" width="640" height="400">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="lg:col-span-2">
|
|
<div class="flex items-center gap-2">
|
|
<span class="tp-kbd">dialog</span>
|
|
<span class="text-xs text-zinc-500 font-mono">+ratatui</span>
|
|
</div>
|
|
<h2 class="mt-3 text-2xl sm:text-3xl font-bold tracking-tight text-zinc-50">examples/keybindings</h2>
|
|
<p class="mt-3 text-zinc-300 leading-relaxed">
|
|
A modal showing all keybindings, opened with <span class="tp-kbd">?</span>. Demonstrates the built-in <code class="font-mono text-zinc-200">dialog</code> feature: content and result types, plus a ratatui renderer.
|
|
</p>
|
|
|
|
|
|
<h3 class="mt-6 text-sm font-semibold uppercase tracking-widest text-zinc-400">What it shows</h3>
|
|
<ul class="mt-2 space-y-1.5 text-sm text-zinc-300">
|
|
<li class="flex gap-2"><span class="text-accent">▸</span> Modal lifecycle: open, focus, close</li>
|
|
<li class="flex gap-2"><span class="text-accent">▸</span> Background app dimmed behind the modal</li>
|
|
<li class="flex gap-2"><span class="text-accent">▸</span> Custom keymaps rendered with the <code class="font-mono text-zinc-200">kbd</code> widget</li>
|
|
<li class="flex gap-2"><span class="text-accent">▸</span> <code class="font-mono text-zinc-200">Dialog::Keybindings</code> content type</li>
|
|
</ul>
|
|
|
|
<a href="https://gitlab.com/filipriec/tui-pages/-/tree/main/examples/keybindings" class="mt-6 inline-flex items-center gap-1.5 text-sm text-zinc-300 hover:text-white">
|
|
Read source
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 5l7 7-7 7"/></svg>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</article>
|
|
|
|
<!-- CTA -->
|
|
<section class="py-24 border-t border-zinc-800/40 bg-zinc-950/30">
|
|
<div class="max-w-3xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
|
|
<h2 class="text-3xl font-bold tracking-tight text-zinc-50">Build your own.</h2>
|
|
<p class="mt-4 text-zinc-400">
|
|
The book walks you from <code class="font-mono text-zinc-300">cargo new</code> to a working multi-page app. Or read the API reference and dive in.
|
|
</p>
|
|
<div class="mt-8 flex flex-wrap items-center justify-center gap-3">
|
|
<a href="https://tui-pages.farmeris.sk" class="inline-flex items-center gap-2 h-11 px-5 rounded-lg bg-accent text-accent-fg font-medium hover:bg-accent/90 transition-colors">
|
|
Start the tutorial
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 5l7 7-7 7"/></svg>
|
|
</a>
|
|
<a href="https://gitlab.com/filipriec/tui-pages/-/tree/main/examples" class="inline-flex items-center gap-2 h-11 px-5 rounded-lg border border-zinc-700 bg-zinc-900/40 text-zinc-100 font-medium hover:border-zinc-500 hover:bg-zinc-900 transition-colors">
|
|
All examples on GitLab
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</main>
|
|
|
|
<!-- FOOTER -->
|
|
<footer class="border-t border-zinc-800/60 py-12">
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div class="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 text-xs text-zinc-500">
|
|
<p>© 2026 Filip Riečický. Released under the MIT License.</p>
|
|
<p class="font-mono">crafted with <span class="text-accent">htmx</span> + <span class="text-accent">alpine</span> + <span class="text-accent">tailwind</span></p>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
if (window.hljs) {
|
|
document.querySelectorAll('pre code').forEach(el => {
|
|
if (!el.classList.contains('hljs')) hljs.highlightElement(el);
|
|
});
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|