From 64d16441a390e889231f2f67333d5f305b7ab878 Mon Sep 17 00:00:00 2001
From: Owen Jacobson <owen@grimoire.ca>
Date: Tue, 8 Jul 2025 01:44:46 -0400
Subject: Set up a skeleton for swatches.

A swatch is a live, and ideally editable, example of an element of the service. They serve as:

* Documentation: what is this element, how do you use it, what does it do?
* Demonstration: what does this element look like?
* Manual test scaffolding: when I change this element like _so_, what happens?

Swatches are collectively available under `/.swatch/` on a running instance, and are set up in a separate [group] from the rest of the UI. They do not require setup or login for simplicity's sake and because they don't _do_ anything that requires either of those things.

[group]: https://svelte.dev/docs/kit/advanced-routing#Advanced-layouts-(group)

Swatches are manually curated, for a couple of reasons:

* We lack the technical infrastructure needed to do this based on static analysis; and
* Manual curation lets us include affordances like "recommended values," that would be tricky to express as part of the type or schema for the component.

The tradeoff, however, is that swatches may fall out of step with the components they depic, if not reviewed regularly. I hope that, by making them part of the development process, this risk will be mitigated through regular use.
---
 ui/routes/(swatch)/.swatch/+page.svelte | 10 ++++++++++
 1 file changed, 10 insertions(+)
 create mode 100644 ui/routes/(swatch)/.swatch/+page.svelte

(limited to 'ui/routes/(swatch)/.swatch/+page.svelte')

diff --git a/ui/routes/(swatch)/.swatch/+page.svelte b/ui/routes/(swatch)/.swatch/+page.svelte
new file mode 100644
index 0000000..8d03c8d
--- /dev/null
+++ b/ui/routes/(swatch)/.swatch/+page.svelte
@@ -0,0 +1,10 @@
+<h1>swatches</h1>
+
+<p>
+  Swatches are "live, but disconnected" elements of the application, designed specifically to
+  support live editing and iteration.
+</p>
+
+<h2>components</h2>
+
+<ul></ul>
-- 
cgit v1.2.3


From c631c8fc855b1854f14fc7fbf1d8afedaa37a0db Mon Sep 17 00:00:00 2001
From: Owen Jacobson <owen@grimoire.ca>
Date: Tue, 8 Jul 2025 01:35:28 -0400
Subject: Event capture and display tools.

This is meant to be used in swatches, to display the events and callbacks generated by a component as part of the swatch. The usage pattern is described in the comments (in both places).

Naturally, this has its own swatch.
---
 ui/lib/components/swatch/EventLog.svelte           | 37 +++++++++++++++++++++
 ui/lib/swatch/event-capture.svelte.js              | 22 +++++++++++++
 ui/routes/(swatch)/.swatch/+page.svelte            |  4 ++-
 .../(swatch)/.swatch/swatch/EventLog/+page.svelte  | 38 ++++++++++++++++++++++
 4 files changed, 100 insertions(+), 1 deletion(-)
 create mode 100644 ui/lib/components/swatch/EventLog.svelte
 create mode 100644 ui/lib/swatch/event-capture.svelte.js
 create mode 100644 ui/routes/(swatch)/.swatch/swatch/EventLog/+page.svelte

(limited to 'ui/routes/(swatch)/.swatch/+page.svelte')

