studio-engine 0.77.0 → 0.77.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0c579a6d057a79eb540fee2347d6000c6c5af80273e61efdbd2e1d8eda173214
4
- data.tar.gz: 726c8217e6f23e277af7f3fcc215885d7bfed504ee2a215b574aa5775986ffad
3
+ metadata.gz: 6e39db0e8ae3fa259b3e0869c0e33099d1fd840192e9da33ae7d43bc37ce07d7
4
+ data.tar.gz: 171d736d4f5a6669446e718130d029499d0170b4102a2e76d5990193feac5901
5
5
  SHA512:
6
- metadata.gz: 72b688c3d92118f08ea7ba2263db3973fedeec0d16d07d9f45296c9c68fc581e6f5d56f30eb6d3375f0dedff9d1330de6ed992f5080995ddb44aa0ec6b79eae1
7
- data.tar.gz: cf4ed66373933628dccd7eeb8e59164da68cfcc25f3407befff234ebd18ce2793a2d60bfb71daae219ec8980f5f7ada6b3b34f092697d4dbcb8894f451acd162
6
+ metadata.gz: 1a3bd81ed22cc40b1d98864b469e60d97b9e8a4e2178eb518bd409cafbfe2b37c8171dc3daaf064bf3a0a5f432ac8fd758c23288c607ca9d1631bec81f8f5e10
7
+ data.tar.gz: 4023eff14f61f6c8bf3be70fc0fb69d5990ff62fe9cb968f652b9cd11b450bbe85b6686d35b46eba2e76b2fddb7d17de895751a2ecb67a4483238352a6106ca9
data/CHANGELOG.md CHANGED
@@ -4,6 +4,68 @@ The format is [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). This pro
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## 0.77.2 — 2026-09-28
8
+
9
+ ### Fixed
10
+
11
+ - **The browser lab stopped writing per-request state into the engine's process-wide
12
+ config.** `E2eLabController#bar_stack` set up the link sidebar by assigning
13
+ `Studio.sidebar_sections` from `?sidebar=1`, and that accessor is a
14
+ `mattr_accessor` — one slot for the whole Puma process. So one request armed the
15
+ sidebar for every request after it: measured at `a73edfe`, after a single
16
+ `GET /lab/bar_stack?sidebar=1`, `/lab/toast_over_banner` served 2 link-sidebar
17
+ triggers, 2 slide-out panels and `--nav-h: 145px` against 0, 0 and 125px before it,
18
+ on a page that declares no sections. **No shipped engine code changed**; the lab is
19
+ the dummy test app, which is in no gem (`spec.files` has never included `test/`).
20
+ What changed is what the browser lane measures. The dummy host now declares the
21
+ accessor once at boot, in the callable form `docs/NEW_APP_SETUP.md` shows, reading
22
+ what the current request declared through a `before_action` on every lab action —
23
+ so `?sidebar=1` works on any lab page, carries nowhere, and
24
+ `Studio::SidebarSections.resolve` stays on the path.
25
+ - The lane never went red for it. Playwright walks `e2e/` in file-name order and
26
+ `nav_collapse.spec.js`, which clears the slot, sorts between the contaminator and
27
+ the victim; run those two adjacent and every assertion still passes. So
28
+ `playwright.config.js`'s comment claiming the lab pages are stateless was false
29
+ and was arming whoever next raised `workers` above 1. It now names the incident
30
+ and the guard instead of asserting itself.
31
+ - `test/integration/e2e_lab_isolation_test.rb` holds the seam and more than this one
32
+ accessor: it enumerates every lab GET from the router and every `Studio` accessor
33
+ that has a writer, walks each route bare and with every knob the lane turns, and
34
+ diffs the values either side.
35
+
36
+ ### Added
37
+
38
+ - **The header's reserved balance column has a spec.** `layouts/_navbar` gives the
39
+ right column a hard `width: min(14rem, 46vw)` when a host passes `balance_html`
40
+ (`.user-nav-col`) and the same number as a `max-width` when it does not
41
+ (`.user-nav-fit`). All five phone-width header specs drove the fit path;
42
+ `/lab/bar_stack` has carried a `?balance=1` knob since it was written and nothing
43
+ turned it. Measured across 320/360/375/390/412/430, the two paths are identical to
44
+ a tenth of a pixel — the fit column is already pinned to its cap at every phone
45
+ width — so this is coverage over correct code, not a fix. It is not redundant:
46
+ the two classes are separate declarations at three media bands each, and mutating
47
+ `.user-nav-col` to a bare 20rem left all five existing specs green and reddened
48
+ only this one.
49
+
50
+ ## 0.77.1 — 2026-09-27
51
+
52
+ ### Fixed
53
+
54
+ - **The engine header fits a phone.** `.user-nav-col` / `.user-nav-fit` capped their
55
+ two phone bands at a constant `14rem`/`15rem` — 224px is 57% of a 390px screen — on
56
+ a `flex-shrink-0` column, leaving the left column 166px for a 48px logo, its gap,
57
+ 32px of padding and the app's name. Every flex item defaults to `min-width: auto`,
58
+ so the name could not truncate either: it drew across the gap and on top of the user
59
+ column beside it. The bands are now `min(14rem, 46vw)` and `min(15rem, 46vw)`, with
60
+ `min-w-0` on each flex item between the nav row and the title and `truncate` on the
61
+ two title spans. `min()` resolves to the plain rem at ~487px and ~522px, so the
62
+ 768px band and every desktop width are unchanged; below ~344px the app name
63
+ truncates rather than spilling.
64
+ - **Consumers that render `layouts/_navbar` unforked inherit this on upgrade** —
65
+ `mcritchie-industries` and `acquisition-studio`. `mcritchie-studio` inlines its own
66
+ `<header>` and `turf-monster` forks the partial and declares its own
67
+ `.user-nav-col` widths, so each adopts the change separately.
68
+
7
69
  ## 0.77.0 — 2026-09-26
