houseaccount 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +17 -1
  3. data/README.md +10 -10
  4. data/art/index.html.erb +87 -138
  5. data/lib/houseaccount/helpers/flows.rb +3 -2
  6. data/lib/houseaccount/version.rb +1 -1
  7. data/public/css/houseaccount.css +1 -1
  8. data/public/index.html +88 -139
  9. data/public/{v0.11.0 → v0.12.0}/css/houseaccount.css +1 -1
  10. metadata +19 -19
  11. /data/public/{v0.11.0 → v0.12.0}/font/bootstrap-icons-6LILWPE2.woff2 +0 -0
  12. /data/public/{v0.11.0 → v0.12.0}/font/quicksand-500-latin-QHYSRFVK.woff2 +0 -0
  13. /data/public/{v0.11.0 → v0.12.0}/font/quicksand-500-latin-ext-QZ4PXVHB.woff2 +0 -0
  14. /data/public/{v0.11.0 → v0.12.0}/font/quicksand-500-latin-ext.woff2 +0 -0
  15. /data/public/{v0.11.0 → v0.12.0}/font/quicksand-500-latin.woff2 +0 -0
  16. /data/public/{v0.11.0 → v0.12.0}/font/quicksand-500-vietnamese-RRA5CUQB.woff2 +0 -0
  17. /data/public/{v0.11.0 → v0.12.0}/font/quicksand-500-vietnamese.woff2 +0 -0
  18. /data/public/{v0.11.0 → v0.12.0}/js/houseaccount.js +0 -0
  19. /data/public/{v0.11.0 → v0.12.0}/theme/bootstrap.css +0 -0
  20. /data/public/{v0.11.0 → v0.12.0}/theme/dawn.css +0 -0
  21. /data/public/{v0.11.0 → v0.12.0}/theme/dracula.css +0 -0
  22. /data/public/{v0.11.0 → v0.12.0}/theme/gruvbox.css +0 -0
  23. /data/public/{v0.11.0 → v0.12.0}/theme/monokai.css +0 -0
  24. /data/public/{v0.11.0 → v0.12.0}/theme/nord.css +0 -0
  25. /data/public/{v0.11.0 → v0.12.0}/theme/one_dark.css +0 -0
  26. /data/public/{v0.11.0 → v0.12.0}/theme/solarized.css +0 -0
  27. /data/public/{v0.11.0 → v0.12.0}/theme/tokyo_night.css +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: de7a17a9106491567876581098b93d4320dd463a29e3cc917f87ee2c54e4d532
4
- data.tar.gz: 9a46cdc89dd6f090736d7f82bd8dfb74385d42479c25b46fe0d721b7f065ec4c
3
+ metadata.gz: 247974e6010176c5287b60457bafb5a026ad1ee501c944ce780e3cadb1211225
4
+ data.tar.gz: a0c0a478884552c608ff2e9374fbd97fdabc292089cdc752168210da18460b77
5
5
  SHA512:
6
- metadata.gz: 5b5c2d9bc1997a8aa938788f0f46b7da04c43642672142654ba0486151333c17449608860f6027d4068382c1ad6ea041da6bdd74ab5bd4efbd92d5e128b47cb4
7
- data.tar.gz: 8f468506e8349470d44f2a5661c92517a46ddc0542144cc72a079419c605f059260ef1a6b155c9ee4059363c6c36f321167bc1965bea8d68db615c82dc1b5bf4
6
+ metadata.gz: b4aa364acf156ea2fc1430232ed75f98d9e3416d7b7099016f7e981d8d9592dfe49f8c43237e2204552f05fcce2e2800c50f41e0857e75d52874804e2f24265b
7
+ data.tar.gz: 5e0a5e27071c4e0416bf8085b995aa733db8f10784bf9ca2f6690e0e07aa25c7be90365647253fb73504a19cd88a36b3ac832086559e5b801fceb962473639aa
data/CHANGELOG.md CHANGED
@@ -7,6 +7,22 @@ For more information about changelogs, check [Keep a Changelog](http://keepachan
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## 0.12.0 - 2026-09-17
11
+
12
+ * [Change] The showcase shows rather than describes
13
+
14
+ The page at design.houseaccount.com carried a paragraph over every component saying what
15
+ the component below it was about to do. Each is gone: the thing itself is on the page, a
16
+ few pixels under where the description stood, and it is the one that cannot go stale. What
17
+ is left is the name of each component and, where a path is named, a link to the file.
18
+
19
+ The page reads down the middle now, and its sections stand in the order somebody comes for
20
+ them: Components — with Chat, Wall and Tables as subsections of it, which is what they
21
+ always were — then Error pages, Palettes and Icons, which is Favicons with the drawing
22
+ under `/logo` as its first column. The header says what the page is in one sentence: the
23
+ components, error pages, palettes and icons shared by Fountain, Goldrush, Houston and
24
+ Autopilot, each mark linking to its own host.
25
+
10
26
  ## 0.11.0 - 2026-09-16
11
27
 
12
28
  * [Feature] The built stylesheet and script are in the package, for a page that links them
@@ -15,7 +31,7 @@ For more information about changelogs, check [Keep a Changelog](http://keepachan
15
31
  script opens on three bare specifiers nothing resolves without an import map, and the
16
32
  stylesheet is fourteen `@import` lines a browser would fetch one after another. So the
17
33
  built `css/`, `js/`, `theme/` and `font/` ship beside them, and a page on any host links
18
- one file from a CDN holding the package — `cdn.jsdelivr.net/npm/houseaccount@0.11.0/` —
34
+ one file from a CDN holding the package — `cdn.jsdelivr.net/npm/houseaccount@0.11.0/public/` —
19
35
  at a version that is owed those bytes for good, npm never letting one be written twice.
20
36
 
21
37
  * [Change] Every URL inside the stylesheet is relative
data/README.md CHANGED
@@ -22,10 +22,10 @@ gem install houseaccount
22
22
 
23
23
  ```ruby
24
24
  # Gemfile
25
- gem 'houseaccount', '~> 0.11.0'
25
+ gem 'houseaccount', '~> 0.12.0'
26
26
  ```
27
27
 
28
- `~> 0.11.0` stops short of `0.12`, since below 1.0 a minor release may break whatever it likes.
28
+ `~> 0.12.0` stops short of `0.13`, since below 1.0 a minor release may break whatever it likes.
29
29
  Rails 8.1 and Ruby 3.2 are the minimum.
30
30
 
31
31
  ### From npm
@@ -59,7 +59,7 @@ Stimulus application rather than taking the house's:
59
59
  import WallController from 'houseaccount/controllers/wall_controller.js'
60
60
  ```
61
61
 
62
- Pin as a Gemfile does, and for the same reason: `"houseaccount": "~0.11.0"` stops short of `0.12`.
62
+ Pin as a Gemfile does, and for the same reason: `"houseaccount": "~0.12.0"` stops short of `0.13`.
63
63
 
64
64
  A page takes the gem's layout, and wears the same head:
65
65
 
@@ -95,7 +95,7 @@ which Pages redirects away from.
95
95
 
96
96
  With the gem in the bundle an app serves `/css/houseaccount.css`, `/js/houseaccount.js`,
97
97
  `/theme/*`, `/font/*`, `/logo/*` and `/favicon/*` itself — and its own version's copy under
98
- `/v0.11.0/`, which is what the head helper links, cached for a year — answers a 400, 404, 406, 422 or 500
98
+ `/v0.12.0/`, which is what the head helper links, cached for a year — answers a 400, 404, 406, 422 or 500
99
99
  with the house's own page, and has these helpers in every view:
100
100
 
101
101
  ```erb
@@ -191,7 +191,7 @@ rather than the app's own people: unsaid, it is this app's, by its name.
191
191
 
192
192
  The words are the view's, said in `content_for`: `:title` is the `h1`, `:subtitle` the line
193
193
  under it, drawn only where there is one, and `:width` how wide the card is, a CSS length that
194
- is `30rem` unless said — a chat's page says `75rem`. What the layout knows goes in the call:
194
+ is `75rem` unless said — a page asking one question, a sign-in say, says `30rem`. What the layout knows goes in the call:
195
195
  `footer:` is the pieces of the foot, joined by a middot, none drawing no foot, and `logo:`
196
196
  where the mark links, the house's front door unless said.
197
197
 
@@ -240,19 +240,19 @@ Those follow the latest release. Every release is also kept whole under its own
240
240
  forever and cached for a year, for a page that would rather move on its own terms:
241
241
 
242
242
  ```html
243
- <link rel='stylesheet' href='https://design.houseaccount.com/v0.11.0/css/houseaccount.css'>
244
- <script type='module' src='https://design.houseaccount.com/v0.11.0/js/houseaccount.js'></script>
243
+ <link rel='stylesheet' href='https://design.houseaccount.com/v0.12.0/css/houseaccount.css'>
244
+ <script type='module' src='https://design.houseaccount.com/v0.12.0/js/houseaccount.js'></script>
245
245
  ```
246
246
 
247
247
  The same two files come from any CDN that carries the npm package, for a page that would
248
248
  rather not depend on the site at all:
249
249
 
250
250
  ```html
251
- <link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/houseaccount@0.11.0/css/houseaccount.css'>
252
- <script type='module' src='https://cdn.jsdelivr.net/npm/houseaccount@0.11.0/js/houseaccount.js'></script>
251
+ <link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/houseaccount@0.12.0/public/css/houseaccount.css'>
252
+ <script type='module' src='https://cdn.jsdelivr.net/npm/houseaccount@0.12.0/public/js/houseaccount.js'></script>
253
253
  ```
254
254
 
255
- The palettes are beside them, at `/theme/nord.css` and the rest. A published version is never
255
+ The palettes are beside them, at `public/theme/nord.css` and the rest. A published version is never
256
256
  written again, so that URL is owed its bytes for as long as npm stands.
257
257
 
258
258
  A host with a Content Security Policy allows whichever origin it names for `style-src`,
data/art/index.html.erb CHANGED
@@ -19,113 +19,57 @@
19
19
  /* The page's own chrome and nothing else: everything shown below is styled by
20
20
  css/houseaccount.css alone, which is the point of showing it. */
21
21
  .design-section { padding-block: 2rem; border-block-end: var(--bs-border-width) solid var(--bs-border-color); }
22
- .design-swatch { display: flex; flex-direction: column; align-items: center; gap: .5rem; width: 7rem; }
23
- .design-swatch img { width: 4rem; height: 4rem; }
22
+ .design-section > p { max-width: 48rem; margin-inline: auto; }
23
+ .design-subsection { margin-block-start: 2.5rem; padding-block-start: 1.5rem; border-block-start: var(--bs-border-width) dashed var(--bs-border-color); }
24
+ .design-mark { width: 1.5rem; height: 1.5rem; }
25
+ .design-logo { width: 2.5rem; height: 2.5rem; }
24
26
  .design-url { font-family: var(--bs-font-monospace); font-size: var(--bs-font-size-sm); color: var(--bs-fg-2); overflow-wrap: anywhere; }
25
27
  .design-shell { height: 18rem; border: var(--bs-border-width) solid var(--bs-border-color); border-radius: var(--bs-radius-3); overflow: hidden; }
26
28
  .design-shell .recourse-shell { height: 100%; }
27
- .chat-thread { max-width: 36rem; }
29
+ .chat-thread { max-width: 36rem; margin-inline: auto; }
28
30
  /* The wall fills a viewport; here it fills a box, so the page can show it beside the rest. */
29
31
  .design-wall { position: relative; height: 24rem; overflow: hidden; border-radius: var(--bs-radius-3); }
30
32
  .design-wall .tools { position: absolute; }
31
33
  .design-wall .flow { height: 100%; justify-content: center; }
32
34
  </style>
33
35
  </head>
34
- <body>
35
- <header class='container-fluid px-3 py-3 border-bottom d-flex align-items-center gap-3'>
36
+ <body class='text-center'>
37
+ <header class='container-fluid px-3 py-3 border-bottom d-flex flex-wrap justify-content-center align-items-baseline gap-3'>
36
38
  <a class='lockup quicksand' href='#'><svg aria-hidden='true' style='width: 1.0515em; height: 1.0515em; top: 0.18625em' viewBox='0 0 512 512'><g fill='none' stroke='#3b8ae8' stroke-width='28' stroke-linecap='round' stroke-linejoin='round' transform='rotate(45 256 256)'><path d='M196 60 L316 60 L316 372 L196 372 Z'/><path d='M196 120 L316 120'/><path d='M196 372 L256 470 L316 372'/><path d='M232 431 L256 470 L280 431 Z' fill='#1B5288'/></g></svg>design</a>
37
- <span class='fg-2'>the front end every HouseAccount app shares</span>
38
- <nav class='ms-auto d-flex gap-3 small'>
39
- <a href='#logo'>Logos</a><a href='#favicon'>Favicons</a><a href='#theme'>Palettes</a>
40
- <a href='#component'>Components</a><a href='#chat'>Chat</a><a href='#wall'>Wall</a><a href='#table'>Tables</a><a href='#page'>Pages</a>
41
- </nav>
39
+ <nav class='fg-2'>the <a href='#component'>components</a>, <a href='#page'>error pages</a>, <a href='#theme'>palettes</a>, <a href='#favicon'>icons</a> shared by <a href='https://pro.houseaccount.com/bookings' title='Fountain'><img class='design-mark' src='logo/fountain.svg' alt='Fountain'></a> <a href='https://gold.houseaccount.com/specialty_matches' title='Goldrush'><img class='design-mark' src='logo/goldrush.svg' alt='Goldrush'></a> <a href='https://providers.houseaccount.com/providers' title='Houston'><img class='design-mark' src='logo/houston.svg' alt='Houston'></a> <a href='https://checkout.houseaccount.com/providers' title='Autopilot'><img class='design-mark' src='logo/autopilot.svg' alt='Autopilot'></a></nav>
42
40
  </header>
43
41
 
44
42
  <main class='container-fluid px-3'>
45
43
  <section class='design-section'>
46
- <h1 class='quicksand'>Everything a HouseAccount page is made of</h1>
47
- <p class='lead' style='max-width: 48rem'>
48
- One stylesheet, one script, the marks every app is known by, and the pages shown when an
49
- app is not. Each is at a stable path here; an app on the <code>houseaccount</code> gem
50
- serves the same paths itself, and everything else links them from this origin.
51
- </p>
52
- <div class='row g-3' style='max-width: 60rem'>
44
+ <h1 class='quicksand'>Multiple apps, same front-end</h1>
45
+ <div class='row g-3 mx-auto' style='max-width: 60rem'>
53
46
  <div class='col-12 md:col-6'>
54
47
  <div class='card p-3'>
55
48
  <strong>Stylesheet</strong>
56
- <span class='design-url'>https://design.houseaccount.com/css/houseaccount.css</span>
57
- <span class='small fg-2 mt-1'>Bootstrap 6 alpha, Bootstrap Icons and the house's own rules.</span>
49
+ <a class='design-url' href='css/houseaccount.css'>https://design.houseaccount.com/css/houseaccount.css</a>
50
+ <span class='small fg-2 mt-1'>Bootstrap 6 alpha, Bootstrap Icons and the components below.</span>
58
51
  </div>
59
52
  </div>
60
53
  <div class='col-12 md:col-6'>
61
54
  <div class='card p-3'>
62
55
  <strong>Script</strong>
63
- <span class='design-url'>https://design.houseaccount.com/js/houseaccount.js</span>
64
- <span class='small fg-2 mt-1'>Turbo, Bootstrap, and a Stimulus application with every controller the house names.</span>
56
+ <a class='design-url' href='js/houseaccount.js'>https://design.houseaccount.com/js/houseaccount.js</a>
57
+ <span class='small fg-2 mt-1'>Turbo, Bootstrap, and a Stimulus application</span>
65
58
  </div>
66
59
  </div>
67
60
  <div class='col-12'>
68
61
  <div class='card p-3'>
69
62
  <strong>Pinned to a version — the latest is <%= version %></strong>
70
- <span class='design-url'>https://design.houseaccount.com/v<%= version %>/css/houseaccount.css · /v<%= version %>/js/houseaccount.js · /v<%= version %>/theme/nord.css</span>
71
- <span class='small fg-2 mt-1'>Every release stays at its own prefix forever, whole and cached for a year, for a page that moves on its own terms. The unversioned paths follow the latest.</span>
63
+ <span class='design-url'><a href='v<%= version %>/css/houseaccount.css'>v<%= version %>/css/houseaccount.css</a> · <a href='v<%= version %>/js/houseaccount.js'>v<%= version %>/js/houseaccount.js</a> · <a href='v<%= version %>/theme/nord.css'>v<%= version %>/theme/nord.css</a></span>
72
64
  </div>
73
65
  </div>
74
66
  </div>
75
67
  </section>
76
68
 
77
- <section class='design-section' id='logo'>
78
- <h2>Logos</h2>
79
- <p class='fg-2'>One drawing per app under <code>/logo</code>, as SVG and as a 512-pixel PNG.</p>
80
- <div class='d-flex flex-wrap gap-4'>
81
- <figure class='design-swatch'><img src='logo/houseaccount.svg' alt='HouseAccount'><figcaption class='design-url'>logo/houseaccount.svg</figcaption></figure>
82
- <figure class='design-swatch'><img src='logo/fountain.svg' alt='Fountain'><figcaption class='design-url'>logo/fountain.svg</figcaption></figure>
83
- <figure class='design-swatch'><img src='logo/goldrush.svg' alt='Goldrush'><figcaption class='design-url'>logo/goldrush.svg</figcaption></figure>
84
- <figure class='design-swatch'><img src='logo/houston.svg' alt='Houston'><figcaption class='design-url'>logo/houston.svg</figcaption></figure>
85
- <figure class='design-swatch'><img src='logo/autopilot.svg' alt='Autopilot'><figcaption class='design-url'>logo/autopilot.svg</figcaption></figure>
86
- <figure class='design-swatch'><img src='logo/design.svg' alt='Design'><figcaption class='design-url'>logo/design.svg</figcaption></figure>
87
- <figure class='design-swatch'><img src='logo/houseaccount.png' alt='HouseAccount, bitmap'><figcaption class='design-url'>logo/houseaccount.png</figcaption></figure>
88
- </div>
89
- </section>
90
-
91
- <section class='design-section' id='favicon'>
92
- <h2>Favicons</h2>
93
- <p class='fg-2'>What a tab, a phone and a manifest each ask for, per app under <code>/favicon</code>. The pink one is a local machine's.</p>
94
- <div class='table-responsive'>
95
- <table class='table table-hover' style='max-width: 60rem'>
96
- <thead><tr><th scope='col'>App</th><th scope='col'>.svg</th><th scope='col'>-dev.svg</th><th scope='col'>-96.png</th><th scope='col'>-180.png</th><th scope='col'>-192.png</th><th scope='col'>-512.png</th><th scope='col'>.ico</th><th scope='col'>.webmanifest</th></tr></thead>
97
- <tbody>
98
- <tr><th scope='row'>houseaccount</th><td><img src='favicon/houseaccount.svg' width='24' alt=''></td><td><img src='favicon/houseaccount-dev.svg' width='24' alt=''></td><td><img src='favicon/houseaccount-96.png' width='24' alt=''></td><td><img src='favicon/houseaccount-180.png' width='24' alt=''></td><td><img src='favicon/houseaccount-192.png' width='24' alt=''></td><td><img src='favicon/houseaccount-512.png' width='24' alt=''></td><td><a href='favicon/houseaccount.ico'>ico</a></td><td><a href='favicon/houseaccount.webmanifest'>manifest</a></td></tr>
99
- <tr><th scope='row'>fountain</th><td><img src='favicon/fountain.svg' width='24' alt=''></td><td><img src='favicon/fountain-dev.svg' width='24' alt=''></td><td><img src='favicon/fountain-96.png' width='24' alt=''></td><td><img src='favicon/fountain-180.png' width='24' alt=''></td><td><img src='favicon/fountain-192.png' width='24' alt=''></td><td><img src='favicon/fountain-512.png' width='24' alt=''></td><td><a href='favicon/fountain.ico'>ico</a></td><td><a href='favicon/fountain.webmanifest'>manifest</a></td></tr>
100
- <tr><th scope='row'>goldrush</th><td><img src='favicon/goldrush.svg' width='24' alt=''></td><td><img src='favicon/goldrush-dev.svg' width='24' alt=''></td><td><img src='favicon/goldrush-96.png' width='24' alt=''></td><td><img src='favicon/goldrush-180.png' width='24' alt=''></td><td><img src='favicon/goldrush-192.png' width='24' alt=''></td><td><img src='favicon/goldrush-512.png' width='24' alt=''></td><td><a href='favicon/goldrush.ico'>ico</a></td><td><a href='favicon/goldrush.webmanifest'>manifest</a></td></tr>
101
- <tr><th scope='row'>houston</th><td><img src='favicon/houston.svg' width='24' alt=''></td><td><img src='favicon/houston-dev.svg' width='24' alt=''></td><td><img src='favicon/houston-96.png' width='24' alt=''></td><td><img src='favicon/houston-180.png' width='24' alt=''></td><td><img src='favicon/houston-192.png' width='24' alt=''></td><td><img src='favicon/houston-512.png' width='24' alt=''></td><td><a href='favicon/houston.ico'>ico</a></td><td><a href='favicon/houston.webmanifest'>manifest</a></td></tr>
102
- <tr><th scope='row'>design</th><td><img src='favicon/design.svg' width='24' alt=''></td><td><img src='favicon/design-dev.svg' width='24' alt=''></td><td><img src='favicon/design-96.png' width='24' alt=''></td><td><img src='favicon/design-180.png' width='24' alt=''></td><td><img src='favicon/design-192.png' width='24' alt=''></td><td><img src='favicon/design-512.png' width='24' alt=''></td><td><a href='favicon/design.ico'>ico</a></td><td><a href='favicon/design.webmanifest'>manifest</a></td></tr>
103
- <tr><th scope='row'>autopilot</th><td><img src='favicon/autopilot.svg' width='24' alt=''></td><td><img src='favicon/autopilot-dev.svg' width='24' alt=''></td><td><img src='favicon/autopilot-96.png' width='24' alt=''></td><td><img src='favicon/autopilot-180.png' width='24' alt=''></td><td><img src='favicon/autopilot-192.png' width='24' alt=''></td><td><img src='favicon/autopilot-512.png' width='24' alt=''></td><td><a href='favicon/autopilot.ico'>ico</a></td><td><a href='favicon/autopilot.webmanifest'>manifest</a></td></tr>
104
- </tbody>
105
- </table>
106
- </div>
107
- </section>
108
-
109
- <section class='design-section' id='theme'>
110
- <h2>Palettes</h2>
111
- <p class='fg-2'>Nine stylesheets under <code>/theme</code> that repaint Bootstrap's ramps; the toggle rotates through them and flips the mode, the way the sidebar's does.</p>
112
- <div class='d-flex align-items-center gap-3'>
113
- <button type='button' class='btn btn-outline theme-primary' data-controller='scheme' data-action='scheme#rotate'
114
- data-scheme-themes-value='["bootstrap","dawn","dracula","gruvbox","monokai","nord","one_dark","solarized","tokyo_night"]'
115
- data-scheme-path-value='theme' data-scheme-storage-value='recourse-scheme'>
116
- <span class='recourse-scheme-light'><i class='bi bi-moon-fill'></i> Another palette, dark</span>
117
- <span class='recourse-scheme-dark'><i class='bi bi-sun-fill'></i> Another palette, light</span>
118
- </button>
119
- <span class='design-url'>theme/&lt;name&gt;.css · bootstrap dawn dracula gruvbox monokai nord one_dark solarized tokyo_night</span>
120
- </div>
121
- </section>
122
-
123
69
  <section class='design-section' id='component'>
124
70
  <h2>Components</h2>
125
- <p class='fg-2'>Bootstrap 6 as the house draws it. Every rule that differs from upstream is in <code>css/houseaccount.css</code>.</p>
126
-
127
- <h3 class='h5 mt-4'>Buttons and badges</h3>
128
- <div class='d-flex flex-wrap align-items-center gap-2'>
71
+ <h3 class='h5 design-subsection'>Buttons and badges</h3>
72
+ <div class='d-flex flex-wrap justify-content-center align-items-center gap-2'>
129
73
  <button type='button' class='btn btn-solid theme-primary'>Solid</button>
130
74
  <button type='button' class='btn btn-outline theme-primary'>Outline</button>
131
75
  <button type='button' class='btn btn-link p-0 align-baseline'>Link</button>
@@ -134,23 +78,39 @@
134
78
  <span class='badge theme-danger'>failed</span>
135
79
  </div>
136
80
 
137
- <h3 class='h5 mt-4'>Breadcrumb</h3>
138
- <nav aria-label='Breadcrumb'><ol class='breadcrumb m-0'>
81
+ <h3 class='h5 design-subsection'>Breadcrumb</h3>
82
+ <nav aria-label='Breadcrumb'><ol class='breadcrumb m-0 justify-content-center'>
139
83
  <li class='breadcrumb-item'><a class='breadcrumb-link' href='#'><i class='bi bi-geo'></i> States</a></li>
140
84
  <li class='breadcrumb-item'><span class='breadcrumb-link active'>California</span></li>
141
85
  </ol></nav>
142
86
 
143
- <h3 class='h5 mt-4'>PIN</h3>
144
- <p class='fg-2 small'>What <code>pin_field form, :pin_confirmation</code> draws: one real field, six slots by Bootstrap, the code offered by the phone from the text that brought it, and a paste that sends itself.</p>
145
- <form onsubmit='return false' style='max-width: 22rem'>
87
+ <h3 class='h5 design-subsection' id='table'>Tables</h3>
88
+ <div class='table-responsive' style='container-type: inline-size'>
89
+ <table class='table table-hover sm:table-stacked'>
90
+ <thead><tr>
91
+ <th scope='col'><i class='bi bi-bookmark' role='img' data-controller='tooltip' data-bs-placement='top' data-bs-title='Kept'></i></th>
92
+ <th scope='col'><a href='#'>Name <i class='bi bi-sort-down'></i></a></th>
93
+ <th scope='col'><a href='#'>Phone</a></th>
94
+ <th scope='col'><a href='#'>Status</a></th>
95
+ <th scope='col' class='recourse-counter'><i class='bi bi-briefcase' role='img' data-controller='tooltip' data-bs-placement='top' data-bs-title='Jobs'></i></th>
96
+ </tr></thead>
97
+ <tbody>
98
+ <tr class='recourse-kept'><td class='recourse-bookmark'><i class='bi bi-bookmark-fill'></i></td><td data-cell='Name'>Blue Crew</td><td data-cell='Phone'><span data-controller='phone'>4155550000</span></td><td data-cell='Status'><span class='badge'>active</span></td><td class='recourse-counter'><a href='#' data-cell='Jobs'><span class='recourse-counter-figure'>21</span><span class='recourse-counter-word'>21 jobs</span></a></td></tr>
99
+ <tr class='recourse-written'><td class='recourse-bookmark'><i class='bi bi-bookmark'></i></td><td data-cell='Name'>Nashville Plumbing</td><td data-cell='Phone'><span data-controller='phone'>6155550123</span></td><td data-cell='Status'><span class='badge'>draft</span></td><td class='recourse-counter'><a href='#' data-cell='Jobs'><span class='recourse-counter-figure'>3</span><span class='recourse-counter-word'>3 jobs</span></a></td></tr>
100
+ <tr><td class='recourse-bookmark'><i class='bi bi-bookmark'></i></td><td data-cell='Name'>Golden Gate Electric</td><td data-cell='Phone'><span data-controller='phone'>4155559876</span></td><td data-cell='Status'><span class='badge'>active</span></td><td class='recourse-counter'><a href='#' data-cell='Jobs'><span class='recourse-counter-figure'>38,405</span><span class='recourse-counter-word'>38,405 jobs</span></a></td></tr>
101
+ </tbody>
102
+ </table>
103
+ </div>
104
+
105
+ <h3 class='h5 design-subsection'>PIN</h3>
106
+ <form class='mx-auto' onsubmit='return false' style='max-width: 22rem'>
146
107
  <div class='otp otp-lg' data-controller='otp' data-bs-otp='true'>
147
108
  <input class='otp-input' inputmode='numeric' pattern='[0-9]{6}' minlength='6' maxlength='6' autocomplete='one-time-code' required type='text' name='pin' id='pin' aria-label='6-digit code'>
148
109
  </div>
149
110
  </form>
150
111
 
151
- <h3 class='h5 mt-4'>Combobox</h3>
152
- <p class='fg-2 small'>A <code>&lt;select data-controller='combobox'&gt;</code>, dressed by the bundle: a search box, a check per pick where it is <code>multiple</code>, an <code>All</code> row that puts held-back options on the menu, and a figure beside an option from <code>data-count</code>. The select stays what the form submits.</p>
153
- <div class='d-flex flex-wrap gap-3 align-items-start'>
112
+ <h3 class='h5 design-subsection'>Combobox</h3>
113
+ <div class='d-flex flex-wrap justify-content-center gap-3 align-items-start'>
154
114
  <div style='width: 16rem'>
155
115
  <label class='form-label' for='team'>Team</label>
156
116
  <select class='form-select' id='team' name='team' data-controller='combobox' data-combobox-placeholder-value='Select…' data-search='Search…' data-clear='Clear search' data-no-results='No results found'>
@@ -171,46 +131,39 @@
171
131
  </div>
172
132
  </div>
173
133
 
174
- <h3 class='h5 mt-4'>Confirm</h3>
175
- <p class='fg-2 small'>Any link or form with <code>data-turbo-confirm</code> asks through a Bootstrap dialog the bundle draws on the first ask: the first line is the question, the rest are paragraphs, and the answer wears the words of the button that asked.</p>
134
+ <h3 class='h5 design-subsection'>Confirm</h3>
176
135
  <a class='btn btn-sm btn-solid theme-danger' href='#confirm-demo' data-turbo-method='delete' data-turbo-confirm='Delete California?&#10;&#10;58 counties and 3 markets will be deleted with it.&#10;12 messages will be kept, without a job.&#10;Anything under those goes too.&#10;&#10;This cannot be undone.'>Delete state</a>
177
136
 
178
- <h3 class='h5 mt-4'>Tooltip and relative time</h3>
137
+ <h3 class='h5 design-subsection'>Tooltip and relative time</h3>
179
138
  <p>Hover the icon and the time: <i class='bi bi-telephone' role='img' data-controller='tooltip' data-bs-placement='top' data-bs-title='Phone'></i> ·
180
139
  <time datetime='2026-09-13T12:00:00-04:00' data-controller='relative-time tooltip' data-bs-placement='left' data-bs-title='a moment ago'>Sep 13 at 12:00pm EDT</time></p>
181
140
 
182
- <h3 class='h5 mt-4'>Phone</h3>
183
- <p class='fg-2 small'>The server hands over ten digits and <code>data-controller='phone'</code>; the browser decides the shape, in a cell and in a field.</p>
184
- <p>A cell: <span data-controller='phone'>4155550000</span></p>
185
- <div style='max-width: 20rem'>
141
+ <h3 class='h5 design-subsection'>Phone</h3>
142
+ <p>Phone: <span data-controller='phone'>4155550000</span></p>
143
+ <div class='mx-auto' style='max-width: 20rem'>
186
144
  <label class='form-label' for='phone'>Phone</label>
187
145
  <input class='form-control' type='tel' id='phone' data-controller='phone' data-action='keydown->phone#down input->phone#input' value='4155550000'>
188
146
  </div>
189
147
 
190
- <h3 class='h5 mt-4'>A masked value</h3>
191
- <div class='form-control-plaintext d-flex gap-2 align-items-end' data-controller='reveal' data-reveal-plain-value='SEC-0000'>
148
+ <h3 class='h5 design-subsection'>Mask</h3>
149
+ <div class='form-control-plaintext d-flex justify-content-center gap-2 align-items-end' data-controller='reveal' data-reveal-plain-value='SEC-0000'>
192
150
  <span data-reveal-target='mask'>********</span>
193
151
  <button type='button' class='btn btn-link btn-sm p-0' data-action='reveal#show' data-reveal-target='button'>Show</button>
194
152
  </div>
195
153
 
196
- <h3 class='h5 mt-4'>Toast</h3>
197
- <div class='toast show' role='status' aria-live='polite' style='position: static'>
154
+ <h3 class='h5 design-subsection'>Toast</h3>
155
+ <div class='toast show mx-auto' role='status' aria-live='polite' style='position: static'>
198
156
  <div class='toast-body d-flex align-items-center gap-2'><i class='bi bi-check-circle-fill fg-success'></i> Blue Crew was updated.</div>
199
157
  </div>
200
- </section>
201
158
 
202
- <section class='design-section' id='chat'>
203
- <h2>Chat</h2>
204
- <p class='fg-2'>What the <code>chat_with</code> helper draws: turns in on the left and out on the right, who said each and when, a delivery mark, what a turn cost, an answer being typed, and a field whose suggestion cycles.</p>
159
+ <h3 class='h5 design-subsection' id='chat'>Chat</h3>
205
160
  <div class='chat-thread' data-controller='thread'>
206
161
  <div class='chat' data-thread-target='messages'>
207
- <small class='chat-aside chat-aside-in'>Claude <time datetime='2026-09-13T12:00:00-04:00' title='September 13, 2026 12:00'>2 minutes ago</time></small>
208
- <p class='chat-bubble chat-in'>Data loaded! What can I help with?</p>
209
162
  <small class='chat-aside chat-aside-out'>you <time datetime='2026-09-13T12:01:00-04:00' title='September 13, 2026 12:01'>a minute ago</time> <strong class='fg-success'>✓</strong></small>
210
163
  <p class='chat-bubble chat-out'>How much did I bill last month?</p>
211
- <small class='chat-aside chat-aside-in'>Claude <time datetime='2026-09-13T12:01:30-04:00' title='September 13, 2026 12:01'>a minute ago</time> · $0.0123</small>
212
- <p class='chat-bubble chat-in'><span class='fs-4 d-block'>$12,400</span>Across 31 jobs, up from $9,800 the month before.</p>
213
- <small class='chat-aside chat-aside-out'>you <strong class='fg-danger'>✕</strong></small>
164
+ <small class='chat-aside chat-aside-in'><time datetime='2026-09-13T12:01:30-04:00' title='September 13, 2026 12:01'>a minute ago</time> · $0.0123</small>
165
+ <p class='chat-bubble chat-in'>Across 31 jobs, up from $9,800 the month before.</p>
166
+ <small class='chat-aside chat-aside-out'>you</small>
214
167
  <p class='chat-bubble chat-out'>And the month before?</p>
215
168
  <p class='chat-bubble chat-in chat-typing' aria-label='Typing'><span></span><span></span><span></span></p>
216
169
  </div>
@@ -222,11 +175,9 @@
222
175
  <input type='submit' value='Send' class='btn btn-solid rounded-3 theme-primary ms-3'>
223
176
  </form>
224
177
  </div>
225
- </section>
226
178
 
227
- <section class='design-section' id='wall'>
228
- <h2>Wall</h2>
229
- <p class='fg-2'>A page of the signup flow, as <code>flow</code> draws it around a card: the mark over a cyanotype of the trades a homeowner books, drifting up in columns with the family's marks among them, a title, a line, the card as wide as <code>width:</code> says, and the way out. One attribute draws the wall, <code>data-controller='wall'</code>. Blueprint blues in light, inverted in dark.</p>
179
+ <h3 class='h5 design-subsection' id='wall'>Wall</h3>
180
+ <p class='fg-2'>A page of the signup flow, as <code>flow</code> draws it around a card.</p>
230
181
  <div class='design-wall'>
231
182
  <div class='flow' data-controller='wall'>
232
183
  <header><a class='lockup quicksand' href='#wall'><svg aria-hidden='true' style='width: 0.8117em; height: 0.8117em; top: 0.0358em' viewBox='0 0 512 512'><g fill='none' stroke='#3b8ae8' stroke-width='28' stroke-linecap='round' stroke-linejoin='round'><path d='M256 302Q256 256 295.8 233L406.2 169.3Q446 146.3 446 192.3V319.7Q446 365.7 406.2 388.7L295.8 452.4Q256 475.4 256 429.4Z' fill='#1B5288'/><path d='M216.2 59.6Q256 36.6 295.8 59.6L406.2 123.3Q446 146.3 446 192.3V319.7Q446 365.7 406.2 388.7L295.8 452.4Q256 475.4 216.2 452.4L105.8 388.7Q66 365.7 66 319.7V192.3Q66 146.3 105.8 123.3Z'/><path d='M256 256 95.4 163.3'/><path d='M256 256 416.6 163.3'/><path d='M256 256V441.4'/></g></svg><span class='house'>house</span>account</a></header>
@@ -246,49 +197,47 @@
246
197
  </div>
247
198
  </section>
248
199
 
249
- <section class='design-section' id='table'>
250
- <h2>Tables</h2>
251
- <p class='fg-2'>A recourse table: sortable headings with an icon, a kept row, the row a write just landed on, and cells that stack under 576 pixels.</p>
252
- <div class='table-responsive' style='container-type: inline-size'>
253
- <table class='table table-hover sm:table-stacked'>
254
- <thead><tr>
255
- <th scope='col'><i class='bi bi-bookmark' role='img' data-controller='tooltip' data-bs-placement='top' data-bs-title='Kept'></i></th>
256
- <th scope='col'><a href='#'>Name <i class='bi bi-sort-down'></i></a></th>
257
- <th scope='col'><a href='#'>Phone</a></th>
258
- <th scope='col'><a href='#'>Status</a></th>
259
- <th scope='col' class='recourse-counter'><i class='bi bi-briefcase' role='img' data-controller='tooltip' data-bs-placement='top' data-bs-title='Jobs'></i></th>
260
- </tr></thead>
261
- <tbody>
262
- <tr class='recourse-kept'><td class='recourse-bookmark'><i class='bi bi-bookmark-fill'></i></td><td data-cell='Name'>Blue Crew</td><td data-cell='Phone'><span data-controller='phone'>4155550000</span></td><td data-cell='Status'><span class='badge'>active</span></td><td class='recourse-counter'><a href='#' data-cell='Jobs'><span class='recourse-counter-figure'>21</span><span class='recourse-counter-word'>21 jobs</span></a></td></tr>
263
- <tr class='recourse-written'><td class='recourse-bookmark'><i class='bi bi-bookmark'></i></td><td data-cell='Name'>Nashville Plumbing</td><td data-cell='Phone'><span data-controller='phone'>6155550123</span></td><td data-cell='Status'><span class='badge'>draft</span></td><td class='recourse-counter'><a href='#' data-cell='Jobs'><span class='recourse-counter-figure'>3</span><span class='recourse-counter-word'>3 jobs</span></a></td></tr>
264
- <tr><td class='recourse-bookmark'><i class='bi bi-bookmark'></i></td><td data-cell='Name'>Golden Gate Electric</td><td data-cell='Phone'><span data-controller='phone'>4155559876</span></td><td data-cell='Status'><span class='badge'>active</span></td><td class='recourse-counter'><a href='#' data-cell='Jobs'><span class='recourse-counter-figure'>38,405</span><span class='recourse-counter-word'>38,405 jobs</span></a></td></tr>
265
- </tbody>
266
- </table>
267
- </div>
268
- </section>
269
-
270
200
  <section class='design-section' id='page'>
271
- <h2>Pages</h2>
272
- <p class='fg-2'>What a HouseAccount app answers when it cannot answer, under <code>/page</code>. The <code>houseaccount</code> engine serves them for every status.</p>
273
- <ul class='list-unstyled d-flex flex-wrap gap-3'>
201
+ <h2>Error pages</h2>
202
+ <ul class='list-unstyled d-flex flex-wrap justify-content-center gap-3'>
274
203
  <li><a href='page/400'>400 Bad request</a></li>
275
204
  <li><a href='page/404'>404 Not found</a></li>
276
205
  <li><a href='page/406-unsupported-browser'>406 Unsupported browser</a></li>
277
206
  <li><a href='page/422'>422 Unprocessable</a></li>
278
207
  <li><a href='page/500'>500 Server error</a></li>
279
208
  </ul>
280
- <p class='fg-2'>And what each app shows while it is down, under <code>/down</code>: its own mark in the middle, the house's at the foot. The engine answers <code>/down.html</code> with the host's own once <code>Houseaccount.app</code> names it, and Heroku's maintenance page points here.</p>
281
- <ul class='list-unstyled d-flex flex-wrap gap-3'>
282
- <li><a href='down/fountain'>fountain</a></li>
283
- <li><a href='down/goldrush'>goldrush</a></li>
284
- <li><a href='down/houston'>houston</a></li>
285
- <li><a href='down/autopilot'>autopilot</a></li>
286
- <li><a href='down/design'>design</a></li>
287
- </ul>
209
+ </section>
210
+
211
+ <section class='design-section' id='theme'>
212
+ <h2>Palettes</h2>
213
+ <button type='button' class='btn btn-outline theme-primary' data-controller='scheme' data-action='scheme#rotate'
214
+ data-scheme-themes-value='["bootstrap","dawn","dracula","gruvbox","monokai","nord","one_dark","solarized","tokyo_night"]'
215
+ data-scheme-path-value='theme' data-scheme-storage-value='recourse-scheme'>
216
+ <span class='recourse-scheme-light'><i class='bi bi-moon-fill'></i> Another palette, dark</span>
217
+ <span class='recourse-scheme-dark'><i class='bi bi-sun-fill'></i> Another palette, light</span>
218
+ </button>
219
+ </section>
220
+
221
+ <section class='design-section' id='favicon'>
222
+ <h2>Icons</h2>
223
+ <p class='fg-2'>Every mark an app is known by: the drawing under <code>/logo</code>, and what a tab, a phone and a manifest each ask for under <code>/favicon</code>. The pink one is a local machine's.</p>
224
+ <div class='table-responsive'>
225
+ <table class='table table-hover mx-auto' style='max-width: 60rem'>
226
+ <thead><tr><th scope='col'>Logo</th><th scope='col'>App</th><th scope='col'>.svg</th><th scope='col'>-dev.svg</th><th scope='col'>-96.png</th><th scope='col'>-180.png</th><th scope='col'>-192.png</th><th scope='col'>-512.png</th><th scope='col'>.ico</th><th scope='col'>.webmanifest</th></tr></thead>
227
+ <tbody>
228
+ <tr><td><img class='design-logo' src='logo/houseaccount.svg' alt=''></td><th scope='row'>houseaccount</th><td><img src='favicon/houseaccount.svg' width='24' alt=''></td><td><img src='favicon/houseaccount-dev.svg' width='24' alt=''></td><td><img src='favicon/houseaccount-96.png' width='24' alt=''></td><td><img src='favicon/houseaccount-180.png' width='24' alt=''></td><td><img src='favicon/houseaccount-192.png' width='24' alt=''></td><td><img src='favicon/houseaccount-512.png' width='24' alt=''></td><td><a href='favicon/houseaccount.ico'>ico</a></td><td><a href='favicon/houseaccount.webmanifest'>manifest</a></td></tr>
229
+ <tr><td><img class='design-logo' src='logo/fountain.svg' alt=''></td><th scope='row'>fountain</th><td><img src='favicon/fountain.svg' width='24' alt=''></td><td><img src='favicon/fountain-dev.svg' width='24' alt=''></td><td><img src='favicon/fountain-96.png' width='24' alt=''></td><td><img src='favicon/fountain-180.png' width='24' alt=''></td><td><img src='favicon/fountain-192.png' width='24' alt=''></td><td><img src='favicon/fountain-512.png' width='24' alt=''></td><td><a href='favicon/fountain.ico'>ico</a></td><td><a href='favicon/fountain.webmanifest'>manifest</a></td></tr>
230
+ <tr><td><img class='design-logo' src='logo/goldrush.svg' alt=''></td><th scope='row'>goldrush</th><td><img src='favicon/goldrush.svg' width='24' alt=''></td><td><img src='favicon/goldrush-dev.svg' width='24' alt=''></td><td><img src='favicon/goldrush-96.png' width='24' alt=''></td><td><img src='favicon/goldrush-180.png' width='24' alt=''></td><td><img src='favicon/goldrush-192.png' width='24' alt=''></td><td><img src='favicon/goldrush-512.png' width='24' alt=''></td><td><a href='favicon/goldrush.ico'>ico</a></td><td><a href='favicon/goldrush.webmanifest'>manifest</a></td></tr>
231
+ <tr><td><img class='design-logo' src='logo/houston.svg' alt=''></td><th scope='row'>houston</th><td><img src='favicon/houston.svg' width='24' alt=''></td><td><img src='favicon/houston-dev.svg' width='24' alt=''></td><td><img src='favicon/houston-96.png' width='24' alt=''></td><td><img src='favicon/houston-180.png' width='24' alt=''></td><td><img src='favicon/houston-192.png' width='24' alt=''></td><td><img src='favicon/houston-512.png' width='24' alt=''></td><td><a href='favicon/houston.ico'>ico</a></td><td><a href='favicon/houston.webmanifest'>manifest</a></td></tr>
232
+ <tr><td><img class='design-logo' src='logo/design.svg' alt=''></td><th scope='row'>design</th><td><img src='favicon/design.svg' width='24' alt=''></td><td><img src='favicon/design-dev.svg' width='24' alt=''></td><td><img src='favicon/design-96.png' width='24' alt=''></td><td><img src='favicon/design-180.png' width='24' alt=''></td><td><img src='favicon/design-192.png' width='24' alt=''></td><td><img src='favicon/design-512.png' width='24' alt=''></td><td><a href='favicon/design.ico'>ico</a></td><td><a href='favicon/design.webmanifest'>manifest</a></td></tr>
233
+ <tr><td><img class='design-logo' src='logo/autopilot.svg' alt=''></td><th scope='row'>autopilot</th><td><img src='favicon/autopilot.svg' width='24' alt=''></td><td><img src='favicon/autopilot-dev.svg' width='24' alt=''></td><td><img src='favicon/autopilot-96.png' width='24' alt=''></td><td><img src='favicon/autopilot-180.png' width='24' alt=''></td><td><img src='favicon/autopilot-192.png' width='24' alt=''></td><td><img src='favicon/autopilot-512.png' width='24' alt=''></td><td><a href='favicon/autopilot.ico'>ico</a></td><td><a href='favicon/autopilot.webmanifest'>manifest</a></td></tr>
234
+ </tbody>
235
+ </table>
236
+ </div>
288
237
  </section>
289
238
  </main>
290
239
 
291
- <footer class='container-fluid px-3 py-4 small fg-2 d-flex flex-wrap gap-3'>
240
+ <footer class='container-fluid px-3 py-4 small fg-2 d-flex flex-wrap justify-content-center gap-3'>
292
241
  <span>The <code>houseaccount</code> gem draws all of this in a Rails app.</span>
293
242
  <a href='https://github.com/HouseAccountEng/design'>Source</a>
294
243
  <a href='https://rubydoc.info/gems/houseaccount'>Reference</a>
@@ -2,8 +2,9 @@ module HouseAccount
2
2
  module Helpers
3
3
  # The page of a signup flow: the mark over the wall, a title, a line, one card, the way out.
4
4
  module Flows
5
- # How wide the card is unless a page says otherwise: one column of a form, on a desktop.
6
- WIDTH = '30rem'
5
+ # How wide the card is unless a page says otherwise: as wide as a thread, a table or a
6
+ # contract wants. A page asking one question says a narrower one.
7
+ WIDTH = '75rem'
7
8
 
8
9
  # Draws the page around the card's content, standing on the wall: the mark linking to
9
10
  # `logo` over what the view said in `content_for` — its `:title`, its `:subtitle`, how
@@ -1,4 +1,4 @@
1
1
  module HouseAccount
2
2
  # Version of the gem, read by the gemspec and by hosts checking compatibility.
3
- VERSION = '0.11.0'
3
+ VERSION = '0.12.0'
4
4
  end