diff --git a/ui/lib/components/swatch/EventLog.svelte b/ui/lib/components/swatch/EventLog.svelte
new file mode 100644
index 0000000..2d8c5c0
--- /dev/null
+++ b/ui/lib/components/swatch/EventLog.svelte
@@ -0,0 +1,37 @@
+<script>
+  /*
+   * The interface exposed by this component is designed to be compatible with the interface
+   * exposed by the `EventCapture` class, so that you can do this:
+   *
+   *    let capture = $state(new EventCapture());
+   *    const someEvent = capture.on('someEvent');
+   *
+   *    // …
+   *
+   *    <EventLog events={capture.events} clear={capture.clear.bind(capture)} />
+   */
+
+  let { events, clear = () => {} } = $props();
+
+  function onclick() {
+    clear();
+  }
+</script>
+
+<button {onclick}>clear</button>
+<table>
+  <thead>
+    <tr>
+      <th>event</th>
+      <th>arguments</th>
+    </tr>
+  </thead>
+  <tbody>
+    {#each events as { event, args }}
+      <tr>
+        <td>{event}</td>
+        <td><code>{JSON.stringify(args)}</code></td>
+      </tr>
+    {/each}
+  </tbody>
+</table>
diff --git a/ui/lib/swatch/event-capture.svelte.js b/ui/lib/swatch/event-capture.svelte.js
new file mode 100644
index 0000000..32c0f39
--- /dev/null
+++ b/ui/lib/swatch/event-capture.svelte.js
@@ -0,0 +1,22 @@
+/*
+ * The interface exposed by this class is designed to closely match the interface expected by
+ * the `EventLog` component, so that you can do this:
+ *
+ *    let capture = $state(new EventCapture());
+ *    const someEvent = capture.on('someEvent');
+ *
+ *    // …
+ *
+ *    <EventLog events={capture.events} clear={capture.clear.bind(capture)} />
+ */
+export default class EventCapture {
+  events = $state([]);
+
+  on(event) {
+    return (...args) => this.events.push({ event, args });
+  }
+
+  clear() {
+    this.events = [];
+  }
+}
diff --git a/ui/routes/(swatch)/.swatch/+page.svelte b/ui/routes/(swatch)/.swatch/+page.svelte
index 8d03c8d..abcb53f 100644
--- a/ui/routes/(swatch)/.swatch/+page.svelte
+++ b/ui/routes/(swatch)/.swatch/+page.svelte
@@ -7,4 +7,6 @@
 
 <h2>components</h2>
 
-<ul></ul>
+<ul>
+  <li><a href="swatch/EventLog">swatch/EventLog</a></li>
+</ul>
diff --git a/ui/routes/(swatch)/.swatch/swatch/EventLog/+page.svelte b/ui/routes/(swatch)/.swatch/swatch/EventLog/+page.svelte
new file mode 100644
index 0000000..a751ca3
--- /dev/null
+++ b/ui/routes/(swatch)/.swatch/swatch/EventLog/+page.svelte
@@ -0,0 +1,38 @@
+<script>
+  import EventCapture from '$lib/swatch/event-capture.svelte.js';
+  import { json } from '$lib/swatch/derive.js';
+
+  import EventLog from '$lib/components/swatch/EventLog.svelte';
+
+  let eventsInput = $state(
+    JSON.stringify(
+      [{ event: 'example', args: ['argument a', 'argument b'] }],
+      /* replacer */ null,
+      /* space */ 2,
+    ),
+  );
+  let events = $derived(json(eventsInput));
+
+  let capture = $state(new EventCapture());
+  const clear = capture.on('clear');
+</script>
+
+<h1><code>swatch/EventLog</code></h1>
+
+<nav><p><a href="..">Back to swatches</a></p></nav>
+
+<h2>properties</h2>
+
+<div class="component-properties">
+  <label>events (json) <textarea bind:value={eventsInput}></textarea></label>
+</div>
+
+<h2>rendered</h2>
+
+<div class="component-preview">
+  <EventLog {events} {clear} />
+</div>
+
+<h2>events</h2>
+
+<EventLog events={capture.events} clear={capture.clear.bind(capture)} />
-- 
cgit v1.2.3


From e7f942dd5b638a351cbff4ae4e4c35aef6aebcac Mon Sep 17 00:00:00 2001
From: Owen Jacobson <owen@grimoire.ca>
Date: Tue, 8 Jul 2025 19:35:26 -0400
Subject: Add a swatch for the `ChangePassword` component.

---
 ui/routes/(swatch)/.swatch/+page.svelte            |  1 +
 .../(swatch)/.swatch/ChangePassword/+page.svelte   | 23 ++++++++++++++++++++++
 2 files changed, 24 insertions(+)
 create mode 100644 ui/routes/(swatch)/.swatch/ChangePassword/+page.svelte

(limited to 'ui/routes/(swatch)/.swatch/+page.svelte')

diff --git a/ui/routes/(swatch)/.swatch/+page.svelte b/ui/routes/(swatch)/.swatch/+page.svelte
index abcb53f..4833bcb 100644
--- a/ui/routes/(swatch)/.swatch/+page.svelte
+++ b/ui/routes/(swatch)/.swatch/+page.svelte
@@ -8,5 +8,6 @@
 <h2>components</h2>
 
 <ul>
+  <li><a href="ChangePassword">ChangePassword</a></li>
   <li><a href="swatch/EventLog">swatch/EventLog</a></li>
 </ul>
diff --git a/ui/routes/(swatch)/.swatch/ChangePassword/+page.svelte b/ui/routes/(swatch)/.swatch/ChangePassword/+page.svelte
new file mode 100644
index 0000000..8ef6792
--- /dev/null
+++ b/ui/routes/(swatch)/.swatch/ChangePassword/+page.svelte
@@ -0,0 +1,23 @@
+<script>
+  import EventCapture from '$lib/swatch/event-capture.svelte.js';
+
+  import ChangePassword from '$lib/components/ChangePassword.svelte';
+  import EventLog from '$lib/components/swatch/EventLog.svelte';
+
+  let capture = $state(new EventCapture());
+  const changePassword = capture.on('changePassword');
+</script>
+
+<h1><code>ChangePassword</code></h1>
+
+<nav><p><a href=".">Back to swatches</a></p></nav>
+
+<h2>rendered</h2>
+
+<div class="component-preview">
+  <ChangePassword {changePassword} />
+</div>
+
+<h2>events</h2>
+
+<EventLog events={capture.events} clear={capture.clear.bind(capture)} />
-- 
cgit v1.2.3


From a2a0ec035f74a454df5a76ed999355f536f5b277 Mon Sep 17 00:00:00 2001
From: Owen Jacobson <owen@grimoire.ca>
Date: Tue, 8 Jul 2025 19:45:49 -0400
Subject: Create a swatch for the `Conversation` component.

---
 ui/routes/(swatch)/.swatch/+page.svelte            |  1 +
 .../(swatch)/.swatch/Conversation/+page.svelte     | 31 ++++++++++++++++++++++
 2 files changed, 32 insertions(+)
 create mode 100644 ui/routes/(swatch)/.swatch/Conversation/+page.svelte

(limited to 'ui/routes/(swatch)/.swatch/+page.svelte')

diff --git a/ui/routes/(swatch)/.swatch/+page.svelte b/ui/routes/(swatch)/.swatch/+page.svelte
index abcb53f..165bbad 100644
--- a/ui/routes/(swatch)/.swatch/+page.svelte
+++ b/ui/routes/(swatch)/.swatch/+page.svelte
@@ -8,5 +8,6 @@
 <h2>components</h2>
 
 <ul>
+  <li><a href="Conversation">Conversation</a></li>
   <li><a href="swatch/EventLog">swatch/EventLog</a></li>
 </ul>
diff --git a/ui/routes/(swatch)/.swatch/Conversation/+page.svelte b/ui/routes/(swatch)/.swatch/Conversation/+page.svelte
new file mode 100644
index 0000000..0b98204
--- /dev/null
+++ b/ui/routes/(swatch)/.swatch/Conversation/+page.svelte
@@ -0,0 +1,31 @@
+<script>
+  import Conversation from '$lib/components/Conversation.svelte';
+
+  let id = $state('Czero');
+  let name = $state('a long conversation');
+  let active = $state(false);
+  let hasUnreads = $state(false);
+</script>
+
+<h1><code>Conversation</code></h1>
+
+<nav><p><a href=".">Back to swatches</a></p></nav>
+
+<h2>properties</h2>
+
+<div class="component-properties">
+  <label>id <input type="text" bind:value={id} /></label>
+  <label>name <input type="text" bind:value={name} /></label>
+  <label>active <input type="checkbox" bind:checked={active} /></label>
+  <label>has unreads <input type="checkbox" bind:checked={hasUnreads} /></label>
+</div>
+
+<h2>rendered</h2>
+
+<div class="component-preview">
+  <nav class="list-nav">
+    <ul>
+      <Conversation {id} {name} {active} {hasUnreads} />
+    </ul>
+  </nav>
+</div>
-- 
cgit v1.2.3


From 3fd175165ee262f0180b78d2dd206a993c20200c Mon Sep 17 00:00:00 2001
From: Owen Jacobson <owen@grimoire.ca>
Date: Mon, 7 Jul 2025 16:11:59 -0400
Subject: Create a swatch for the `ConversationList` component.

---
 ui/routes/(swatch)/.swatch/+page.svelte            |  1 +
 .../(swatch)/.swatch/ConversationList/+page.svelte | 54 ++++++++++++++++++++++
 2 files changed, 55 insertions(+)
 create mode 100644 ui/routes/(swatch)/.swatch/ConversationList/+page.svelte

(limited to 'ui/routes/(swatch)/.swatch/+page.svelte')

diff --git a/ui/routes/(swatch)/.swatch/+page.svelte b/ui/routes/(swatch)/.swatch/+page.svelte
index abcb53f..c8f2133 100644
--- a/ui/routes/(swatch)/.swatch/+page.svelte
+++ b/ui/routes/(swatch)/.swatch/+page.svelte
@@ -8,5 +8,6 @@
 <h2>components</h2>
 
 <ul>
+  <li><a href="ConversationList">ConversationList</a></li>
   <li><a href="swatch/EventLog">swatch/EventLog</a></li>
 </ul>
diff --git a/ui/routes/(swatch)/.swatch/ConversationList/+page.svelte b/ui/routes/(swatch)/.swatch/ConversationList/+page.svelte
new file mode 100644
index 0000000..1a56966
--- /dev/null
+++ b/ui/routes/(swatch)/.swatch/ConversationList/+page.svelte
@@ -0,0 +1,54 @@
+<script>
+  import { json } from '$lib/swatch/derive.js';
+
+  import ConversationList from '$lib/components/ConversationList.svelte';
+
+  let conversationsInput = $state(
+    JSON.stringify(
+      [
+        {
+          id: 'Czero',
+          name: 'A long conversation',
+          hasUnreads: false,
+        },
+        {
+          id: 'Cone',
+          name: 'A shorter conversation',
+          hasUnreads: true,
+        },
+      ],
+      /* replacer */ null,
+      /* space */ 2,
+    ),
+  );
+  let conversations = $derived(json(conversationsInput));
+
+  let active = $state(null);
+</script>
+
+<h1><code>ConversationList</code></h1>
+
+<nav><p><a href=".">Back to swatches</a></p></nav>
+
+<h2>properties</h2>
+
+<div class="component-properties">
+  <label
+    ><p>conversations (json)</p>
+    <textarea class="html" bind:value={conversationsInput}></textarea>
+  </label>
+
+  <label>active <input type="text" bind:value={active} /></label>
+  <div class="suggestion">
+    interesting values:
+    <button onclick={() => (active = null)}>(none)</button>
+    <button onclick={() => (active = 'Czero')}>Czero</button>
+    <button onclick={() => (active = 'Cone')}>Cone</button>
+  </div>
+</div>
+
+<h2>rendered</h2>
+
+<div class="component-preview">
+  <ConversationList {conversations} {active} />
+</div>
-- 
cgit v1.2.3


From ca4a9dfbc2d2339e6f76330026d8fe15be36ee67 Mon Sep 17 00:00:00 2001
From: Owen Jacobson <owen@grimoire.ca>
Date: Tue, 8 Jul 2025 19:52:28 -0400
Subject: Create swatch for the `CreateConversationForm` component.

---
 ui/routes/(swatch)/.swatch/+page.svelte            |  1 +
 .../.swatch/CreateConversationForm/+page.svelte    | 23 ++++++++++++++++++++++
 2 files changed, 24 insertions(+)
 create mode 100644 ui/routes/(swatch)/.swatch/CreateConversationForm/+page.svelte

(limited to 'ui/routes/(swatch)/.swatch/+page.svelte')

diff --git a/ui/routes/(swatch)/.swatch/+page.svelte b/ui/routes/(swatch)/.swatch/+page.svelte
index abcb53f..4ce1762 100644
--- a/ui/routes/(swatch)/.swatch/+page.svelte
+++ b/ui/routes/(swatch)/.swatch/+page.svelte
@@ -8,5 +8,6 @@
 <h2>components</h2>
 
 <ul>
+  <li><a href="CreateConversationForm">CreateConversationForm</a></li>
   <li><a href="swatch/EventLog">swatch/EventLog</a></li>
 </ul>
diff --git a/ui/routes/(swatch)/.swatch/CreateConversationForm/+page.svelte b/ui/routes/(swatch)/.swatch/CreateConversationForm/+page.svelte
new file mode 100644
index 0000000..f089969
--- /dev/null
+++ b/ui/routes/(swatch)/.swatch/CreateConversationForm/+page.svelte
@@ -0,0 +1,23 @@
+<script>
+  import EventCapture from '$lib/swatch/event-capture.svelte.js';
+
+  import CreateConversationForm from '$lib/components/CreateConversationForm.svelte';
+  import EventLog from '$lib/components/swatch/EventLog.svelte';
+
+  let capture = $state(new EventCapture());
+  const createConversation = capture.on('createConversation');
+</script>
+
+<h1><code>CreateConversationForm</code></h1>
+
+<nav><p><a href=".">Back to swatches</a></p></nav>
+
+<h2>rendered</h2>
+
+<div class="component-preview">
+  <CreateConversationForm {createConversation} />
+</div>
+
+<h2>events</h2>
+
+<EventLog events={capture.events} clear={capture.clear.bind(capture)} />
-- 
cgit v1.2.3


From f7c89692e76112fd20275ce631c102588835c8b8 Mon Sep 17 00:00:00 2001
From: Owen Jacobson <owen@grimoire.ca>
Date: Tue, 8 Jul 2025 19:53:08 -0400
Subject: Create swatch for the `Invite` component.

---
 ui/routes/(swatch)/.swatch/+page.svelte        |  1 +
 ui/routes/(swatch)/.swatch/Invite/+page.svelte | 21 +++++++++++++++++++++
 2 files changed, 22 insertions(+)
 create mode 100644 ui/routes/(swatch)/.swatch/Invite/+page.svelte

(limited to 'ui/routes/(swatch)/.swatch/+page.svelte')

diff --git a/ui/routes/(swatch)/.swatch/+page.svelte b/ui/routes/(swatch)/.swatch/+page.svelte
index abcb53f..5242718 100644
--- a/ui/routes/(swatch)/.swatch/+page.svelte
+++ b/ui/routes/(swatch)/.swatch/+page.svelte
@@ -8,5 +8,6 @@
 <h2>components</h2>
 
 <ul>
+  <li><a href="Invite">Invite</a></li>
   <li><a href="swatch/EventLog">swatch/EventLog</a></li>
 </ul>
diff --git a/ui/routes/(swatch)/.swatch/Invite/+page.svelte b/ui/routes/(swatch)/.swatch/Invite/+page.svelte
new file mode 100644
index 0000000..0786194
--- /dev/null
+++ b/ui/routes/(swatch)/.swatch/Invite/+page.svelte
@@ -0,0 +1,21 @@
+<script>
+  import Invite from '$lib/components/Invite.svelte';
+
+  let id = $state('Iaaaa');
+</script>
+
+<h1><code>Invite</code></h1>
+
+<nav><p><a href=".">Back to swatches</a></p></nav>
+
+<h2>properties</h2>
+
+<div class="component-properties">
+  <label>id <input type="text" bind:value={id} /></label>
+</div>
+
+<h2>rendered</h2>
+
+<div class="component-preview">
+  <Invite {id} />
+</div>
-- 
cgit v1.2.3


From 718ffe3dceffb4a0439d2b3192a266cb75c7fda7 Mon Sep 17 00:00:00 2001
From: Owen Jacobson <owen@grimoire.ca>
Date: Tue, 8 Jul 2025 19:55:34 -0400
Subject: Create swatch for the `Invites` component.

---
 ui/routes/(swatch)/.swatch/+page.svelte         |  1 +
 ui/routes/(swatch)/.swatch/Invites/+page.svelte | 35 +++++++++++++++++++++++++
 2 files changed, 36 insertions(+)
 create mode 100644 ui/routes/(swatch)/.swatch/Invites/+page.svelte

(limited to 'ui/routes/(swatch)/.swatch/+page.svelte')

diff --git a/ui/routes/(swatch)/.swatch/+page.svelte b/ui/routes/(swatch)/.swatch/+page.svelte
index abcb53f..c28b46e 100644
--- a/ui/routes/(swatch)/.swatch/+page.svelte
+++ b/ui/routes/(swatch)/.swatch/+page.svelte
@@ -8,5 +8,6 @@
 <h2>components</h2>
 
 <ul>
+  <li><a href="Invites">Invites</a></li>
   <li><a href="swatch/EventLog">swatch/EventLog</a></li>
 </ul>
diff --git a/ui/routes/(swatch)/.swatch/Invites/+page.svelte b/ui/routes/(swatch)/.swatch/Invites/+page.svelte
new file mode 100644
index 0000000..8c24627
--- /dev/null
+++ b/ui/routes/(swatch)/.swatch/Invites/+page.svelte
@@ -0,0 +1,35 @@
+<script>
+  import { json } from '$lib/swatch/derive.js';
+  import EventCapture from '$lib/swatch/event-capture.svelte.js';
+
+  import EventLog from '$lib/components/swatch/EventLog.svelte';
+  import Invites from '$lib/components/Invites.svelte';
+
+  let invitesInput = $state(
+    JSON.stringify([{ id: 'Iaaaa' }, { id: 'Ibbbb' }], /* replacer */ null, /* space */ 2),
+  );
+  let invites = $derived(json(invitesInput));
+
+  let capture = $state(new EventCapture());
+  const createInvite = capture.on('createInvite');
+</script>
+
+<h1><code>Invites</code></h1>
+
+<nav><p><a href=".">Back to swatches</a></p></nav>
+
+<h2>properties</h2>
+
+<div class="component-properties">
+  <label>invites (json) <textarea bind:value={invitesInput}></textarea></label>
+</div>
+
+<h2>rendered</h2>
+
+<div class="component-preview">
+  <Invites {invites} {createInvite} />
+</div>
+
+<h2>events</h2>
+
+<EventLog events={capture.events} clear={capture.clear.bind(capture)} />
-- 
cgit v1.2.3


From dbccc44ad781bba04862017c9b041240821d4c08 Mon Sep 17 00:00:00 2001
From: Owen Jacobson <owen@grimoire.ca>
Date: Tue, 8 Jul 2025 19:56:11 -0400
Subject: Create swatch for the `LogIn` component.

---
 ui/routes/(swatch)/.swatch/+page.svelte       |  1 +
 ui/routes/(swatch)/.swatch/LogIn/+page.svelte | 31 +++++++++++++++++++++++++++
 2 files changed, 32 insertions(+)
 create mode 100644 ui/routes/(swatch)/.swatch/LogIn/+page.svelte

(limited to 'ui/routes/(swatch)/.swatch/+page.svelte')

diff --git a/ui/routes/(swatch)/.swatch/+page.svelte b/ui/routes/(swatch)/.swatch/+page.svelte
index abcb53f..9484cf9 100644
--- a/ui/routes/(swatch)/.swatch/+page.svelte
+++ b/ui/routes/(swatch)/.swatch/+page.svelte
@@ -8,5 +8,6 @@
 <h2>components</h2>
 
 <ul>
+  <li><a href="LogIn">LogIn</a></li>
   <li><a href="swatch/EventLog">swatch/EventLog</a></li>
 </ul>
diff --git a/ui/routes/(swatch)/.swatch/LogIn/+page.svelte b/ui/routes/(swatch)/.swatch/LogIn/+page.svelte
new file mode 100644
index 0000000..8501a6c
--- /dev/null
+++ b/ui/routes/(swatch)/.swatch/LogIn/+page.svelte
@@ -0,0 +1,31 @@
+<script>
+  import EventCapture from '$lib/swatch/event-capture.svelte.js';
+
+  import EventLog from '$lib/components/swatch/EventLog.svelte';
+  import LogIn from '$lib/components/LogIn.svelte';
+
+  let legend = $state('sign in');
+
+  let capture = $state(new EventCapture());
+  const logIn = capture.on('logIn');
+</script>
+
+<h1><code>LogIn</code></h1>
+
+<nav><p><a href=".">Back to swatches</a></p></nav>
+
+<h2>properties</h2>
+
+<div class="component-properties">
+  <label>legend <input type="text" bind:value={legend} /></label>
+</div>
+
+<h2>rendered</h2>
+
+<div class="component-preview">
+  <LogIn {legend} {logIn} />
+</div>
+
+<h2>events</h2>
+
+<EventLog events={capture.events} clear={capture.clear.bind(capture)} />
-- 
cgit v1.2.3


From 3b32644d2f30170bdf949dffaea79cde4d4ec647 Mon Sep 17 00:00:00 2001
From: Owen Jacobson <owen@grimoire.ca>
Date: Tue, 8 Jul 2025 19:57:50 -0400
Subject: Create swatch for the `MessageInput` component.

---
 ui/routes/(swatch)/.swatch/+page.svelte            |  1 +
 .../(swatch)/.swatch/MessageInput/+page.svelte     | 23 ++++++++++++++++++++++
 2 files changed, 24 insertions(+)
 create mode 100644 ui/routes/(swatch)/.swatch/MessageInput/+page.svelte

(limited to 'ui/routes/(swatch)/.swatch/+page.svelte')

diff --git a/ui/routes/(swatch)/.swatch/+page.svelte b/ui/routes/(swatch)/.swatch/+page.svelte
index abcb53f..db02fc3 100644
--- a/ui/routes/(swatch)/.swatch/+page.svelte
+++ b/ui/routes/(swatch)/.swatch/+page.svelte
@@ -8,5 +8,6 @@
 <h2>components</h2>
 
 <ul>
+  <li><a href="MessageInput">MessageInput</a></li>
   <li><a href="swatch/EventLog">swatch/EventLog</a></li>
 </ul>
diff --git a/ui/routes/(swatch)/.swatch/MessageInput/+page.svelte b/ui/routes/(swatch)/.swatch/MessageInput/+page.svelte
new file mode 100644
index 0000000..b1d5864
--- /dev/null
+++ b/ui/routes/(swatch)/.swatch/MessageInput/+page.svelte
@@ -0,0 +1,23 @@
+<script>
+  import EventCapture from '$lib/swatch/event-capture.svelte.js';
+
+  import MessageInput from '$lib/components/MessageInput.svelte';
+  import EventLog from '$lib/components/swatch/EventLog.svelte';
+
+  let capture = $state(new EventCapture());
+  const sendMessage = capture.on('sendMessage');
+</script>
+
+<h1><code>MessageInput</code></h1>
+
+<nav><p><a href=".">Back to swatches</a></p></nav>
+
+<h2>rendered</h2>
+
+<div class="component-preview">
+  <MessageInput {sendMessage} />
+</div>
+
+<h2>events</h2>
+
+<EventLog events={capture.events} clear={capture.clear.bind(capture)} />
-- 
cgit v1.2.3


From 44a462286ccaa8489642460a0199c951aad43418 Mon Sep 17 00:00:00 2001
From: Owen Jacobson <owen@grimoire.ca>
Date: Tue, 8 Jul 2025 19:58:14 -0400
Subject: Create swatch for the `Message` component.

---
 ui/routes/(swatch)/.swatch/+page.svelte         |  1 +
 ui/routes/(swatch)/.swatch/Message/+page.svelte | 63 +++++++++++++++++++++++++
 2 files changed, 64 insertions(+)
 create mode 100644 ui/routes/(swatch)/.swatch/Message/+page.svelte

(limited to 'ui/routes/(swatch)/.swatch/+page.svelte')

diff --git a/ui/routes/(swatch)/.swatch/+page.svelte b/ui/routes/(swatch)/.swatch/+page.svelte
index abcb53f..d3b211a 100644
--- a/ui/routes/(swatch)/.swatch/+page.svelte
+++ b/ui/routes/(swatch)/.swatch/+page.svelte
@@ -8,5 +8,6 @@
 <h2>components</h2>
 
 <ul>
+  <li><a href="Message">Message</a></li>
   <li><a href="swatch/EventLog">swatch/EventLog</a></li>
 </ul>
diff --git a/ui/routes/(swatch)/.swatch/Message/+page.svelte b/ui/routes/(swatch)/.swatch/Message/+page.svelte
new file mode 100644
index 0000000..6fd9b6b
--- /dev/null
+++ b/ui/routes/(swatch)/.swatch/Message/+page.svelte
@@ -0,0 +1,63 @@
+<script>
+  import { DateTime } from 'luxon';
+
+  import EventCapture from '$lib/swatch/event-capture.svelte.js';
+
+  import Message from '$lib/components/Message.svelte';
+  import EventLog from '$lib/components/swatch/EventLog.svelte';
+
+  let id = $state('Mplayspelunky');
+  let atInput = $state('2025-07-07T15:19:00Z');
+  // Astonishingly, `DateTime.fromISO` does not throw on invalid inputs. It generates an "Invalid
+  // DateTime" sentinel value, instead.
+  let at = $derived(DateTime.fromISO(atInput));
+  let renderedBody = $state(
+    '<p>Lorem ipsum <code>dolor</code> sit amet, consectetur adipiscing elit. Nunc quis ante ac leo tristique iaculis vel in tortor. Praesent sed interdum ipsum. Pellentesque blandit, sapien at mattis facilisis, leo mi gravida erat, in euismod mi lectus non dui. Praesent at justo vel mauris pulvinar sodales ut sed nisl. Aliquam aliquet justo vel cursus imperdiet. Suspendisse potenti. Duis varius tortor finibus, rutrum justo ac, tincidunt enim.</p>\n' +
+      '<p>Donec velit dui, bibendum a augue sit amet, tempus condimentum neque. Integer nibh tortor, imperdiet at aliquet eu, rutrum eget ligula. Donec porttitor nisi lacus, eu bibendum augue maximus eget. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Maecenas in est eget lectus dapibus tincidunt. Ut ut nisi egestas, posuere libero laoreet, venenatis erat. Nulla maximus, nisl eget interdum ornare, enim turpis semper ligula, sed ultricies sem sem quis arcu. Ut a dapibus augue. Pellentesque nec tincidunt sem.</p>',
+  );
+  let editable = $state(true);
+  let cssClass = $state('');
+
+  let capture = $state(new EventCapture());
+  const deleteMessage = capture.on('deleteMessage');
+</script>
+
+<h1><code>Message</code></h1>
+
+<nav><p><a href=".">Back to swatches</a></p></nav>
+
+<h2>properties</h2>
+
+<div class="component-properties">
+  <label>id <input type="text" bind:value={id} /></label>
+  <label>at (iso-8601)<input type="text" bind:value={atInput} /></label>
+  <div class="suggestion">
+    interesting values:
+    <button onclick={() => (atInput = DateTime.now().toISO())}>Now</button>
+  </div>
+
+  <label>css class <input type="text" bind:value={cssClass} /></label>
+  <div class="suggestion">
+    interesting values:
+    <button onclick={() => (cssClass = '')}>(none)</button>
+    <button onclick={() => (cssClass = 'unsent')}>unsent</button>
+    <button onclick={() => (cssClass = 'deleted')}>deleted</button>
+  </div>
+
+  <label>editable <input type="checkbox" bind:checked={editable} /></label>
+
+  <label
+    ><p>rendered body (html)</p>
+    <textarea class="html" bind:value={renderedBody}></textarea>
+  </label>
+</div>
+
+<h2>rendered</h2>
+
+<div class="component-preview">
+  <Message {id} {at} {renderedBody} {editable} class={cssClass} {deleteMessage} />
+</div>
+
+<h2>events</h2>
+
+<EventLog events={capture.events} clear={capture.clear.bind(capture)} />
-- 
cgit v1.2.3


From 0fc1908827cbae3652f1ba2ef746aad5ab1a73c8 Mon Sep 17 00:00:00 2001
From: Owen Jacobson <owen@grimoire.ca>
Date: Tue, 8 Jul 2025 20:03:24 -0400
Subject: Create swatch for the `MessageRun` component.

---
 ui/routes/(swatch)/.swatch/+page.svelte            |  1 +
 ui/routes/(swatch)/.swatch/MessageRun/+page.svelte | 40 ++++++++++++++++++++++
 2 files changed, 41 insertions(+)
 create mode 100644 ui/routes/(swatch)/.swatch/MessageRun/+page.svelte

(limited to 'ui/routes/(swatch)/.swatch/+page.svelte')

diff --git a/ui/routes/(swatch)/.swatch/+page.svelte b/ui/routes/(swatch)/.swatch/+page.svelte
index abcb53f..dbdf883 100644
--- a/ui/routes/(swatch)/.swatch/+page.svelte
+++ b/ui/routes/(swatch)/.swatch/+page.svelte
@@ -8,5 +8,6 @@
 <h2>components</h2>
 
 <ul>
+  <li><a href="MessageRun">MessageRun</a></li>
   <li><a href="swatch/EventLog">swatch/EventLog</a></li>
 </ul>
diff --git a/ui/routes/(swatch)/.swatch/MessageRun/+page.svelte b/ui/routes/(swatch)/.swatch/MessageRun/+page.svelte
new file mode 100644
index 0000000..a8c8853
--- /dev/null
+++ b/ui/routes/(swatch)/.swatch/MessageRun/+page.svelte
@@ -0,0 +1,40 @@
+<script>
+  import MessageRun from '$lib/components/MessageRun.svelte';
+
+  let sender = $state('wlonk');
+  let cssClass = $state('own-message');
+  let children = $state(
+    '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc quis ante ac leo tristique iaculis vel in tortor. Praesent sed interdum ipsum. Pellentesque blandit, sapien at mattis facilisis, leo mi gravida erat, in euismod mi lectus non dui. Praesent at justo vel mauris pulvinar sodales ut sed nisl. Aliquam aliquet justo vel cursus imperdiet. Suspendisse potenti. Duis varius tortor finibus, rutrum justo ac, tincidunt enim.</p>\n' +
+      '<p>Donec velit dui, bibendum a augue sit amet, tempus condimentum neque. Integer nibh tortor, imperdiet at aliquet eu, rutrum eget ligula. Donec porttitor nisi lacus, eu bibendum augue maximus eget. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Maecenas in est eget lectus dapibus tincidunt. Ut ut nisi egestas, posuere libero laoreet, venenatis erat. Nulla maximus, nisl eget interdum ornare, enim turpis semper ligula, sed ultricies sem sem quis arcu. Ut a dapibus augue. Pellentesque nec tincidunt sem.</p>',
+  );
+</script>
+
+<h1><code>MessageRun</code></h1>
+
+<nav><p><a href=".">Back to swatches</a></p></nav>
+
+<h2>properties</h2>
+
+<div class="component-properties">
+  <label>sender <input type="text" bind:value={sender} /></label>
+  <label>css class <input type="text" bind:value={cssClass} /></label>
+  <div class="suggestion">
+    interesting values:
+    <button onclick={() => (cssClass = 'own-message')}>own-message</button>
+    <button onclick={() => (cssClass = 'other-message')}>other-message</button>
+  </div>
+
+  <label
+    ><p>children (html)</p>
+    <textarea class="html" bind:value={children}></textarea>
+  </label>
+</div>
+
+<h2>rendered</h2>
+
+<div class="component-preview">
+  <MessageRun {sender} class={cssClass}>
+    <!-- eslint-disable-next-line svelte/no-at-html-tags -->
+    {@html children}
+  </MessageRun>
+</div>
-- 
cgit v1.2.3


From 5bdebec905c3ad13220c8f55c136c34d31236d35 Mon Sep 17 00:00:00 2001
From: Owen Jacobson <owen@grimoire.ca>
Date: Tue, 8 Jul 2025 20:08:12 -0400
Subject: Create swatch for the `LogOut` component.

---
 ui/routes/(swatch)/.swatch/+page.svelte        |  1 +
 ui/routes/(swatch)/.swatch/LogOut/+page.svelte | 23 +++++++++++++++++++++++
 2 files changed, 24 insertions(+)
 create mode 100644 ui/routes/(swatch)/.swatch/LogOut/+page.svelte

(limited to 'ui/routes/(swatch)/.swatch/+page.svelte')

diff --git a/ui/routes/(swatch)/.swatch/+page.svelte b/ui/routes/(swatch)/.swatch/+page.svelte
index abcb53f..9a26017 100644
--- a/ui/routes/(swatch)/.swatch/+page.svelte
+++ b/ui/routes/(swatch)/.swatch/+page.svelte
@@ -8,5 +8,6 @@
 <h2>components</h2>
 
 <ul>
+  <li><a href="LogOut">LogOut</a></li>
   <li><a href="swatch/EventLog">swatch/EventLog</a></li>
 </ul>
diff --git a/ui/routes/(swatch)/.swatch/LogOut/+page.svelte b/ui/routes/(swatch)/.swatch/LogOut/+page.svelte
new file mode 100644
index 0000000..5eebcde
--- /dev/null
+++ b/ui/routes/(swatch)/.swatch/LogOut/+page.svelte
@@ -0,0 +1,23 @@
+<script>
+  import EventCapture from '$lib/swatch/event-capture.svelte.js';
+
+  import LogOut from '$lib/components/LogOut.svelte';
+  import EventLog from '$lib/components/swatch/EventLog.svelte';
+
+  let capture = $state(new EventCapture());
+  const logOut = capture.on('logOut');
+</script>
+
+<h1><code>LogOut</code></h1>
+
+<nav><p><a href=".">Back to swatches</a></p></nav>
+
+<h2>rendered</h2>
+
+<div class="component-preview">
+  <LogOut {logOut} />
+</div>
+
+<h2>events</h2>
+
+<EventLog events={capture.events} clear={capture.clear.bind(capture)} />
-- 
cgit v1.2.3