8
70
 
9
71
  ### Added
@@ -62,13 +62,44 @@
62
62
  class="nav-shell <%= is_preview ? 'bg-page' : "#{'vt-pinned-header ' if pin_header}sticky top-0 z-50 bg-page transition-shadow duration-300" %>"
63
63
  :class="scrolled && 'shadow-lg border-b border-subtle is-scrolled'">
64
64
  <style>
65
- .user-nav-col { width: 14rem; }
65
+ /* THE PHONE STEP IS A SHARE OF THE VIEWPORT, NOT A CONSTANT, and that is the
66
+ whole width fix. 14rem is 224px — 57% of a 390px screen — handed to a
67
+ flex-shrink-0 column, so the left column was left 166px for a 48px logo,
68
+ a 4px gap, 32px of padding and whatever the app is called. MEASURED on
69
+ /lab/bar_stack?signed_in=1 at 390x844, app_name "McRitchie Industries":
70
+ the title's own box ran to x=175.3 inside a column whose border box ends
71
+ at x=166, and "Industries" painted ON TOP of the wallet address in the
72
+ column beside it. documentElement.scrollWidth was 390 against a
73
+ clientWidth of 390 the entire time — the page did not scroll sideways,
74
+ so every document-level check of this header was green while the header
75
+ was visibly broken.
76
+
77
+ min() rather than a new breakpoint: the cap still resolves to 14rem on
78
+ anything at or above ~487px, so this band's desktop-side behaviour is
79
+ byte-identical and only the phone widths move. 46vw is not a taste
80
+ value — it is the largest share that still leaves the left column the
81
+ 191px a 48px logo, its gap, its padding and a ten-character word need at
82
+ 360px, the narrowest mainstream Android. Below that the title truncates
83
+ (see min-w-0 + truncate on the markup) instead of spilling.
84
+
85
+ BOTH LINES, and that is not redundancy. .user-nav-col is a hard width
86
+ (a host passing balance_html reserves the seat) and .user-nav-fit is a
87
+ cap (no balance, so the column hugs its content). They are two different
88
+ properties and a fix to one leaves the other exactly as broken. */
89
+ .user-nav-col { width: min(14rem, 46vw); }
66
90
  /* No balance content → no reserved column. The nav hugs its icons and
67
91
  name instead of floating in the balance's empty seat. max-width steps
68
92
  mirror the col's clamps: the item is flex-shrink-0, so without them a
69
93
  long nowrap username sizes the column past a narrow viewport. */
