diff options
| author | Owen Jacobson <owen@grimoire.ca> | 2025-07-08 01:44:46 -0400 |
|---|---|---|
| committer | Owen Jacobson <owen@grimoire.ca> | 2025-07-08 01:55:36 -0400 |
| commit | 64d16441a390e889231f2f67333d5f305b7ab878 (patch) | |
| tree | 88d686ef194eada20fc0c157e681ed72971ecc3f | |
| parent | 4eb0cc56696a3805538e5ce6d380ea26e097424c (diff) | |
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.
| -rw-r--r-- | docs/developer/SUMMARY.md | 4 | ||||
| -rw-r--r-- | docs/developer/client/swatches.md | 16 | ||||
| -rw-r--r-- | src/routes.rs | 1 | ||||
| -rw-r--r-- | src/ui/handlers/mod.rs | 2 | ||||
| -rw-r--r-- | src/ui/handlers/swatch.rs | 8 | ||||
| -rw-r--r-- | ui/app.css | 1 | ||||
| -rw-r--r-- | ui/routes/(swatch)/.swatch/+page.js | 1 | ||||
| -rw-r--r-- | ui/routes/(swatch)/.swatch/+page.svelte | 10 | ||||
| -rw-r--r-- | ui/styles/swatches.css | 24 |
9 files changed, 67 insertions, 0 deletions
diff --git a/docs/developer/SUMMARY.md b/docs/developer/SUMMARY.md index 6b0ce6a..71f85d1 100644 --- a/docs/developer/SUMMARY.md +++ b/docs/developer/SUMMARY.md @@ -14,6 +14,10 @@ - [Running Pilcrow locally](server/running.md) - [Debian packaging](server/debian-packaging.md) +# The client + +- [Swatches](client/swatches.md) + # Development tools - [Formatting](tools/formatting.md) diff --git a/docs/developer/client/swatches.md b/docs/developer/client/swatches.md new file mode 100644 index 0000000..df4f643 --- /dev/null +++ b/docs/developer/client/swatches.md @@ -0,0 +1,16 @@ +# Swatches + +To make it easier to experiment with the client's component framework, the client exposes "swatches" - pages demonstrating individual components in isolation. + +Swatches are available from a running client at the `/.swatch/` URL. This URL is not linked in the client; you Just Need To Know. + +## Writing Swatches + +Swatches are manually curated. When adding a component, add a swatch if you can. + +Things to consider: + +- For complex values, use a parser, so that the user reading your swatch can edit the structure as text. +- For freeform values whose meaning is significant, provide buttons to let the user rapidly enter and experiment with interesting values. +- Be thorough. Let the user experiment with values, even if you think those values may be nonsensical. +- Try to show the component _without_ supporting markup, as far as is possible. However, if a component generates markup that requires context - a table row component needs a table, for example, or a list element needs a list - then include that markup in the swatch. diff --git a/src/routes.rs b/src/routes.rs index 49d9fb6..6993070 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -10,6 +10,7 @@ pub fn routes(app: &App) -> Router<App> { // UI routes that can be accessed before the administrator completes setup. let ui_bootstrap = Router::new() .route("/{*path}", get(ui::handlers::asset)) + .route("/.swatch/{*path}", get(ui::handlers::swatch)) .route("/setup", get(ui::handlers::setup)); // UI routes that require the administrator to complete setup first. diff --git a/src/ui/handlers/mod.rs b/src/ui/handlers/mod.rs index ed0c14e..bcc65a1 100644 --- a/src/ui/handlers/mod.rs +++ b/src/ui/handlers/mod.rs @@ -5,6 +5,7 @@ mod invite; mod login; mod me; mod setup; +mod swatch; pub use asset::handler as asset; pub use conversation::handler as conversation; @@ -13,3 +14,4 @@ pub use invite::handler as invite; pub use login::handler as login; pub use me::handler as me; pub use setup::handler as setup; +pub use swatch::handler as swatch; diff --git a/src/ui/handlers/swatch.rs b/src/ui/handlers/swatch.rs new file mode 100644 index 0000000..4562b04 --- /dev/null +++ b/src/ui/handlers/swatch.rs @@ -0,0 +1,8 @@ +use crate::{ + error::Internal, + ui::assets::{Asset, Assets}, +}; + +pub async fn handler() -> Result<Asset, Internal> { + Assets::index() +} @@ -9,6 +9,7 @@ @import url('styles/messages.css'); @import url('styles/textarea.css'); @import url('styles/forms.css'); +@import url('styles/swatches.css'); @import url('styles/invites.css'); body { diff --git a/ui/routes/(swatch)/.swatch/+page.js b/ui/routes/(swatch)/.swatch/+page.js new file mode 100644 index 0000000..d3c3250 --- /dev/null +++ b/ui/routes/(swatch)/.swatch/+page.js @@ -0,0 +1 @@ +export const trailingSlash = 'always'; 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> diff --git a/ui/styles/swatches.css b/ui/styles/swatches.css new file mode 100644 index 0000000..f2a9f99 --- /dev/null +++ b/ui/styles/swatches.css @@ -0,0 +1,24 @@ +.component-preview { + border: 1px solid grey; + margin: 1rem 2rem; +} + +.component-properties { + margin: 1rem 2rem; +} + +.component-properties textarea { + width: 100%; + height: 10em; +} + +.component-properties textarea.html { + font-family: FiraCode, monospace; +} + +.component-properties .suggestion { + font-size: 80%; + margin-left: 1rem; + margin-right: 1rem; + margin-bottom: 0.5em; +} |
