run-what 1.3.0

HTML-first web framework powered by Rust. No JavaScript frameworks, no build steps—just HTML.
<what>
title: "Step 5 — Sessions & State"
active_step: 5
</what>

<h1 class="text-3xl font-bold mb-2" style="color: #111827; letter-spacing: -0.02em;">Step 5 — Sessions &amp; State</h1>
<p class="text-gray-500 text-sm mb-8">Server-side state that persists, mutated from HTML attributes.</p>

<section class="mb-8">
  <h2 class="text-lg font-semibold mb-3" style="color: #111827;">How it works</h2>
  <p class="text-gray-600 mb-4" style="line-height: 1.7;">
    Sessions are stored server-side in SQLite. Every browser gets a unique session. The <code>w-set</code> attribute on any HTML element mutates session data when clicked or changed. No JavaScript. No API routes.
  </p>
  <pre class="bg-gray-50 p-4 rounded text-sm font-mono" style="border: 1px solid #e5e7eb; overflow-x: auto;"><code>&lt;button w-set="session.counter += 1"&gt;+1&lt;/button&gt;
&lt;span&gt;#session.counter#&lt;/span&gt;</code></pre>
</section>

<section class="mb-8">
  <h2 class="text-lg font-semibold mb-3" style="color: #111827;">Interactive counter</h2>
  <p class="text-gray-600 mb-3" style="line-height: 1.7;">
    This counter is stored in your session. Reload the page — the value persists.
  </p>
  <div class="card mb-4">
    <div class="card-body">
      <div class="flex items-center gap-4 mb-2">
        <div class="text-4xl font-bold" style="color: #6366f1; min-width: 3rem; text-align: center;">#session.tut_counter|default:"0"#</div>
        <div class="flex gap-2">
          <button class="btn btn-primary" w-set="session.tut_counter += 1">+1</button>
          <button class="btn btn-outline" w-set="session.tut_counter -= 1">-1</button>
          <button class="btn btn-outline" w-set="session.tut_counter = 0">Reset</button>
        </div>
      </div>
      <p class="text-sm text-gray-500">Reload the page. The number will still be there.</p>
    </div>
  </div>
  <pre class="bg-gray-50 p-4 rounded text-sm font-mono" style="border: 1px solid #e5e7eb; overflow-x: auto;"><code>&lt;div&gt;#session.tut_counter|default:"0"#&lt;/div&gt;
&lt;button w-set="session.tut_counter += 1"&gt;+1&lt;/button&gt;
&lt;button w-set="session.tut_counter -= 1"&gt;-1&lt;/button&gt;
&lt;button w-set="session.tut_counter = 0"&gt;Reset&lt;/button&gt;</code></pre>
</section>

<section class="mb-8">
  <h2 class="text-lg font-semibold mb-3" style="color: #111827;">Toggle demo</h2>
  <p class="text-gray-600 mb-3" style="line-height: 1.7;">
    Booleans toggle with the <code>toggle</code> operator.
  </p>
  <div class="card mb-4">
    <div class="card-body">
      <div class="flex items-center gap-4">
        <button class="btn btn-outline" w-set="session.tut_toggle = toggle">
          <if session.tut_toggle>ON</if>
          <unless session.tut_toggle>OFF</unless>
        </button>
        <span class="text-sm text-gray-500">
          Status: <strong>
            <if session.tut_toggle>active</if>
            <unless session.tut_toggle>inactive</unless>
          </strong>
        </span>
      </div>
    </div>
  </div>
  <pre class="bg-gray-50 p-4 rounded text-sm font-mono" style="border: 1px solid #e5e7eb; overflow-x: auto;"><code>&lt;button w-set="session.tut_toggle = toggle"&gt;
  &lt;if session.tut_toggle&gt;ON&lt;/if&gt;
  &lt;unless session.tut_toggle&gt;OFF&lt;/unless&gt;
&lt;/button&gt;</code></pre>
</section>

<section class="mb-8">
  <h2 class="text-lg font-semibold mb-3" style="color: #111827;">Mutation patterns</h2>
  <div class="card">
    <div class="card-body">
      <table style="width: 100%; border-collapse: collapse; font-size: 0.875rem;">
        <thead>
          <tr style="border-bottom: 1px solid #e5e7eb;">
            <th style="text-align: left; padding: 0.5rem 0.75rem; color: #6b7280; font-weight: 600;">Pattern</th>
            <th style="text-align: left; padding: 0.5rem 0.75rem; color: #6b7280; font-weight: 600;">Effect</th>
          </tr>
        </thead>
        <tbody>
          <tr style="border-bottom: 1px solid #f3f4f6;">
            <td style="padding: 0.5rem 0.75rem;"><code>session.n += 1</code></td>
            <td style="padding: 0.5rem 0.75rem; color: #6b7280;">Increment by 1</td>
          </tr>
          <tr style="border-bottom: 1px solid #f3f4f6;">
            <td style="padding: 0.5rem 0.75rem;"><code>session.n -= 5</code></td>
            <td style="padding: 0.5rem 0.75rem; color: #6b7280;">Decrement by 5</td>
          </tr>
          <tr style="border-bottom: 1px solid #f3f4f6;">
            <td style="padding: 0.5rem 0.75rem;"><code>session.x = "hello"</code></td>
            <td style="padding: 0.5rem 0.75rem; color: #6b7280;">Set a string value</td>
          </tr>
          <tr style="border-bottom: 1px solid #f3f4f6;">
            <td style="padding: 0.5rem 0.75rem;"><code>session.flag = toggle</code></td>
            <td style="padding: 0.5rem 0.75rem; color: #6b7280;">Toggle boolean</td>
          </tr>
          <tr>
            <td style="padding: 0.5rem 0.75rem;"><code>session.x = $value</code></td>
            <td style="padding: 0.5rem 0.75rem; color: #6b7280;">Set from input field value</td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
</section>

<section class="mb-8">
  <h2 class="text-lg font-semibold mb-3" style="color: #111827;">Application-wide state</h2>
  <p class="text-gray-600 mb-3" style="line-height: 1.7;">
    Use <code>app.*</code> instead of <code>session.*</code> for state shared across all users. Use <code>wired.*</code> for real-time state pushed to all connected browsers via WebSocket.
  </p>
  <pre class="bg-gray-50 p-4 rounded text-sm font-mono" style="border: 1px solid #e5e7eb; overflow-x: auto;"><code>session.*   &lt;!-- Per-user, persists across reloads --&gt;
app.*       &lt;!-- Shared across all users --&gt;
wired.*     &lt;!-- Shared + real-time WebSocket push --&gt;</code></pre>
</section>

<div class="card" style="border-color: #bbf7d0; background: #f0fdf4;">
  <div class="card-body">
    <div class="text-sm font-semibold mb-2" style="color: #14532d;">What you learned</div>
    <ul class="text-sm space-y-1" style="color: #166534; padding-left: 1.25rem; list-style: disc;">
      <li><code>w-set</code> on any element mutates server state when clicked or changed</li>
      <li><code>session.*</code> is per-user and persists across page reloads</li>
      <li>Mutations: <code>+= 1</code>, <code>-= N</code>, <code>= "value"</code>, <code>= $value</code>, <code>= toggle</code></li>
      <li>Multiple mutations: <code>w-set="session.a += 1; session.b = 'ok'"</code></li>
      <li><code>app.*</code> is shared across all users; <code>wired.*</code> pushes real-time via WebSocket</li>
    </ul>
  </div>
</div>