70
- .user-nav-fit { max-width: 14rem; }
71
- @media (min-width: 400px) { .user-nav-col { width: 15rem; } .user-nav-fit { max-width: 15rem; } }
94
+ .user-nav-fit { max-width: min(14rem, 46vw); }
95
+ /* THE SAME SHARE IN THE NEXT BAND UP, and leaving it out was measurably
96
+ worse than not fixing the first one. With only the base band capped, a
97
+ 412px screen (Pixel-class, and the 400px band's own territory) gave the
98
+ title 84px while a 390px screen gave it 107 — a WIDER phone showing LESS
99
+ of the app's name. Monotone or it is not fixed. min(15rem, 46vw) resolves
100
+ to the plain 15rem at ~522px and up, so everything above this band's
101
+ phone edge is unchanged. */
102
+ @media (min-width: 400px) { .user-nav-col { width: min(15rem, 46vw); } .user-nav-fit { max-width: min(15rem, 46vw); } }
72
103
  @media (min-width: 768px) { .user-nav-col { width: 20rem; } .user-nav-fit { max-width: 20rem; } }
73
104
  /* The COLLAPSE band table used to live here, which meant only an app
74
105
  rendering THIS partial got it. Three of five apps fork the navbar, so each
@@ -88,16 +119,27 @@
88
119
  </style>
89
120
  <div class="nav-row flex items-center">
90
121
  <%# Left side: logo + nav %>
91
- <div class="flex-1 px-4">
92
- <div class="flex items-center gap-6">
93
- <%= link_to root_path, class: "nav-logo-link inline-flex items-center gap-3 group" do %>
122
+ <%# min-w-0 THREE TIMES, on every flex item between the row and the title.
123
+ A flex item's default min-width is auto, which floors it at its own
124
+ min-content — so ONE of these left out puts the floor back and the
125
+ title spills across the gap again. The chain is: row item (.flex-1) ->
126
+ its inner flex -> the logo link. The <h1> is the fourth link and carries
127
+ its own min-w-0 below. %>
128
+ <div class="flex-1 min-w-0 px-4">
129
+ <div class="flex items-center gap-6 min-w-0">
130
+ <%= link_to root_path, class: "nav-logo-link inline-flex items-center gap-3 group min-w-0" do %>
94
131
  <% if logo_path %>
95
132
  <%# No w-*/h-* utility here: .nav-shell .nav-logo sizes it off --nav-p.
96
133
  transition-transform, NOT transition-all — the hover lift still
97
134
  eases, while width/height follow the finger with no clock. %>
98
135
  <img src="<%= logo_path %>" alt="<%= Studio.app_name %>" class="nav-logo rounded-full shadow-lg <%= "group-hover:scale-105 transition-transform duration-300" unless is_preview %>">
99
136
  <% end %>
100
- <h1 class="nav-title font-extrabold text-heading tracking-tight"><span><%= prefix %></span><span class="text-primary"><%= last_word %></span></h1>
137
+ <%# truncate on the SPANS, not the h1. .nav-title is itself a flex
138
+ container (a column below 768px, a baseline row above), so the
139
+ overflow that has to be clipped belongs to each word's own box —
140
+ `truncate` on the h1 would clip the flex CONTAINER and leave the
141
+ spans drawing outside it, which is the bug rather than the fix. %>
142
+ <h1 class="nav-title font-extrabold text-heading tracking-tight min-w-0"><span class="truncate"><%= prefix %></span><span class="text-primary truncate"><%= last_word %></span></h1>
101
143
  <% end %>
