Compare commits

...

9 Commits

Author SHA1 Message Date
Priec
51beca2776 caddyfile prod fix 2026-06-02 23:33:27 +02:00
Priec
0b9df4549e production website 2026-06-02 23:23:48 +02:00
Priec
78407ae9e8 prod ready 2026-06-02 23:06:09 +02:00
Priec
bc670d11dc better for prod 2026-06-02 22:35:13 +02:00
Priec
d22dca0a27 svgs done 2026-06-02 22:20:36 +02:00
Priec
3266c944ba first svg is pitch perfect 2026-06-02 21:55:06 +02:00
Priec
93769b3129 register is now fully working 2026-06-02 21:40:40 +02:00
Priec
83a80b6e31 highlights 2026-06-02 19:57:30 +02:00
Priec
7c85022686 light mode 2026-06-02 19:56:08 +02:00
15 changed files with 27476 additions and 35612 deletions

23
Caddyfile Normal file
View File

@@ -0,0 +1,23 @@
tui-pages.farmeris.sk {
encode gzip
# mdbook served under /book (book.toml has site-url = "/book/")
redir /book /book/
handle /book/* {
root * /app/tui-pages-docs
file_server
}
# website at the root (catch-all — must come last)
handle {
root * /app/tui-pages-web
file_server
}
# custom 404 page for the website
handle_errors {
root * /app/tui-pages-web
rewrite * /404.html
file_server
}
}

View File

@@ -37,9 +37,20 @@ the page plays back.
- `SCALE` — source pixel width fed to chafa; scale it up with `SIZE`.
After changing `SIZE`, set a matching `font-size` in `static/css/ascii.css`
(it halves each time you double the grid) so the ASCII fills the screen.
(lines 3233, the two `font-size: max(...)` declarations) so the ASCII fills
the screen. The font-size scales **inversely** with the grid: halve the grid →
double the font-size. The two `max()` multipliers are:
Current setup: `480x144`, font-size `max(0.35vw, 0.695vh)`.
- vw multiplier ≈ `1 / (cols × 0.6)` (0.6 ≈ JetBrains Mono char aspect ratio)
- vh multiplier ≈ `1 / rows`
| `SIZE` | `font-size` in `ascii.css` |
| --------- | ------------------------------ |
| `480x144` | `max(0.35vw, 0.695vh)` |
| `360x108` | `max(0.463vw, 0.926vh)` |
| `240x72` | `max(0.7vw, 1.39vh)` |
Current setup: `240x72`, font-size `max(0.7vw, 1.39vh)`.
## License

View File

@@ -10,7 +10,7 @@
<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">
<link rel="canonical" href="https://tui-pages.farmeris.sk/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.">
@@ -82,7 +82,7 @@
<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://tui-pages.farmeris.sk/book" 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>
@@ -114,7 +114,7 @@
</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">
Three apps in the box.
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.
@@ -129,7 +129,12 @@
<div class="lg:col-span-3">
<div class="tp-card !p-2">
<div class="tp-terminal">
<img src="/static/img/terminal-default.svg" alt="examples/default TUI screenshot" class="block w-full h-auto" loading="lazy" width="640" height="400">
<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>
@@ -144,21 +149,7 @@
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">Run it</h3>
<div
x-data="{ copied: false }"
class="mt-2 inline-flex items-stretch w-full max-w-md rounded-lg border border-zinc-800 bg-zinc-950/80 overflow-hidden font-mono text-sm"
>
<code class="px-3 py-2.5 text-zinc-100 whitespace-nowrap">cargo run --example default</code>
<button type="button"
@click="navigator.clipboard.writeText('cargo run --example default').then(() => { copied = true; setTimeout(() => copied = false, 1400) })"
class="ml-auto px-3 border-l border-zinc-800 text-zinc-400 hover:text-white hover:bg-zinc-900 transition-colors flex items-center gap-1.5"
>
<svg x-show="!copied" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
<svg x-show="copied" x-cloak width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
<span x-text="copied ? 'Copied' : 'Copy'" class="text-xs"></span>
</button>
</div>
<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">
@@ -184,7 +175,12 @@
<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" alt="examples/canvas TUI screenshot" class="block w-full h-auto" loading="lazy" width="640" height="400">
<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>
@@ -199,22 +195,6 @@
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">Run it</h3>
<div
x-data="{ copied: false }"
class="mt-2 inline-flex items-stretch w-full max-w-md rounded-lg border border-zinc-800 bg-zinc-950/80 overflow-hidden font-mono text-sm"
>
<code class="px-3 py-2.5 text-zinc-100 whitespace-nowrap">cargo run --example canvas --features canvas</code>
<button type="button"
@click="navigator.clipboard.writeText('cargo run --example canvas --features canvas').then(() => { copied = true; setTimeout(() => copied = false, 1400) })"
class="ml-auto px-3 border-l border-zinc-800 text-zinc-400 hover:text-white hover:bg-zinc-900 transition-colors flex items-center gap-1.5"
>
<svg x-show="!copied" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
<svg x-show="copied" x-cloak width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
<span x-text="copied ? 'Copied' : 'Copy'" class="text-xs"></span>
</button>
</div>
<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>
@@ -239,7 +219,12 @@
<div class="lg:col-span-3">
<div class="tp-card !p-2">
<div class="tp-terminal">
<img src="/static/img/terminal-keybindings.svg" alt="examples/keybindings TUI screenshot" class="block w-full h-auto" loading="lazy" width="640" height="400">
<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>
@@ -254,21 +239,6 @@
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">Run it</h3>
<div
x-data="{ copied: false }"
class="mt-2 inline-flex items-stretch w-full max-w-md rounded-lg border border-zinc-800 bg-zinc-950/80 overflow-hidden font-mono text-sm"
>
<code class="px-3 py-2.5 text-zinc-100 whitespace-nowrap">cargo run --example keybindings --features dialog</code>
<button type="button"
@click="navigator.clipboard.writeText('cargo run --example keybindings --features dialog').then(() => { copied = true; setTimeout(() => copied = false, 1400) })"
class="ml-auto px-3 border-l border-zinc-800 text-zinc-400 hover:text-white hover:bg-zinc-900 transition-colors flex items-center gap-1.5"
>
<svg x-show="!copied" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
<svg x-show="copied" x-cloak width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
<span x-text="copied ? 'Copied' : 'Copy'" class="text-xs"></span>
</button>
</div>
<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">
@@ -295,7 +265,7 @@
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">
<a href="https://tui-pages.farmeris.sk/book" 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>

View File

@@ -8,25 +8,27 @@
<meta name="theme-color" content="#fafafa" media="(prefers-color-scheme: light)">
<title>tui-pages — a framework for building TUIs in Rust</title>
<meta name="description" content="A complete framework for building TUIs in Rust on top of ratatui. Pre-programmed focus manager, input pipeline, keymaps, and page navigation. Stop rewriting the same architecture for every project.">
<meta name="description" content="A complete UX framework for building TUIs in Rust. Stop rewriting the same architecture for every project.">
<meta name="keywords" content="rust, tui, ratatui, terminal, framework, ui, cargo, crate">
<meta name="author" content="Filip Riečický">
<link rel="icon" href="/static/img/favicon.svg" type="image/svg+xml">
<link rel="canonical" href="https://tui-pages.dev/">
<link rel="canonical" href="https://tui-pages.farmeris.sk/">
<!-- Open Graph -->
<meta property="og:type" content="website">
<meta property="og:title" content="tui-pages — a framework for building TUIs in Rust">
<meta property="og:description" content="A complete framework for building TUIs in Rust on top of ratatui. Pre-programmed focus manager, input pipeline, keymaps, and page navigation.">
<meta property="og:url" content="https://tui-pages.dev/">
<meta property="og:url" content="https://tui-pages.farmeris.sk/">
<meta property="og:image" content="/static/img/og-image.svg">
<meta property="og:site_name" content="tui-pages">
<!-- Twitter -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="tui-pages — a framework for building TUIs in Rust">
<meta name="twitter:description" content="Pre-programmed focus, keymaps, and page navigation. Stop rewriting the same architecture for every TUI project.">
<meta name="twitter:description" content="UX for TUIs in Rust. Stop rewriting the same architecture for every project.">
<meta name="twitter:image" content="/static/img/og-image.svg">
<!-- Preconnect -->
@@ -127,7 +129,7 @@
<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-zinc-300 hover:text-white rounded-md hover:bg-zinc-800/50 transition-colors">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://tui-pages.farmeris.sk/book" 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>
@@ -177,7 +179,7 @@
>
<ul class="px-4 py-3 space-y-1 text-sm">
<li><a href="/examples.html" class="block px-3 py-2 rounded-md text-zinc-300 hover:bg-zinc-800/60">Examples</a></li>
<li><a href="https://tui-pages.farmeris.sk" class="block px-3 py-2 rounded-md text-zinc-300 hover:bg-zinc-800/60">Book</a></li>
<li><a href="https://tui-pages.farmeris.sk/book" class="block px-3 py-2 rounded-md text-zinc-300 hover:bg-zinc-800/60">Book</a></li>
<li><a href="https://docs.rs/tui-pages" class="block px-3 py-2 rounded-md text-zinc-300 hover:bg-zinc-800/60">API</a></li>
<li><a href="https://gitlab.com/filipriec/tui-pages" class="block px-3 py-2 rounded-md text-zinc-300 hover:bg-zinc-800/60">GitLab</a></li>
</ul>
@@ -208,7 +210,7 @@
</h1>
<p class="mt-6 text-lg text-zinc-300 max-w-xl leading-relaxed">
<code class="font-mono text-accent">tui-pages</code> gives you a pre-programmed focus manager, input pipeline, keymaps, and page navigation on top of <a href="https://ratatui.rs" class="text-zinc-100 underline decoration-zinc-700 underline-offset-4 hover:decoration-accent">ratatui</a>. Stop rewriting the same architecture for every project.
<code class="font-mono text-accent">tui-pages</code> gives you full UX you would ever need. Stop rewriting the same architecture for every project.
</p>
<div class="mt-8 flex flex-wrap items-center gap-3">
@@ -216,7 +218,7 @@
Get started
<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://tui-pages.farmeris.sk" 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">
<a href="https://tui-pages.farmeris.sk/book" 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">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2zM22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/></svg>
Read the book
</a>
@@ -250,7 +252,12 @@
<div class="absolute -inset-4 -z-10 bg-gradient-to-br from-accent/15 via-transparent to-emerald-500/5 rounded-3xl blur-2xl"></div>
<div class="tp-float">
<div class="tp-terminal">
<img src="/static/img/terminal-default.svg" alt="Screenshot of the examples/default TUI app built with tui-pages" class="block w-full h-auto" loading="eager" width="640" height="400">
<img
src="/static/img/terminal-default.svg"
:src="theme === 'night' ? '/static/img/terminal-default.svg' : '/static/img/terminal-default-light.svg'"
alt="Screenshot of the examples/default TUI app built with tui-pages"
class="block w-full h-auto"
loading="eager" width="640" height="400">
</div>
<p class="mt-3 text-center text-xs text-zinc-500 font-mono">examples/default · cargo run</p>
</div>
@@ -563,8 +570,8 @@ pub fn keymaps() -&gt; KeyMap {
<div class="flex flex-wrap items-end justify-between gap-4">
<div class="max-w-2xl">
<p class="text-sm font-medium text-accent uppercase tracking-widest">Examples</p>
<h2 class="mt-3 text-3xl sm:text-4xl font-bold tracking-tight text-zinc-50">Three apps in the box.</h2>
<p class="mt-4 text-lg text-zinc-400 leading-relaxed">Each one is a full <code class="font-mono text-zinc-300">cargo run</code> away. Read the source, run it, fork it.</p>
<h2 class="mt-3 text-3xl sm:text-4xl font-bold tracking-tight text-zinc-50">Rich examples.</h2>
<p class="mt-4 text-lg text-zinc-400 leading-relaxed">Each one is a simple <code class="font-mono text-zinc-300">cargo run</code> away. Read the source, run it, copy it.</p>
</div>
<a href="/examples.html" class="inline-flex items-center gap-1.5 text-sm text-zinc-300 hover:text-white">
All examples
@@ -575,7 +582,12 @@ pub fn keymaps() -&gt; KeyMap {
<div class="mt-12 grid md:grid-cols-3 gap-6">
<a href="/examples.html#default" class="group block rounded-2xl border border-zinc-800 bg-zinc-950/50 overflow-hidden hover:border-accent/60 transition-colors">
<div class="tp-terminal m-3">
<img src="/static/img/terminal-default.svg" alt="default example screenshot" class="block w-full h-auto" loading="lazy" width="640" height="400">
<img
src="/static/img/terminal-default.svg"
:src="theme === 'night' ? '/static/img/terminal-default.svg' : '/static/img/terminal-default-light.svg'"
alt="default example screenshot"
class="block w-full h-auto"
loading="lazy" width="640" height="400">
</div>
<div class="p-5 pt-2">
<div class="flex items-center gap-2">
@@ -588,7 +600,12 @@ pub fn keymaps() -&gt; KeyMap {
<a href="/examples.html#canvas" class="group block rounded-2xl border border-zinc-800 bg-zinc-950/50 overflow-hidden hover:border-accent/60 transition-colors">
<div class="tp-terminal m-3">
<img src="/static/img/terminal-canvas.svg" alt="canvas example screenshot" class="block w-full h-auto" loading="lazy" width="640" height="400">
<img
src="/static/img/terminal-canvas.svg"
:src="theme === 'night' ? '/static/img/terminal-canvas.svg' : '/static/img/terminal-canvas-light.svg'"
alt="canvas example screenshot"
class="block w-full h-auto"
loading="lazy" width="640" height="400">
</div>
<div class="p-5 pt-2">
<div class="flex items-center gap-2">
@@ -601,7 +618,12 @@ pub fn keymaps() -&gt; KeyMap {
<a href="/examples.html#keybindings" class="group block rounded-2xl border border-zinc-800 bg-zinc-950/50 overflow-hidden hover:border-accent/60 transition-colors">
<div class="tp-terminal m-3">
<img src="/static/img/terminal-keybindings.svg" alt="keybindings example screenshot" class="block w-full h-auto" loading="lazy" width="640" height="400">
<img
src="/static/img/terminal-keybindings.svg"
:src="theme === 'night' ? '/static/img/terminal-keybindings.svg' : '/static/img/terminal-keybindings-light.svg'"
alt="keybindings example screenshot"
class="block w-full h-auto"
loading="lazy" width="640" height="400">
</div>
<div class="p-5 pt-2">
<div class="flex items-center gap-2">
@@ -660,7 +682,7 @@ rt.run() // framework handles the rest</code></pre>
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-10 flex flex-wrap items-center justify-center gap-3">
<a href="https://tui-pages.farmeris.sk" class="inline-flex items-center gap-2 h-12 px-6 rounded-lg bg-accent text-accent-fg font-medium hover:bg-accent/90 transition-colors">
<a href="https://tui-pages.farmeris.sk/book" class="inline-flex items-center gap-2 h-12 px-6 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>
@@ -691,7 +713,7 @@ rt.run() // framework handles the rest</code></pre>
<h4 class="text-xs font-semibold uppercase tracking-widest text-zinc-400">Resources</h4>
<ul class="mt-3 space-y-2 text-sm">
<li><a href="https://docs.rs/tui-pages" class="text-zinc-300 hover:text-white">API reference</a></li>
<li><a href="https://tui-pages.farmeris.sk" class="text-zinc-300 hover:text-white">The Book</a></li>
<li><a href="https://tui-pages.farmeris.sk/book" class="text-zinc-300 hover:text-white">The Book</a></li>
<li><a href="/examples.html" class="text-zinc-300 hover:text-white">Examples</a></li>
<li><a href="https://crates.io/crates/tui-pages" class="text-zinc-300 hover:text-white">crates.io</a></li>
</ul>

View File

@@ -1,4 +1,4 @@
User-agent: *
Allow: /
Sitemap: https://tui-pages.dev/sitemap.xml
Sitemap: https://tui-pages.farmeris.sk/sitemap.xml

View File

@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://tui-pages.dev/</loc>
<loc>https://tui-pages.farmeris.sk/</loc>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>https://tui-pages.dev/examples.html</loc>
<loc>https://tui-pages.farmeris.sk/examples.html</loc>
<changefreq>weekly</changefreq>
<priority>0.9</priority>
</url>

View File

@@ -12,6 +12,7 @@
- tints the dense characters rust-orange with text-shadow + glow
- adds a CRT scanline overlay
- disables the animation under prefers-reduced-motion
- swaps the tint for a soft sepia wash in light mode (paper & ink feel)
========================================================================== */
/* Full-screen ASCII mountain top layer ----------------------------------- */
@@ -28,17 +29,18 @@
margin: 0;
padding: 0;
font-family: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
font-size: max(0.35vw, 0.695vh);
font-size: max(0.35vw, 0.695svh);
/* font-size: max(0.7vw, 1.39vh); */ /* 240p */
font-size: max(0.463vw, 0.926vh); /* 360p */
line-height: 1.0;
letter-spacing: 0;
color: #f4a26b;
text-shadow: 0 0 8px rgba(183, 65, 14, 0.35);
opacity: 0.45;
color: var(--tp-mountain-color, #f4a26b);
text-shadow: 0 0 8px var(--tp-mountain-glow, rgba(183, 65, 14, 0.35));
opacity: var(--tp-mountain-opacity, 0.45);
white-space: pre;
background: transparent;
overflow: hidden;
user-select: none;
transition: color 250ms ease, opacity 250ms ease, text-shadow 250ms ease;
}
/* CRT scanlines overlay - a thin moving line every 2px. Faint so it doesn't
@@ -64,10 +66,13 @@
100% { background-position: 0 6px; }
}
/* Light theme: dim the background, drop the glow, switch to dark text. */
/* ---------- Light theme: faded ink wash on paper ------------------------
In winter mode the ASCII becomes a soft sepia watermark — a hint of
"topography" rather than a glowing graphic. The scanlines swap to
light-on-dark so they still add texture without darkening the page. */
:root[data-theme="winter"] .tp-mountain-bg {
opacity: 0.20;
color: #2a1810;
opacity: 0.12; /* much fainter than the dark mode rust */
color: #6b5236; /* warm sepia, harmonizes with cream bg */
text-shadow: none;
mix-blend-mode: multiply;
}
@@ -77,10 +82,10 @@
to bottom,
transparent 0,
transparent 2px,
rgba(255, 255, 255, 0.12) 2px,
rgba(255, 255, 255, 0.12) 3px
rgba(28, 25, 23, 0.05) 2px,
rgba(28, 25, 23, 0.05) 3px
);
mix-blend-mode: screen;
mix-blend-mode: multiply;
}
/* Reduced motion: keep the first frame static, no scanline drift. */

View File

@@ -21,30 +21,128 @@ html {
}
}
/* ---------- Theme (default to dark) -------------------------------------- */
/* ---------- Theme tokens -------------------------------------------------
Dark (night) is the default. The `[data-theme="winter"]` block redefines
the same tokens for the light theme. Everything below reads from these. */
:root {
color-scheme: dark light;
--tp-accent: #b7410e;
--tp-accent-fg: #fff5f0;
--tp-grid-line: rgba(63, 63, 70, 0.35);
--tp-hero-from: #0b0b0f;
--tp-hero-to: #18181b;
--tp-text-outline: rgba(0, 0, 0, 0.9);
/* Brand (rust) */
--tp-accent: #b7410e; /* primary accent */
--tp-accent-strong: #d24e15; /* hover/active */
--tp-accent-fg: #fff5f0; /* text-on-accent */
--tp-accent-soft: rgba(183, 65, 14, 0.12);
--tp-accent-glow: rgba(183, 65, 14, 0.35);
/* Surfaces (dark) */
--tp-bg: #09090b; /* page bg */
--tp-bg-elev: #18181b; /* raised surface */
--tp-bg-soft: rgba(24, 24, 27, 0.5);
--tp-bg-card: rgba(24, 24, 27, 0.5);
--tp-bg-card-hover: rgba(24, 24, 27, 0.78);
--tp-bg-nav: rgba(9, 9, 11, 0.65);
--tp-bg-mobile: rgba(9, 9, 11, 0.95);
--tp-bg-section: rgba(24, 24, 27, 0.3); /* alt section tint */
--tp-bg-code: #0b0b0f;
/* Text (dark) */
--tp-fg: #fafafa; /* primary text */
--tp-fg-strong: #ffffff;
--tp-fg-secondary: #d4d4d8; /* body */
--tp-fg-muted: #a1a1aa;
--tp-fg-subtle: #71717a;
--tp-fg-code: #f4f4f5;
/* Borders (dark) */
--tp-border: rgba(63, 63, 70, 0.5);
--tp-border-strong: rgba(63, 63, 70, 0.7);
--tp-border-section:rgba(63, 63, 70, 0.4);
/* Hero / grid (dark) */
--tp-grid-line: rgba(63, 63, 70, 0.35);
--tp-hero-from: #0b0b0f;
--tp-hero-to: #18181b;
--tp-text-outline: rgba(0, 0, 0, 0.9);
--tp-hero-glow-a: rgba(183, 65, 14, 0.10);
--tp-hero-glow-b: rgba(126, 231, 135, 0.05);
/* Mountain background (dark — rust on black) */
--tp-mountain-color: #f4a26b;
--tp-mountain-glow: rgba(183, 65, 14, 0.35);
--tp-mountain-opacity:0.45;
/* Shadows (dark — soft + deep) */
--tp-card-shadow: 0 1px 0 rgba(255, 255, 255, 0.02) inset,
0 12px 24px -16px rgba(0, 0, 0, 0.6);
--tp-card-shadow-hover:
0 1px 0 rgba(255, 255, 255, 0.04) inset,
0 18px 36px -18px rgba(0, 0, 0, 0.7);
}
/* Light theme — warm paper. We swap to a stone (warm-gray) palette so the
text and surfaces harmonize with the rust accent instead of fighting it. */
:root[data-theme="winter"] {
--tp-accent: #93330c;
--tp-accent-fg: #fff5f0;
--tp-grid-line: rgba(228, 228, 231, 0.7);
--tp-hero-from: #fafafa;
--tp-hero-to: #f4f4f5;
--tp-text-outline: rgba(255, 255, 255, 0.95);
/* Brand — slightly darker rust so it has bite on a light bg */
--tp-accent: #9a3a0e;
--tp-accent-strong: #7f2f08;
--tp-accent-fg: #fff7ed;
--tp-accent-soft: rgba(154, 58, 14, 0.08);
--tp-accent-glow: rgba(154, 58, 14, 0.0);
/* Surfaces (warm off-white, not stark) */
--tp-bg: #fbfaf7; /* page bg, slight cream */
--tp-bg-elev: #ffffff; /* cards */
--tp-bg-soft: rgba(255, 255, 255, 0.7);
--tp-bg-card: #ffffff;
--tp-bg-card-hover: #ffffff;
--tp-bg-nav: rgba(255, 255, 255, 0.78);
--tp-bg-mobile: rgba(255, 255, 255, 0.97);
--tp-bg-section: #f3f1ec; /* warm section alt */
--tp-bg-code: #0b0b0f; /* keep code blocks dark in both themes */
/* Text (warm dark — stone, not zinc, so it doesn't look like a science lab) */
--tp-fg: #1c1917; /* primary (stone-900) */
--tp-fg-strong: #0c0a09; /* stone-950 */
--tp-fg-secondary: #44403c; /* stone-700 */
--tp-fg-muted: #57534e; /* stone-600 */
--tp-fg-subtle: #78716c; /* stone-500 */
--tp-fg-code: #f4f4f5;
/* Borders (warm taupe) */
--tp-border: rgba(214, 211, 209, 0.9); /* stone-300 */
--tp-border-strong: rgba(168, 162, 158, 0.8); /* stone-400 */
--tp-border-section:rgba(214, 211, 209, 0.65);
/* Hero / grid (warm, very subtle) */
--tp-grid-line: rgba(180, 130, 80, 0.14);
--tp-hero-from: #fbfaf7;
--tp-hero-to: #f5f3ee;
--tp-text-outline: rgba(255, 255, 255, 0.95);
--tp-hero-glow-a: rgba(154, 58, 14, 0.07);
--tp-hero-glow-b: rgba(120, 140, 90, 0.05);
/* Mountain — very subtle, like a faded ink wash on paper */
--tp-mountain-color: #8a6a44; /* warm sepia */
--tp-mountain-glow: rgba(138, 106, 68, 0);
--tp-mountain-opacity:0.10;
/* Shadows (soft, warm-tinted, like a printed page) */
--tp-card-shadow: 0 1px 0 rgba(255, 255, 255, 1) inset,
0 1px 2px rgba(28, 25, 23, 0.04),
0 8px 24px -12px rgba(28, 25, 23, 0.10);
--tp-card-shadow-hover:
0 1px 0 rgba(255, 255, 255, 1) inset,
0 1px 2px rgba(28, 25, 23, 0.05),
0 14px 32px -14px rgba(154, 58, 14, 0.18);
}
/* ---------- Body --------------------------------------------------------- */
body {
font-family: 'Inter', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
font-feature-settings: 'cv11', 'ss01', 'ss03';
background-color: var(--tp-bg);
color: var(--tp-fg);
transition: background-color 200ms ease, color 200ms ease;
}
/* ---------- View Transitions (progressive enhancement) ------------------ */
@@ -80,6 +178,19 @@ body {
1px 1px 0 var(--tp-text-outline),
0 2px 16px rgba(0, 0, 0, 0.9);
}
:root[data-theme="winter"] .tp-hero h1,
:root[data-theme="winter"] .tp-hero p {
text-shadow:
0 -1px 0 var(--tp-text-outline),
1px 0 0 var(--tp-text-outline),
0 1px 0 var(--tp-text-outline),
-1px 0 0 var(--tp-text-outline),
-1px -1px 0 var(--tp-text-outline),
1px -1px 0 var(--tp-text-outline),
-1px 1px 0 var(--tp-text-outline),
1px 1px 0 var(--tp-text-outline),
0 2px 12px rgba(154, 58, 14, 0.10);
}
.tp-hero::before {
content: "";
@@ -96,8 +207,11 @@ body {
z-index: -1;
opacity: 0.5; /* subtle grid, not a wall */
}
:root[data-theme="winter"] .tp-hero::before {
opacity: 0.7; /* show a touch more on paper */
}
/* Subtle floating code lines in the hero, behind the content */
/* Subtle floating glow in the hero, behind the content */
.tp-hero-glow {
position: absolute;
inset: 0;
@@ -105,43 +219,37 @@ body {
z-index: -1;
opacity: 0.6;
background:
radial-gradient(circle at 15% 30%, rgba(183, 65, 14, 0.08), transparent 35%),
radial-gradient(circle at 85% 70%, rgba(126, 231, 135, 0.05), transparent 35%);
radial-gradient(circle at 15% 30%, var(--tp-hero-glow-a), transparent 35%),
radial-gradient(circle at 85% 70%, var(--tp-hero-glow-b), transparent 35%);
}
/* ---------- Glass nav ---------------------------------------------------- */
.tp-nav {
background: rgba(9, 9, 11, 0.65);
background: var(--tp-bg-nav);
backdrop-filter: saturate(160%) blur(12px);
-webkit-backdrop-filter: saturate(160%) blur(12px);
border-bottom: 1px solid rgba(63, 63, 70, 0.4);
}
:root[data-theme="winter"] .tp-nav {
background: rgba(255, 255, 255, 0.7);
border-bottom-color: rgba(228, 228, 231, 0.7);
border-bottom: 1px solid var(--tp-border);
transition: background 200ms ease, border-color 200ms ease;
}
/* ---------- Feature cards ------------------------------------------------ */
.tp-card {
position: relative;
background: rgba(24, 24, 27, 0.5);
border: 1px solid rgba(63, 63, 70, 0.5);
background: var(--tp-bg-card);
border: 1px solid var(--tp-border);
border-radius: 1rem;
padding: 1.5rem;
transition: border-color 200ms ease, transform 200ms ease, background 200ms ease;
box-shadow: var(--tp-card-shadow);
transition: border-color 200ms ease, transform 200ms ease,
background 200ms ease, box-shadow 200ms ease;
}
.tp-card:hover {
border-color: rgba(183, 65, 14, 0.6);
background: rgba(24, 24, 27, 0.75);
transform: translateY(-2px);
}
:root[data-theme="winter"] .tp-card {
background: rgba(255, 255, 255, 0.6);
border-color: rgba(228, 228, 231, 0.8);
background: var(--tp-bg-card-hover);
box-shadow: var(--tp-card-shadow-hover);
}
:root[data-theme="winter"] .tp-card:hover {
background: rgba(255, 255, 255, 0.9);
border-color: rgba(183, 65, 14, 0.4);
border-color: rgba(154, 58, 14, 0.4);
}
.tp-card-icon {
@@ -151,11 +259,14 @@ body {
width: 2.5rem;
height: 2.5rem;
border-radius: 0.75rem;
background: rgba(183, 65, 14, 0.12);
background: var(--tp-accent-soft);
color: var(--tp-accent);
border: 1px solid rgba(183, 65, 14, 0.25);
border: 1px solid var(--tp-accent-glow);
margin-bottom: 1rem;
}
:root[data-theme="winter"] .tp-card-icon {
border-color: rgba(154, 58, 14, 0.18);
}
/* ---------- Code blocks (kitchen sink — hljs + custom) ------------------ */
.tp-code {
@@ -165,13 +276,19 @@ body {
tab-size: 4;
}
.tp-code pre {
background: #0b0b0f;
border: 1px solid rgba(63, 63, 70, 0.5);
background: var(--tp-bg-code);
border: 1px solid var(--tp-border);
border-radius: 0.75rem;
padding: 1.25rem 1.5rem;
overflow-x: auto;
margin: 0;
}
:root[data-theme="winter"] .tp-code pre {
/* keep the code panel a little warmer on light pages, like a printed
code listing on cream paper */
border-color: rgba(0, 0, 0, 0.12);
box-shadow: 0 12px 28px -16px rgba(28, 25, 23, 0.35);
}
.tp-code pre code.hljs {
background: transparent;
padding: 0;
@@ -185,17 +302,18 @@ body {
font-family: 'JetBrains Mono', ui-monospace, monospace;
font-size: 0.75rem;
font-weight: 500;
border: 1px solid rgba(63, 63, 70, 0.7);
border: 1px solid var(--tp-border-strong);
border-bottom-width: 2px;
border-radius: 0.375rem;
background: rgba(39, 39, 42, 0.6);
color: #f4f4f5;
color: var(--tp-fg-code);
line-height: 1;
}
:root[data-theme="winter"] .tp-kbd {
background: #fff;
color: #18181b;
border-color: #d4d4d8;
background: #ffffff;
color: #1c1917;
border-color: #d6d3d1;
box-shadow: 0 1px 0 rgba(28, 25, 23, 0.04);
}
/* ---------- Terminal window wrapper -------------------------------------- */
@@ -209,6 +327,12 @@ body {
0 18px 36px -18px rgba(0, 0, 0, 0.45);
overflow: hidden;
}
:root[data-theme="winter"] .tp-terminal {
box-shadow:
0 0 0 1px rgba(154, 58, 14, 0.18),
0 24px 48px -20px rgba(154, 58, 14, 0.22),
0 12px 24px -16px rgba(28, 25, 23, 0.10);
}
.tp-terminal::after {
content: "";
position: absolute;
@@ -224,6 +348,15 @@ body {
); /* darken only the top + bottom strips, leave the middle transparent
so the body ASCII art shows through the terminal content */
}
:root[data-theme="winter"] .tp-terminal::after {
background: linear-gradient(
to bottom,
rgba(255, 255, 255, 0.10) 0%,
rgba(255, 255, 255, 0) 18%,
rgba(255, 255, 255, 0) 82%,
rgba(255, 255, 255, 0.10) 100%
);
}
/* ---------- Selection --------------------------------------------------- */
::selection {
@@ -242,27 +375,153 @@ body {
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
background: rgba(63, 63, 70, 0.6);
background: var(--tp-border-strong);
border-radius: 999px;
border: 2px solid transparent;
background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover { background-color: rgba(82, 82, 91, 0.8); background-clip: padding-box; }
::-webkit-scrollbar-thumb:hover {
background-color: var(--tp-fg-subtle);
background-clip: padding-box;
}
/* ---------- No-FOUC theme flash ----------------------------------------- */
html:not([data-theme]) body { background: #09090b; }
:root[data-theme="winter"] body { background: #fafafa; }
/* ---------- Alpine x-cloak (prevents flash of un-initialised content) --- */
[x-cloak] { display: none !important; }
/* ---------- DaisyUI overrides for our theme ----------------------------- */
/* Bring DaisyUI's primary to our accent so .btn-primary etc. look on-brand. */
[data-theme="night"] {
--p: 28 70% 36%;
--pc: 0 0% 100%;
--b1: 240 5% 8%;
--b2: 240 4% 12%;
--b3: 240 4% 16%;
--bc: 0 0% 96%;
/* ==========================================================================
THEME-AWARE TAILWIND OVERRIDES
--------------------------------------------------------------------------
The HTML uses hardcoded `text-zinc-*`, `bg-zinc-*`, `border-zinc-*` etc.
(so the source reads like a normal dark-mode-first site). In light mode
we transparently remap those zinc slots to our warm stone palette.
This block has higher selector specificity (`:root[data-theme=...] .foo`)
than the Tailwind utility class on its own, so it wins without `!important`.
========================================================================== */
:root[data-theme="winter"] {
/* ---- DaisyUI body tokens ----------------------------------------------
daisyUI 4 uses OKLCH under the hood (`oklch(var(--b1) / .N)`); our custom
HSL-flavoured values don't parse, so `bg-base-100` would resolve to
transparent. We override the class directly with our token-driven colour. */
.bg-base-100 { background-color: var(--tp-bg); }
.text-base-content { color: var(--tp-fg); }
/* ---- text ---- */
.text-zinc-50 { color: #0c0a09; }
.text-zinc-100 { color: #1c1917; }
.text-zinc-200 { color: #292524; }
.text-zinc-300 { color: #44403c; }
.text-zinc-400 { color: #57534e; }
.text-zinc-500 { color: #78716c; }
.text-zinc-600 { color: #57534e; }
.text-zinc-700 { color: #d6d3d1; } /* dividers + rare text */
.text-zinc-800 { color: #e7e5e4; }
.text-zinc-900 { color: #ffffff; }
.text-zinc-950 { color: #ffffff; }
.text-white { color: #1c1917; }
/* ---- backgrounds ---- */
.bg-zinc-50 { background-color: #fafaf9; }
.bg-zinc-100 { background-color: #f5f5f4; }
.bg-zinc-200 { background-color: #e7e5e4; }
.bg-zinc-300 { background-color: #d6d3d1; }
.bg-zinc-400 { background-color: #a8a29e; }
.bg-zinc-500 { background-color: #78716c; }
.bg-zinc-600 { background-color: #57534e; }
.bg-zinc-700 { background-color: #d6d3d1; }
.bg-zinc-800 { background-color: #e7e5e4; }
.bg-zinc-900 { background-color: #ffffff; }
.bg-zinc-900\/40 { background-color: rgba(255, 255, 255, 0.65); }
.bg-zinc-900\/50 { background-color: rgba(255, 255, 255, 0.75); }
.bg-zinc-900\/60 { background-color: rgba(255, 255, 255, 0.85); }
.bg-zinc-950 { background-color: #ffffff; }
.bg-zinc-950\/30 { background-color: #f3f1ec; } /* section alt */
.bg-zinc-950\/40 { background-color: #f5f3ee; } /* trust strip */
.bg-zinc-950\/50 { background-color: #ffffff; }
.bg-zinc-950\/60 { background-color: #ffffff; }
.bg-zinc-950\/80 { background-color: #ffffff; }
.bg-zinc-950\/95 { background-color: #ffffff; }
/* ---- borders ---- */
.border-zinc-700 { border-color: #d6d3d1; }
.border-zinc-800 { border-color: #e7e5e4; }
.border-zinc-800\/40 { border-color: rgba(214, 211, 209, 0.55); }
.border-zinc-800\/60 { border-color: rgba(214, 211, 209, 0.75); }
.border-zinc-900\/50 { border-color: rgba(214, 211, 209, 0.7); }
/* The decoration on links (ratatui etc) */
.decoration-zinc-700 { text-decoration-color: #d6d3d1; }
/* ---- hover states (mirror the text/bg map, with a touch more contrast) ---- */
.hover\:text-white:hover { color: #0c0a09; }
.hover\:text-zinc-100:hover { color: #0c0a09; }
.hover\:text-zinc-200:hover { color: #1c1917; }
.hover\:text-zinc-300:hover { color: #1c1917; }
.hover\:text-zinc-400:hover { color: #1c1917; }
.hover\:bg-zinc-800\/50:hover { background-color: rgba(231, 229, 228, 0.7); }
.hover\:bg-zinc-800\/60:hover { background-color: rgba(231, 229, 228, 0.85); }
.hover\:bg-zinc-900:hover { background-color: #f5f3ee; }
.hover\:border-zinc-500:hover { border-color: #a8a29e; }
.hover\:border-zinc-700:hover { border-color: #a8a29e; }
.hover\:decoration-accent:hover { text-decoration-color: var(--tp-accent); }
/* ---- accent (rust) — slightly darker on light for legibility ---- */
.text-accent { color: #9a3a0e; }
.bg-accent { background-color: #9a3a0e; }
.bg-accent\/5 { background-color: rgba(154, 58, 14, 0.05); }
.bg-accent\/10 { background-color: rgba(154, 58, 14, 0.08); }
.bg-accent\/15 { background-color: rgba(154, 58, 14, 0.12); }
.border-accent { border-color: #9a3a0e; }
.border-accent\/30 { border-color: rgba(154, 58, 14, 0.25); }
.border-accent\/40 { border-color: rgba(154, 58, 14, 0.35); }
.border-accent\/60 { border-color: rgba(154, 58, 14, 0.55); }
.hover\:bg-accent\/90:hover { background-color: #7f2f08; }
.hover\:border-accent\/60:hover { border-color: rgba(154, 58, 14, 0.55); }
.hover\:text-accent:hover { color: #9a3a0e; }
.from-accent\/15 { --tw-gradient-from: rgba(154, 58, 14, 0.18); --tw-gradient-to: rgba(154, 58, 14, 0); --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); }
.to-emerald-500\/5 { --tw-gradient-to: rgba(16, 185, 129, 0.06); }
/* ---- tab pill in code-example tab bar ---- */
.bg-zinc-800 { background-color: #e7e5e4; }
.bg-zinc-800.text-white { color: #1c1917; }
}
/* ==========================================================================
DaisyUI overrides for our theme
--------------------------------------------------------------------------
DaisyUI 4 ships a built-in `night` theme — we already use it for dark.
`winter` is our own theme, so we register its HSL tokens so things like
`.bg-base-100` and `.text-base-content` resolve correctly.
Format is "H S% L%" (no hsl() wrapper) — DaisyUI concatenates.
========================================================================== */
[data-theme="night"] {
--p: 20 75% 38%; /* primary — rust */
--pc: 20 100% 97%;
--b1: 240 6% 7%; /* base 100 */
--b2: 240 5% 11%;
--b3: 240 5% 14%;
--bc: 0 0% 96%; /* base content */
/* DaisyUI 4 expects OKLCH and ignores HSL on modern browsers. Provide
the fallback so the body has a real colour even if OKLCH parsing fails. */
--fallback-b1: #09090b;
--fallback-bc: #fafafa;
/* Make DaisyUI semantic tokens resolve to our rust accent. */
.bg-base-100 { background-color: var(--tp-bg); }
.text-base-content { color: var(--tp-fg); }
}
[data-theme="winter"] {
--p: 19 82% 32%; /* primary — darker rust, sits on cream */
--pc: 30 100% 97%;
--b1: 36 25% 97%; /* base 100 — warm paper */
--b2: 36 18% 94%;
--b3: 36 12% 89%;
--bc: 24 12% 12%; /* base content — warm near-black */
--n: 24 10% 18%; /* neutral */
--nc: 36 25% 97%;
--fallback-b1: #fbfaf7;
--fallback-bc: #1c1917;
}

View File

@@ -0,0 +1,120 @@
<svg viewBox="0 0 640 400" xmlns="http://www.w3.org/2000/svg" class="w-full h-auto" role="img" aria-label="A text editor built with the tui-pages textarea: relative line numbers and Rust syntax highlighting">
<!-- Light-mode twin of terminal-canvas.svg. Same 80x25 grid, light neutral palette. -->
<style>
.text { fill: #26272b; }
.muted { fill: #5a5a62; }
.dim { fill: #8a8a90; }
.blue { fill: #1f7fb8; }
.gold { fill: #a8862a; }
.green { fill: #1f9d3f; }
.pink { fill: #d6398b; }
.greenfg{ fill: #f2fff2; }
.curfg { fill: #f4f4f2; }
.b { font-weight: 700; }
text {
font-family: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
font-size: 13px;
text-rendering: geometricPrecision;
}
</style>
<g xml:space="preserve">
<rect x="0.5" y="0.5" width="639" height="399" rx="10" fill="#f4f4f2" stroke="#d8d8d2"/>
<rect x="0" y="2" width="72" height="20" class="green"/>
<text x="8" y="16" class="greenfg b">main.rs</text>
<text x="80" y="16" class="muted">lib.rs</text>
<text x="144" y="16" class="muted">Cargo.toml</text>
<rect x="0" y="96" width="640" height="16" fill="#e7e7e3"/>
<text x="16" y="44" class="dim" text-anchor="end">4</text>
<text x="16" y="60" class="dim" text-anchor="end">3</text>
<text x="16" y="76" class="dim" text-anchor="end">2</text>
<text x="16" y="92" class="dim" text-anchor="end">1</text>
<text x="8" y="108" class="gold b">5</text>
<text x="16" y="124" class="dim" text-anchor="end">1</text>
<text x="16" y="140" class="dim" text-anchor="end">2</text>
<text x="16" y="156" class="dim" text-anchor="end">3</text>
<text x="16" y="172" class="dim" text-anchor="end">4</text>
<text x="16" y="188" class="dim" text-anchor="end">5</text>
<text x="16" y="204" class="dim" text-anchor="end">6</text>
<text x="32" y="44" class="pink">use</text>
<text x="64" y="44" class="text">tui_pages</text>
<text x="136" y="44" class="muted">::</text>
<text x="152" y="44" class="muted">{</text>
<text x="160" y="44" class="gold">Page</text>
<text x="192" y="44" class="muted">,</text>
<text x="208" y="44" class="gold">TextArea</text>
<text x="272" y="44" class="muted">}</text>
<text x="280" y="44" class="muted">;</text>
<text x="32" y="76" class="pink">pub</text>
<text x="64" y="76" class="pink">fn</text>
<text x="88" y="76" class="blue">editor</text>
<text x="136" y="76" class="muted">()</text>
<text x="160" y="76" class="muted">-&gt;</text>
<text x="184" y="76" class="gold">Page</text>
<text x="224" y="76" class="muted">{</text>
<text x="64" y="92" class="pink">let</text>
<text x="96" y="92" class="text">title</text>
<text x="144" y="92" class="muted">=</text>
<text x="160" y="92" class="green">"Editor"</text>
<text x="224" y="92" class="muted">;</text>
<text x="64" y="108" class="pink">let</text>
<text x="96" y="108" class="pink">mut</text>
<rect x="128" y="96" width="8" height="16" fill="#26272b"/>
<text x="128" y="108" class="curfg">a</text>
<text x="136" y="108" class="text">rea</text>
<text x="168" y="108" class="muted">=</text>
<text x="184" y="108" class="gold">TextArea</text>
<text x="248" y="108" class="muted">::</text>
<text x="264" y="108" class="blue">default</text>
<text x="320" y="108" class="muted">()</text>
<text x="336" y="108" class="muted">;</text>
<text x="64" y="124" class="text">area</text>
<text x="96" y="124" class="muted">.</text>
<text x="104" y="124" class="blue">set_placeholder</text>
<text x="224" y="124" class="muted">(</text>
<text x="232" y="124" class="green">"Type here…"</text>
<text x="328" y="124" class="muted">)</text>
<text x="336" y="124" class="muted">;</text>
<text x="64" y="156" class="gold">Page</text>
<text x="96" y="156" class="muted">::</text>
<text x="112" y="156" class="blue">new</text>
<text x="136" y="156" class="muted">(</text>
<text x="144" y="156" class="text">title</text>
<text x="184" y="156" class="muted">)</text>
<text x="96" y="172" class="muted">.</text>
<text x="104" y="172" class="blue">child</text>
<text x="144" y="172" class="muted">(</text>
<text x="152" y="172" class="text">area</text>
<text x="184" y="172" class="muted">)</text>
<text x="96" y="188" class="muted">.</text>
<text x="104" y="188" class="blue">on_key</text>
<text x="152" y="188" class="muted">(</text>
<text x="160" y="188" class="green">'q'</text>
<text x="184" y="188" class="muted">,</text>
<text x="200" y="188" class="muted">|</text>
<text x="208" y="188" class="text">app</text>
<text x="232" y="188" class="muted">|</text>
<text x="248" y="188" class="text">app</text>
<text x="272" y="188" class="muted">.</text>
<text x="280" y="188" class="blue">quit</text>
<text x="312" y="188" class="muted">())</text>
<text x="32" y="204" class="muted">}</text>
<text x="32" y="380" class="green b">NOR</text>
<text x="120" y="380" class="muted">main.rs</text>
<text x="256" y="380" class="muted">Ln 5, Col 18</text>
<text x="632" y="380" class="gold" text-anchor="end">tui-pages v0.7.2 │ 60 FPS</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@@ -1,52 +1,138 @@
<svg viewBox="0 0 640 400" xmlns="http://www.w3.org/2000/svg" class="w-full h-auto" role="img" aria-label="examples/canvas terminal screenshot">
<svg viewBox="0 0 640 400" xmlns="http://www.w3.org/2000/svg" class="w-full h-auto" role="img" aria-label="A text editor built with the tui-pages textarea: relative line numbers and Rust syntax highlighting">
<!--
tui-pages textarea showcased as a modal-editor (vim/helix style) on a strict
80x25 monospace grid (cell = 8x16 px). Each cell carries at most two colors.
Gutter: current line shows its absolute number, others are relative.
Syntax: kw=pink, type=gold, fn=blue, string=green, punctuation=muted.
-->
<style>
.bg { fill: #18181b; }
.chrome { fill: #27272a; }
.dot { fill: #52525b; }
.field { fill: #0e0e10; stroke: #3f3f46; stroke-width: 1; }
.field-focus { fill: #1c130f; stroke: #b7410e; stroke-width: 2; }
.btn { fill: #b7410e; }
.sep { stroke: #27272a; stroke-width: 1; }
text { font-family: ui-monospace, 'JetBrains Mono', 'SF Mono', Menlo, Consolas, monospace; fill: #f4f4f5; }
.t-md { font-size: 14px; }
.t-sm { font-size: 12px; }
.t-xs { font-size: 11px; }
.muted { fill: #a1a1aa; }
.dim { fill: #71717a; }
.label { fill: #a1a1aa; letter-spacing: 0.08em; }
.btn-fg { fill: #fff5f0; }
.text { fill: #d7d7db; }
.muted { fill: #9a9aa2; }
.dim { fill: #6b6b72; }
.blue { fill: #3ba7e0; }
.gold { fill: #d9b54a; }
.green { fill: #46d160; }
.pink { fill: #f25fa0; }
.greenfg{ fill: #0c130c; }
.curfg { fill: #1a1b1e; }
.b { font-weight: 700; }
text {
font-family: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
font-size: 13px;
text-rendering: geometricPrecision;
}
</style>
<rect class="bg" width="640" height="400" rx="12"/>
<rect class="chrome" width="640" height="36" rx="12"/>
<rect class="chrome" y="24" width="640" height="12"/>
<line class="sep" x1="0" y1="36" x2="640" y2="36"/>
<g xml:space="preserve">
<rect x="0.5" y="0.5" width="639" height="399" rx="10" fill="#1a1b1e" stroke="#2a2b30"/>
<circle class="dot" cx="20" cy="18" r="5.5"/>
<circle class="dot" cx="40" cy="18" r="5.5"/>
<circle class="dot" cx="60" cy="18" r="5.5"/>
<!-- buffer tabs (main.rs active) -->
<rect x="0" y="2" width="72" height="20" class="green"/>
<text x="8" y="16" class="greenfg b">main.rs</text>
<text x="80" y="16" class="muted">lib.rs</text>
<text x="144" y="16" class="muted">Cargo.toml</text>
<text x="320" y="22" text-anchor="middle" font-size="11" class="dim">examples/canvas — login page</text>
<!-- cursorline -->
<rect x="0" y="96" width="640" height="16" fill="#232428"/>
<text x="40" y="80" font-size="20" font-weight="700">Sign in</text>
<text x="40" y="104" font-size="12" class="muted">Use Tab to move between fields. Enter to submit.</text>
<!-- gutter: relative numbers, current line absolute -->
<text x="16" y="44" class="dim" text-anchor="end">4</text>
<text x="16" y="60" class="dim" text-anchor="end">3</text>
<text x="16" y="76" class="dim" text-anchor="end">2</text>
<text x="16" y="92" class="dim" text-anchor="end">1</text>
<text x="8" y="108" class="gold b">5</text>
<text x="16" y="124" class="dim" text-anchor="end">1</text>
<text x="16" y="140" class="dim" text-anchor="end">2</text>
<text x="16" y="156" class="dim" text-anchor="end">3</text>
<text x="16" y="172" class="dim" text-anchor="end">4</text>
<text x="16" y="188" class="dim" text-anchor="end">5</text>
<text x="16" y="204" class="dim" text-anchor="end">6</text>
<text x="40" y="156" font-size="10" class="label">USERNAME</text>
<rect class="field-focus" x="40" y="164" width="560" height="38" rx="6"/>
<text x="56" y="189" font-size="14">filip</text>
<rect x="92" y="172" width="2" height="22" fill="#b7410e">
<animate attributeName="opacity" values="1;0;1" dur="1s" repeatCount="indefinite"/>
</rect>
<!-- line 1: use tui_pages::{Page, TextArea}; -->
<text x="32" y="44" class="pink">use</text>
<text x="64" y="44" class="text">tui_pages</text>
<text x="136" y="44" class="muted">::</text>
<text x="152" y="44" class="muted">{</text>
<text x="160" y="44" class="gold">Page</text>
<text x="192" y="44" class="muted">,</text>
<text x="208" y="44" class="gold">TextArea</text>
<text x="272" y="44" class="muted">}</text>
<text x="280" y="44" class="muted">;</text>
<text x="40" y="232" font-size="10" class="label">PASSWORD</text>
<rect class="field" x="40" y="240" width="560" height="38" rx="6"/>
<text x="56" y="265" font-size="14" class="muted">••••••••••••</text>
<!-- line 3: pub fn editor() -> Page { -->
<text x="32" y="76" class="pink">pub</text>
<text x="64" y="76" class="pink">fn</text>
<text x="88" y="76" class="blue">editor</text>
<text x="136" y="76" class="muted">()</text>
<text x="160" y="76" class="muted">-&gt;</text>
<text x="184" y="76" class="gold">Page</text>
<text x="224" y="76" class="muted">{</text>
<rect class="btn" x="40" y="300" width="140" height="38" rx="6"/>
<text x="110" y="324" text-anchor="middle" font-size="13" class="btn-fg" font-weight="600">Sign in</text>
<text x="200" y="324" font-size="11" class="dim">esc · cancel</text>
<!-- line 4: let title = "Editor"; -->
<text x="64" y="92" class="pink">let</text>
<text x="96" y="92" class="text">title</text>
<text x="144" y="92" class="muted">=</text>
<text x="160" y="92" class="green">"Editor"</text>
<text x="224" y="92" class="muted">;</text>
<line class="sep" x1="0" y1="358" x2="640" y2="358"/>
<text x="20" y="380" font-size="11" class="dim">tab next · shift+tab prev · enter submit</text>
<text x="620" y="380" text-anchor="end" font-size="11" class="dim">canvas feature enabled</text>
<!-- line 5 (current): let mut area = TextArea::default(); -->
<text x="64" y="108" class="pink">let</text>
<text x="96" y="108" class="pink">mut</text>
<rect x="128" y="96" width="8" height="16" fill="#d7d7db"/>
<text x="128" y="108" class="curfg">a</text>
<text x="136" y="108" class="text">rea</text>
<text x="168" y="108" class="muted">=</text>
<text x="184" y="108" class="gold">TextArea</text>
<text x="248" y="108" class="muted">::</text>
<text x="264" y="108" class="blue">default</text>
<text x="320" y="108" class="muted">()</text>
<text x="336" y="108" class="muted">;</text>
<!-- line 6: area.set_placeholder("Type here…"); -->
<text x="64" y="124" class="text">area</text>
<text x="96" y="124" class="muted">.</text>
<text x="104" y="124" class="blue">set_placeholder</text>
<text x="224" y="124" class="muted">(</text>
<text x="232" y="124" class="green">"Type here…"</text>
<text x="328" y="124" class="muted">)</text>
<text x="336" y="124" class="muted">;</text>
<!-- line 8: Page::new(title) -->
<text x="64" y="156" class="gold">Page</text>
<text x="96" y="156" class="muted">::</text>
<text x="112" y="156" class="blue">new</text>
<text x="136" y="156" class="muted">(</text>
<text x="144" y="156" class="text">title</text>
<text x="184" y="156" class="muted">)</text>
<!-- line 9: .child(area) -->
<text x="96" y="172" class="muted">.</text>
<text x="104" y="172" class="blue">child</text>
<text x="144" y="172" class="muted">(</text>
<text x="152" y="172" class="text">area</text>
<text x="184" y="172" class="muted">)</text>
<!-- line 10: .on_key('q', |app| app.quit()) -->
<text x="96" y="188" class="muted">.</text>
<text x="104" y="188" class="blue">on_key</text>
<text x="152" y="188" class="muted">(</text>
<text x="160" y="188" class="green">'q'</text>
<text x="184" y="188" class="muted">,</text>
<text x="200" y="188" class="muted">|</text>
<text x="208" y="188" class="text">app</text>
<text x="232" y="188" class="muted">|</text>
<text x="248" y="188" class="text">app</text>
<text x="272" y="188" class="muted">.</text>
<text x="280" y="188" class="blue">quit</text>
<text x="312" y="188" class="muted">())</text>
<!-- line 11: } -->
<text x="32" y="204" class="muted">}</text>
<!-- status line -->
<text x="32" y="380" class="green b">NOR</text>
<text x="120" y="380" class="muted">main.rs</text>
<text x="256" y="380" class="muted">Ln 5, Col 18</text>
<text x="632" y="380" class="gold" text-anchor="end">tui-pages v0.7.2 │ 60 FPS</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@@ -0,0 +1,80 @@
<svg viewBox="0 0 640 400" xmlns="http://www.w3.org/2000/svg" class="w-full h-auto" role="img" aria-label="A register screen built with tui-pages: tab bar, rounded panel, and first-class role autocomplete">
<!-- Light-mode twin of terminal-default.svg. Same 80x25 grid, light neutral palette. -->
<style>
.text { fill: #26272b; }
.muted { fill: #5a5a62; }
.dim { fill: #8a8a90; }
.ghost { fill: #9a9aa2; }
.blue { fill: #1f7fb8; }
.gold { fill: #a8862a; }
.green { fill: #1f9d3f; }
.peachfg{ fill: #2a1c08; }
.greenfg{ fill: #f2fff2; }
.b { font-weight: 700; }
text {
font-family: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
font-size: 13px;
text-rendering: geometricPrecision;
}
</style>
<g xml:space="preserve">
<rect x="0.5" y="0.5" width="639" height="399" rx="10" fill="#f4f4f2" stroke="#d8d8d2"/>
<text x="8" y="16" class="muted">Login</text>
<rect x="56" y="2" width="80" height="20" class="green"/>
<text x="64" y="16" class="greenfg b">Register</text>
<text x="144" y="16" class="muted">Admin_Panel</text>
<text x="248" y="16" class="muted">Quit</text>
<text x="168" y="60" class="blue b" textLength="304" lengthAdjust="spacing">╭─ Register ─────────────────────────╮</text>
<text x="168" y="76" class="blue"></text><text x="464" y="76" class="blue"></text>
<text x="168" y="92" class="blue"></text><text x="464" y="92" class="blue"></text>
<text x="168" y="108" class="blue"></text><text x="464" y="108" class="blue"></text>
<text x="168" y="124" class="blue"></text><text x="464" y="124" class="blue"></text>
<text x="168" y="140" class="blue"></text><text x="464" y="140" class="blue"></text>
<text x="168" y="156" class="blue"></text><text x="464" y="156" class="blue"></text>
<text x="168" y="172" class="blue"></text><text x="464" y="172" class="blue"></text>
<text x="168" y="188" class="blue"></text><text x="464" y="188" class="blue"></text>
<text x="168" y="204" class="blue"></text><text x="464" y="204" class="blue"></text>
<text x="168" y="220" class="blue"></text><text x="464" y="220" class="blue"></text>
<text x="168" y="236" class="blue"></text><text x="464" y="236" class="blue"></text>
<text x="168" y="252" class="blue"></text><text x="464" y="252" class="blue"></text>
<text x="168" y="268" class="blue"></text><text x="464" y="268" class="blue"></text>
<text x="168" y="284" class="blue"></text><text x="464" y="284" class="blue"></text>
<text x="168" y="300" class="blue"></text><text x="464" y="300" class="blue"></text>
<text x="168" y="316" class="blue"></text><text x="464" y="316" class="blue"></text>
<text x="168" y="332" class="blue"></text><text x="464" y="332" class="blue"></text>
<text x="168" y="348" class="blue" textLength="304" lengthAdjust="spacing">╰────────────────────────────────────╯</text>
<text x="184" y="92" class="muted">Create your account</text>
<text x="184" y="124" class="muted">Email</text>
<text x="280" y="124" class="text">ada@acme.io</text>
<text x="184" y="156" class="muted">Password</text>
<text x="280" y="156" class="muted">••••••••••</text>
<text x="184" y="188" class="muted">Confirm</text>
<text x="280" y="188" class="muted">••••••••••</text>
<text x="184" y="220" class="muted">Role</text>
<text x="280" y="220" class="text">a</text>
<rect x="288" y="208" width="2" height="15" fill="#c98a2a"/>
<text x="288" y="220" class="ghost">dmin</text>
<rect x="280" y="224" width="96" height="32" fill="#ffffff"/>
<rect x="280" y="224" width="96" height="16" fill="#f0c27a"/>
<text x="280" y="236" class="peachfg b">admin</text>
<text x="280" y="252" class="text">accountant</text>
<text x="184" y="300" class="green b" textLength="144" lengthAdjust="spacing">╭────────────────╮</text>
<text x="184" y="316" class="green b" textLength="144" lengthAdjust="spacing">│ Create account │</text>
<text x="184" y="332" class="green b" textLength="144" lengthAdjust="spacing">╰────────────────╯</text>
<text x="360" y="316" class="dim">enter ↵</text>
<text x="32" y="380" class="green b">INS</text>
<text x="72" y="380" class="muted">[+]</text>
<text x="632" y="380" class="gold" text-anchor="end">tui-pages v0.7.2 │ 60 FPS</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@@ -1,57 +1,93 @@
<svg viewBox="0 0 640 400" xmlns="http://www.w3.org/2000/svg" class="w-full h-auto" role="img" aria-label="examples/default terminal screenshot">
<svg viewBox="0 0 640 400" xmlns="http://www.w3.org/2000/svg" class="w-full h-auto" role="img" aria-label="A register screen built with tui-pages: tab bar, rounded panel, and first-class role autocomplete">
<!--
tui-pages UX showcase on a strict 80x25 monospace grid (cell = 8x16 px).
Each cell carries at most two colors (fg + bg), like a real terminal buffer.
Frames use rounded box-drawing chars; fills/highlights are grid-snapped rects.
-->
<style>
.bg { fill: transparent; stroke: #3f3f46; stroke-width: 1; }
.chrome { fill: transparent; }
.dot { fill: #52525b; }
.sep { stroke: #3f3f46; stroke-width: 1; }
.tab { fill: transparent; }
text { font-family: ui-monospace, 'JetBrains Mono', 'SF Mono', Menlo, Consolas, monospace; fill: #f4f4f5; }
.t-md { font-size: 15px; }
.t-sm { font-size: 13px; }
.t-xs { font-size: 11px; }
.muted { fill: #a1a1aa; }
.dim { fill: #71717a; }
.sel-bg { fill: #b7410e; fill-opacity: 0.85; }
.sel-fg { fill: #fff5f0; }
.text { fill: #d7d7db; }
.muted { fill: #9a9aa2; }
.dim { fill: #6b6b72; }
.ghost { fill: #6b6b72; }
.blue { fill: #3ba7e0; }
.gold { fill: #d9b54a; }
.green { fill: #46d160; }
.peachfg{ fill: #1a1206; }
.greenfg{ fill: #0c130c; }
.b { font-weight: 700; }
text {
font-family: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
font-size: 13px;
text-rendering: geometricPrecision;
}
</style>
<rect class="bg" width="640" height="400" rx="12"/>
<rect class="chrome" width="640" height="36" rx="12"/>
<rect class="chrome" y="24" width="640" height="12"/>
<line class="sep" x1="0" y1="36" x2="640" y2="36"/>
<g xml:space="preserve">
<!-- ===== terminal frame ===== -->
<rect x="0.5" y="0.5" width="639" height="399" rx="10" fill="#1a1b1e" stroke="#2a2b30"/>
<circle class="dot" cx="20" cy="18" r="5.5"/>
<circle class="dot" cx="40" cy="18" r="5.5"/>
<circle class="dot" cx="60" cy="18" r="5.5"/>
<!-- ===== tab bar ===== -->
<text x="8" y="16" class="muted">Login</text>
<rect x="56" y="2" width="80" height="20" class="green"/>
<text x="64" y="16" class="greenfg b">Register</text>
<text x="144" y="16" class="muted">Admin_Panel</text>
<text x="248" y="16" class="muted">Quit</text>
<text x="320" y="22" text-anchor="middle" font-size="11" class="dim">examples/default — cargo run</text>
<!-- ===== Register panel (cols 21..58, rows 3..21) ===== -->
<text x="168" y="60" class="blue b" textLength="304" lengthAdjust="spacing">╭─ Register ─────────────────────────╮</text>
<text x="168" y="76" class="blue"></text><text x="464" y="76" class="blue"></text>
<text x="168" y="92" class="blue"></text><text x="464" y="92" class="blue"></text>
<text x="168" y="108" class="blue"></text><text x="464" y="108" class="blue"></text>
<text x="168" y="124" class="blue"></text><text x="464" y="124" class="blue"></text>
<text x="168" y="140" class="blue"></text><text x="464" y="140" class="blue"></text>
<text x="168" y="156" class="blue"></text><text x="464" y="156" class="blue"></text>
<text x="168" y="172" class="blue"></text><text x="464" y="172" class="blue"></text>
<text x="168" y="188" class="blue"></text><text x="464" y="188" class="blue"></text>
<text x="168" y="204" class="blue"></text><text x="464" y="204" class="blue"></text>
<text x="168" y="220" class="blue"></text><text x="464" y="220" class="blue"></text>
<text x="168" y="236" class="blue"></text><text x="464" y="236" class="blue"></text>
<text x="168" y="252" class="blue"></text><text x="464" y="252" class="blue"></text>
<text x="168" y="268" class="blue"></text><text x="464" y="268" class="blue"></text>
<text x="168" y="284" class="blue"></text><text x="464" y="284" class="blue"></text>
<text x="168" y="300" class="blue"></text><text x="464" y="300" class="blue"></text>
<text x="168" y="316" class="blue"></text><text x="464" y="316" class="blue"></text>
<text x="168" y="332" class="blue"></text><text x="464" y="332" class="blue"></text>
<text x="168" y="348" class="blue" textLength="304" lengthAdjust="spacing">╰────────────────────────────────────╯</text>
<text x="20" y="68" font-size="14" class="muted">Pages:</text>
<rect class="sel-bg" x="80" y="55" width="60" height="20" rx="3"/>
<text x="110" y="69" text-anchor="middle" font-size="12" class="sel-fg" font-weight="600">Home</text>
<text x="150" y="69" font-size="12" class="muted">Settings</text>
<text x="220" y="69" font-size="12" class="muted">About</text>
<text x="270" y="69" font-size="12" class="muted">Quit</text>
<!-- subtitle -->
<text x="184" y="92" class="muted">Create your account</text>
<line class="sep" x1="0" y1="92" x2="640" y2="92"/>
<!-- fields: label col 23, value col 35 -->
<text x="184" y="124" class="muted">Email</text>
<text x="280" y="124" class="text">ada@acme.io</text>
<text x="20" y="120" font-size="18" font-weight="700">Home</text>
<text x="20" y="142" font-size="11" class="dim">Choose a section to open.</text>
<text x="184" y="156" class="muted">Password</text>
<text x="280" y="156" class="muted">••••••••••</text>
<line class="sep" x1="0" y1="160" x2="640" y2="160"/>
<text x="184" y="188" class="muted">Confirm</text>
<text x="280" y="188" class="muted">••••••••••</text>
<g font-size="14">
<rect class="sel-bg" x="0" y="170" width="640" height="34"/>
<text x="32" y="192" class="sel-fg" font-weight="600">▸ Dashboard</text>
<text x="600" y="192" text-anchor="end" class="sel-fg" font-size="11">enter</text>
<!-- role: typed prefix white, block cursor, ghost completion gray -->
<text x="184" y="220" class="muted">Role</text>
<text x="280" y="220" class="text">a</text>
<rect x="288" y="208" width="2" height="15" fill="#f3c690"/>
<text x="288" y="220" class="ghost">dmin</text>
<text x="32" y="226" class="muted"> Accounts</text>
<text x="32" y="254" class="muted"> Transactions</text>
<text x="32" y="282" class="muted"> Reports</text>
<text x="32" y="310" class="muted"> Settings</text>
<!-- role dropdown: matches typed "a"; no border, no left pad -->
<rect x="280" y="224" width="96" height="32" fill="#111217"/>
<rect x="280" y="224" width="96" height="16" fill="#f3c690"/>
<text x="280" y="236" class="peachfg b">admin</text>
<text x="280" y="252" class="text">accountant</text>
<!-- primary button (bordered, green) -->
<text x="184" y="300" class="green b" textLength="144" lengthAdjust="spacing">╭────────────────╮</text>
<text x="184" y="316" class="green b" textLength="144" lengthAdjust="spacing">│ Create account │</text>
<text x="184" y="332" class="green b" textLength="144" lengthAdjust="spacing">╰────────────────╯</text>
<text x="360" y="316" class="dim">enter ↵</text>
<!-- ===== footer ===== -->
<text x="32" y="380" class="green b">INS</text>
<text x="72" y="380" class="muted">[+]</text>
<text x="632" y="380" class="gold" text-anchor="end">tui-pages v0.7.2 │ 60 FPS</text>
</g>
<line class="sep" x1="0" y1="358" x2="640" y2="358"/>
<text x="20" y="380" font-size="11" class="dim">↑↓ move · enter select · q quit</text>
<text x="620" y="380" text-anchor="end" font-size="11" class="dim">tui-pages v0.7.2</text>
</svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@@ -0,0 +1,73 @@
<svg viewBox="0 0 640 400" xmlns="http://www.w3.org/2000/svg" class="w-full h-auto" role="img" aria-label="A keybindings help screen built with tui-pages">
<!-- Light-mode twin of terminal-keybindings.svg. Same 80x25 grid, light neutral palette. -->
<style>
.text { fill: #26272b; }
.muted { fill: #5a5a62; }
.dim { fill: #8a8a90; }
.blue { fill: #1f7fb8; }
.gold { fill: #a8862a; }
.green { fill: #1f9d3f; }
.greenfg{ fill: #f2fff2; }
.b { font-weight: 700; }
text {
font-family: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
font-size: 13px;
text-rendering: geometricPrecision;
}
</style>
<g xml:space="preserve">
<rect x="0.5" y="0.5" width="639" height="399" rx="10" fill="#f4f4f2" stroke="#d8d8d2"/>
<rect x="0" y="2" width="56" height="20" class="green"/>
<text x="8" y="16" class="greenfg b">Login</text>
<text x="64" y="16" class="muted">Register</text>
<text x="144" y="16" class="muted">Admin_Panel</text>
<text x="248" y="16" class="muted">Quit</text>
<text x="168" y="60" class="blue b" textLength="304" lengthAdjust="spacing">╭─ Keybindings ──────────────────────╮</text>
<text x="168" y="76" class="blue"></text><text x="464" y="76" class="blue"></text>
<text x="168" y="92" class="blue"></text><text x="464" y="92" class="blue"></text>
<text x="168" y="108" class="blue"></text><text x="464" y="108" class="blue"></text>
<text x="168" y="124" class="blue"></text><text x="464" y="124" class="blue"></text>
<text x="168" y="140" class="blue"></text><text x="464" y="140" class="blue"></text>
<text x="168" y="156" class="blue"></text><text x="464" y="156" class="blue"></text>
<text x="168" y="172" class="blue"></text><text x="464" y="172" class="blue"></text>
<text x="168" y="188" class="blue"></text><text x="464" y="188" class="blue"></text>
<text x="168" y="204" class="blue"></text><text x="464" y="204" class="blue"></text>
<text x="168" y="220" class="blue"></text><text x="464" y="220" class="blue"></text>
<text x="168" y="236" class="blue"></text><text x="464" y="236" class="blue"></text>
<text x="168" y="252" class="blue"></text><text x="464" y="252" class="blue"></text>
<text x="168" y="268" class="blue"></text><text x="464" y="268" class="blue"></text>
<text x="168" y="284" class="blue"></text><text x="464" y="284" class="blue"></text>
<text x="168" y="300" class="blue"></text><text x="464" y="300" class="blue"></text>
<text x="168" y="316" class="blue"></text><text x="464" y="316" class="blue"></text>
<text x="168" y="332" class="blue"></text><text x="464" y="332" class="blue"></text>
<text x="168" y="348" class="blue" textLength="304" lengthAdjust="spacing">╰────────────────────────────────────╯</text>
<text x="184" y="92" class="gold b">MOVEMENT</text>
<text x="200" y="108" class="text">j / k</text>
<text x="304" y="108" class="muted">move down / up</text>
<text x="200" y="124" class="text">gg / G</text>
<text x="304" y="124" class="muted">jump to top / bottom</text>
<text x="184" y="156" class="gold b">ACTIONS</text>
<text x="200" y="172" class="text">enter</text>
<text x="304" y="172" class="muted">select / open</text>
<text x="200" y="188" class="text">/</text>
<text x="304" y="188" class="muted">search</text>
<text x="200" y="204" class="text">space</text>
<text x="304" y="204" class="muted">toggle mark</text>
<text x="184" y="236" class="gold b">APP</text>
<text x="200" y="252" class="text">?</text>
<text x="304" y="252" class="muted">toggle this help</text>
<text x="200" y="268" class="text">:q</text>
<text x="304" y="268" class="muted">quit</text>
<text x="184" y="316" class="dim">press ? or esc to close</text>
<text x="32" y="380" class="green b">NOR</text>
<text x="632" y="380" class="gold" text-anchor="end">tui-pages v0.7.2 │ 60 FPS</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -1,71 +1,82 @@
<svg viewBox="0 0 640 400" xmlns="http://www.w3.org/2000/svg" class="w-full h-auto" role="img" aria-label="examples/keybindings terminal screenshot">
<svg viewBox="0 0 640 400" xmlns="http://www.w3.org/2000/svg" class="w-full h-auto" role="img" aria-label="A keybindings help screen built with tui-pages">
<!--
tui-pages UX showcase on a strict 80x25 monospace grid (cell = 8x16 px).
Each cell carries at most two colors (fg + bg), like a real terminal buffer.
-->
<style>
.bg { fill: #18181b; }
.chrome { fill: #27272a; }
.dot { fill: #52525b; }
.kbd { fill: #27272a; stroke: #3f3f46; stroke-width: 1; }
.modal { fill: #1f1f23; stroke: #b7410e; stroke-width: 2; }
.sep { stroke: #27272a; stroke-width: 1; }
text { font-family: ui-monospace, 'JetBrains Mono', 'SF Mono', Menlo, Consolas, monospace; fill: #f4f4f5; }
.t-sm { font-size: 12px; }
.t-xs { font-size: 11px; }
.muted { fill: #a1a1aa; }
.dim { fill: #71717a; }
.text { fill: #d7d7db; }
.muted { fill: #9a9aa2; }
.dim { fill: #6b6b72; }
.blue { fill: #3ba7e0; }
.gold { fill: #d9b54a; }
.green { fill: #46d160; }
.greenfg{ fill: #0c130c; }
.b { font-weight: 700; }
text {
font-family: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
font-size: 13px;
text-rendering: geometricPrecision;
}
</style>
<rect class="bg" width="640" height="400" rx="12"/>
<rect class="chrome" width="640" height="36" rx="12"/>
<rect class="chrome" y="24" width="640" height="12"/>
<line class="sep" x1="0" y1="36" x2="640" y2="36"/>
<g xml:space="preserve">
<rect x="0.5" y="0.5" width="639" height="399" rx="10" fill="#1a1b1e" stroke="#2a2b30"/>
<circle class="dot" cx="20" cy="18" r="5.5"/>
<circle class="dot" cx="40" cy="18" r="5.5"/>
<circle class="dot" cx="60" cy="18" r="5.5"/>
<!-- tab bar (Login active) -->
<rect x="0" y="2" width="56" height="20" class="green"/>
<text x="8" y="16" class="greenfg b">Login</text>
<text x="64" y="16" class="muted">Register</text>
<text x="144" y="16" class="muted">Admin_Panel</text>
<text x="248" y="16" class="muted">Quit</text>
<text x="320" y="22" text-anchor="middle" font-size="11" class="dim">examples/keybindings — modal open</text>
<!-- panel -->
<text x="168" y="60" class="blue b" textLength="304" lengthAdjust="spacing">╭─ Keybindings ──────────────────────╮</text>
<text x="168" y="76" class="blue"></text><text x="464" y="76" class="blue"></text>
<text x="168" y="92" class="blue"></text><text x="464" y="92" class="blue"></text>
<text x="168" y="108" class="blue"></text><text x="464" y="108" class="blue"></text>
<text x="168" y="124" class="blue"></text><text x="464" y="124" class="blue"></text>
<text x="168" y="140" class="blue"></text><text x="464" y="140" class="blue"></text>
<text x="168" y="156" class="blue"></text><text x="464" y="156" class="blue"></text>
<text x="168" y="172" class="blue"></text><text x="464" y="172" class="blue"></text>
<text x="168" y="188" class="blue"></text><text x="464" y="188" class="blue"></text>
<text x="168" y="204" class="blue"></text><text x="464" y="204" class="blue"></text>
<text x="168" y="220" class="blue"></text><text x="464" y="220" class="blue"></text>
<text x="168" y="236" class="blue"></text><text x="464" y="236" class="blue"></text>
<text x="168" y="252" class="blue"></text><text x="464" y="252" class="blue"></text>
<text x="168" y="268" class="blue"></text><text x="464" y="268" class="blue"></text>
<text x="168" y="284" class="blue"></text><text x="464" y="284" class="blue"></text>
<text x="168" y="300" class="blue"></text><text x="464" y="300" class="blue"></text>
<text x="168" y="316" class="blue"></text><text x="464" y="316" class="blue"></text>
<text x="168" y="332" class="blue"></text><text x="464" y="332" class="blue"></text>
<text x="168" y="348" class="blue" textLength="304" lengthAdjust="spacing">╰────────────────────────────────────╯</text>
<!-- dimmed background content -->
<text x="40" y="80" font-size="14" class="dim">▸ Accounts</text>
<text x="40" y="108" font-size="14" class="dim"> Transactions</text>
<text x="40" y="136" font-size="14" class="dim"> Reports</text>
<text x="40" y="164" font-size="14" class="dim"> Settings</text>
<text x="40" y="320" font-size="11" class="dim">Press ? for help</text>
<!-- MOVEMENT -->
<text x="184" y="92" class="gold b">MOVEMENT</text>
<text x="200" y="108" class="text">j / k</text>
<text x="304" y="108" class="muted">move down / up</text>
<text x="200" y="124" class="text">gg / G</text>
<text x="304" y="124" class="muted">jump to top / bottom</text>
<!-- modal -->
<rect class="modal" x="120" y="60" width="400" height="280" rx="10"/>
<text x="140" y="94" font-size="14" font-weight="700">Keybindings</text>
<line class="sep" x1="140" y1="104" x2="500" y2="104"/>
<!-- ACTIONS -->
<text x="184" y="156" class="gold b">ACTIONS</text>
<text x="200" y="172" class="text">enter</text>
<text x="304" y="172" class="muted">select / open</text>
<text x="200" y="188" class="text">/</text>
<text x="304" y="188" class="muted">search</text>
<text x="200" y="204" class="text">space</text>
<text x="304" y="204" class="muted">toggle mark</text>
<text x="140" y="130" font-size="11" class="muted">MOVEMENT</text>
<rect class="kbd" x="140" y="140" width="34" height="24" rx="4"/>
<text x="157" y="157" text-anchor="middle" font-size="12">j</text>
<text x="184" y="157" font-size="12" class="muted">move down</text>
<!-- APP -->
<text x="184" y="236" class="gold b">APP</text>
<text x="200" y="252" class="text">?</text>
<text x="304" y="252" class="muted">toggle this help</text>
<text x="200" y="268" class="text">:q</text>
<text x="304" y="268" class="muted">quit</text>
<rect class="kbd" x="140" y="170" width="34" height="24" rx="4"/>
<text x="157" y="187" text-anchor="middle" font-size="12">k</text>
<text x="184" y="187" font-size="12" class="muted">move up</text>
<text x="184" y="316" class="dim">press ? or esc to close</text>
<rect class="kbd" x="140" y="200" width="34" height="24" rx="4"/>
<text x="157" y="217" text-anchor="middle" font-size="12">gg</text>
<text x="184" y="217" font-size="12" class="muted">top of list</text>
<text x="290" y="130" font-size="11" class="muted">ACTIONS</text>
<rect class="kbd" x="290" y="140" width="60" height="24" rx="4"/>
<text x="320" y="157" text-anchor="middle" font-size="11">enter</text>
<text x="360" y="157" font-size="12" class="muted">select</text>
<rect class="kbd" x="290" y="170" width="34" height="24" rx="4"/>
<text x="307" y="187" text-anchor="middle" font-size="11">/</text>
<text x="334" y="187" font-size="12" class="muted">search</text>
<rect class="kbd" x="290" y="200" width="60" height="24" rx="4"/>
<text x="320" y="217" text-anchor="middle" font-size="11">ctrl+s</text>
<text x="360" y="217" font-size="12" class="muted">save</text>
<line class="sep" x1="140" y1="300" x2="500" y2="300"/>
<text x="320" y="322" text-anchor="middle" font-size="11" class="dim">press esc to close</text>
<line class="sep" x1="0" y1="358" x2="640" y2="358"/>
<text x="20" y="380" font-size="11" class="dim">esc close · ? toggle this dialog</text>
<text x="620" y="380" text-anchor="end" font-size="11" class="dim">dialog feature enabled</text>
<!-- footer -->
<text x="32" y="380" class="green b">NOR</text>
<text x="632" y="380" class="gold" text-anchor="end">tui-pages v0.7.2 │ 60 FPS</text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

File diff suppressed because it is too large Load Diff