102
144
  <%# Desktop nav — apps should override this partial to add links here %>
103
145
  <nav class="hidden md:flex items-center gap-4">
@@ -41,21 +41,38 @@
41
41
  --nav-title-lead-size: calc(1.5rem - 0.35rem * var(--nav-p));
42
42
  }
43
43
 
44
+ /* THE USER-COLUMN WIDTH STEPS, re-keyed on the wrapper for the same reason
45
+ the --nav-p sizes above are: the shipped rules live in media queries, which
46
+ cannot fire for a CONTAINER at a fixed viewport width.
47
+
48
+ PERCENT HERE, vw THERE, AND THEY ARE THE SAME NUMBER. layouts/_navbar caps
49
+ the two phone bands at min(<rem>, 46vw). A literal 46vw inside a 390px
50
+ preview box on a 1400px monitor resolves to 644px, which would make the
51
+ preview show a header no phone has — so the share is expressed against the
52
+ CONTAINING BLOCK instead, which in this preview is the navbar row, i.e. the
53
+ simulated device width. Retune the cap in _navbar and retune these, or the
54
+ preview starts lying about the one dimension it exists to show.
55
+
56
+ REMOVED, 2026-09-27: three `.username-cap` rules, at 5/6/7rem. No element
57
+ in this engine or in any consuming app has ever carried that class —
58
+ components/_user_nav truncates the name with `truncate` and a min-w-0
59
+ parent instead. They were dead the day they were written and they read, to
60
+ the next person sizing this header, like a cap that was already in force.
61
+ (turf-monster's app/views/admin/navbar.html.erb carries the same three dead
62
+ rules; that is its own repo's to drop.) */
63
+
44
64
  /* Tiny (< 400px) */
45
65
  .navbar-preview.bp-tiny .nav-logo-link { gap: 0.25rem !important; }
46
- .navbar-preview.bp-tiny .user-nav-col { width: 14rem !important; }
47
- .navbar-preview.bp-tiny .user-nav-fit { max-width: 14rem !important; }
48
- .navbar-preview.bp-tiny .username-cap { max-width: 5rem !important; }
66
+ .navbar-preview.bp-tiny .user-nav-col { width: min(14rem, 46%) !important; }
67
+ .navbar-preview.bp-tiny .user-nav-fit { max-width: min(14rem, 46%) !important; }
49
68
 
50
69
  /* Small (400-767px) */
51
- .navbar-preview.bp-small .user-nav-col { width: 15rem !important; }
52
- .navbar-preview.bp-small .user-nav-fit { max-width: 15rem !important; }
53
- .navbar-preview.bp-small .username-cap { max-width: 6rem !important; }
70
+ .navbar-preview.bp-small .user-nav-col { width: min(15rem, 46%) !important; }
71
+ .navbar-preview.bp-small .user-nav-fit { max-width: min(15rem, 46%) !important; }
54
72
 
55
- /* Desktop (768px+) */
73
+ /* Desktop (768px+) — a bare rem, exactly as the shipped band declares it. */
56
74
  .navbar-preview.is-desktop .user-nav-col { width: 20rem !important; }
57
75
  .navbar-preview.is-desktop .user-nav-fit { max-width: 20rem !important; }
58
- .navbar-preview.is-desktop .username-cap { max-width: 7rem !important; }
59
76
 
60
77
  /* Scrolled state. The size half of this used to be TWELVE !important rules
61
78
  restating every collapsed value; the toggle now just sets --nav-p: 1 on
@@ -1,3 +1,3 @@
1
1
  module Studio
2
- VERSION = "0.77.0"
2
+ VERSION = "0.77.2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: studio-engine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.77.0
4
+ version: 0.77.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex McRitchie
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-09-27 00:00:00.000000000 Z
11
+ date: 2026-09-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails