studio-engine 0.103.0.rc1 → 0.103.0.rc2
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 +4 -4
- data/CHANGELOG.md +39 -0
- data/app/components/studio/badge_component.rb +4 -3
- data/app/views/components/_link_sidebar.html.erb +2 -2
- data/app/views/studio/emails/_row.html.erb +1 -1
- data/app/views/studio/emails/show.html.erb +1 -1
- data/app/views/style/_tasks.html.erb +1 -1
- data/lib/studio/theme_resolver.rb +36 -2
- data/lib/studio/version.rb +1 -1
- data/tailwind/studio.tailwind.config.js +3 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 792f0e16ad48572393e4e8cf22f51d497e832af869b0d1bfe6dd5be6ac8da058
|
|
4
|
+
data.tar.gz: c862691168c2c8e782d4b4ec7d6d956058494b717fd2d4b2757f6d9f2bd60148
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5d7b0b148093fca45e7ded99ad0056fc6a8a6e5dc698f1b85a4032414ae9a2a92b92ab94189ba3f7fc287b45fc40b1796e0b4807b910b08a99403b202d965c4a
|
|
7
|
+
data.tar.gz: 5c37ecd0f4c1f526cebe802cfc46a0dda47c4be3b1558ad57d2648de3fbfbf29fa122267551b5673f33000bf1edbaef0ba2a7154ab7f127c36fb099a14487015
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,45 @@ The format is [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). This pro
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **`--color-primary-ink` and `text-primary-ink`: the primary colour as chip
|
|
10
|
+
text.** The theme resolver derives it per theme the way it derives the
|
|
11
|
+
danger, warning and success inks: the configured primary, shaded until it
|
|
12
|
+
clears WCAG AA 4.5:1 on every surface and on its own 10%, 15% and 20% tints.
|
|
13
|
+
`text-primary` and `--color-primary` stay the brand colour.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- **Primary chips are painted in the primary colour and clear AA in both
|
|
18
|
+
themes.** `Studio::BadgeComponent`'s `tone: :primary` drew heading-coloured
|
|
19
|
+
text (white in dark, near-black in light), and its `scheme: "primary"`, the
|
|
20
|
+
Marketing chip on `/admin/emails` and the sidebar's ADMIN chip drew the raw
|
|
21
|
+
primary, 2.2:1 to 3.6:1 on its tint. All of them now draw `text-primary-ink`.
|
|
22
|
+
A host that copies the tone's class string (the hub's `status_tone`) changes
|
|
23
|
+
when it adopts the class.
|
|
24
|
+
- **Every role ink clears AA on its 10%, 15% and 20% tints, as a browser
|
|
25
|
+
paints them.** The apps put the inks on the stronger tints too (turf's
|
|
26
|
+
"Entered" badge is `bg-primary/15`; the hub's workflow and verdict chips are
|
|
27
|
+
`bg-success/20 text-success-ink` and `bg-warning/20 text-warning-ink`), where
|
|
28
|
+
an ink tuned to the 10% chip read as low as 3.83:1 (default warning, dark, on
|
|
29
|
+
20%). The search now counts 0.10, 26/255 (how Chromium composites a 10%
|
|
30
|
+
fill), 0.15 and 0.20, each also one unit off in every channel, because 8-bit
|
|
31
|
+
compositing rounds (Chromium painted a 20% danger tint one unit lighter than
|
|
32
|
+
the blend, taking a 4.51:1 ink to 4.47:1). The inks darken in light and
|
|
33
|
+
lighten in dark. Default theme, 0.102.0 to this release:
|
|
34
|
+
|
|
35
|
+
| Ink | Dark | Light |
|
|
36
|
+
|---|---|---|
|
|
37
|
+
| primary (new) | `#BDB7FE` | `#58519D` |
|
|
38
|
+
| success | `#8EB791` to `#96BC99` | `#2E6C32` to `#2A622D` |
|
|
39
|
+
| warning | `#FF966C` to `#FFAE8D` | `#994A2B` to `#8F4528` |
|
|
40
|
+
| danger | `#F58F8F` to `#F79E9E` | `#AC3131` to `#9E2D2D` |
|
|
41
|
+
|
|
42
|
+
A configured role colour moves the same way; a configured colour that
|
|
43
|
+
already clears every tint (mcritchie-industries' yellow warning) keeps its
|
|
44
|
+
exact hex.
|
|
45
|
+
|
|
7
46
|
## 0.103.0 — 2026-10-10
|
|
8
47
|
|
|
9
48
|
### Added
|
|
@@ -20,7 +20,8 @@ module Studio
|
|
|
20
20
|
# rest of the page uses for that status. Tokens only, so it reads in both themes.
|
|
21
21
|
#
|
|
22
22
|
# scheme: is the palette the components/badge partial took (SCHEMES), including
|
|
23
|
-
# the stage-* pipeline ladder
|
|
23
|
+
# the stage-* pipeline ladder. Its "primary" draws the primary ink; the rest
|
|
24
|
+
# render exactly what that partial rendered.
|
|
24
25
|
# An unknown scheme renders FALLBACK, as the partial did.
|
|
25
26
|
#
|
|
26
27
|
# Pass tone: or scheme:, not both. Neither renders the neutral scheme.
|
|
@@ -34,7 +35,7 @@ module Studio
|
|
|
34
35
|
success: "bg-success/10 text-success-ink border-success/40",
|
|
35
36
|
warning: "bg-warning/10 text-warning-ink border-warning/40",
|
|
36
37
|
danger: "bg-danger/10 text-danger-ink border-danger/40",
|
|
37
|
-
primary: "bg-primary/10 text-
|
|
38
|
+
primary: "bg-primary/10 text-primary-ink border-primary/40",
|
|
38
39
|
muted: "bg-surface-alt text-muted border-subtle"
|
|
39
40
|
}.freeze
|
|
40
41
|
|
|
@@ -44,7 +45,7 @@ module Studio
|
|
|
44
45
|
"warning" => "bg-yellow-500/10 text-yellow-400 border-yellow-500/30",
|
|
45
46
|
"info" => "bg-blue-500/10 text-blue-500 border-blue-500/30",
|
|
46
47
|
"violet" => "bg-violet/10 text-violet border-violet/30",
|
|
47
|
-
"primary" => "bg-primary/10 text-primary border-primary/30",
|
|
48
|
+
"primary" => "bg-primary/10 text-primary-ink border-primary/30",
|
|
48
49
|
"orange" => "bg-orange-500/10 text-orange-500 border-orange-500/30",
|
|
49
50
|
"emerald" => "bg-emerald-500/10 text-emerald-500 border-emerald-500/30",
|
|
50
51
|
"gray" => "bg-gray-500/10 text-gray-400 border-gray-500/30",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
<div class="px-4 pt-4 pb-1 label-upper font-bold text-muted flex items-center gap-2">
|
|
28
28
|
<span><%= section[:title] %></span>
|
|
29
29
|
<% if section[:admin] %>
|
|
30
|
-
<span class="rounded border border-primary/20 bg-primary/10 px-1.5 py-0.5 text-[10px] font-mono text-primary">ADMIN</span>
|
|
30
|
+
<span class="rounded border border-primary/20 bg-primary/10 px-1.5 py-0.5 text-[10px] font-mono text-primary-ink">ADMIN</span>
|
|
31
31
|
<% end %>
|
|
32
32
|
</div>
|
|
33
33
|
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
<% if sidebar_admin && sections.any? { |section| section[:admin] } %>
|
|
93
93
|
<div class="px-4 pt-4 pb-1 label-upper font-bold text-muted flex items-center gap-2">
|
|
94
94
|
<span>Geo</span>
|
|
95
|
-
<span class="rounded border border-primary/20 bg-primary/10 px-1.5 py-0.5 text-[10px] font-mono text-primary">ADMIN</span>
|
|
95
|
+
<span class="rounded border border-primary/20 bg-primary/10 px-1.5 py-0.5 text-[10px] font-mono text-primary-ink">ADMIN</span>
|
|
96
96
|
</div>
|
|
97
97
|
<%= render "components/geo_signpost", variant: :sidebar, close_action: close_action %>
|
|
98
98
|
<% end %>
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
<%= link_to entry.label, admin_email_path(entry.key),
|
|
86
86
|
class: "font-semibold text-heading hover:text-primary underline-offset-2 hover:underline" %>
|
|
87
87
|
<% if entry.marketing? %>
|
|
88
|
-
<span class="badge bg-primary/10 text-primary border-primary/30 ml-1.5 whitespace-nowrap">Marketing</span>
|
|
88
|
+
<span class="badge bg-primary/10 text-primary-ink border-primary/30 ml-1.5 whitespace-nowrap">Marketing</span>
|
|
89
89
|
<% end %>
|
|
90
90
|
<% if entry.description.present? %>
|
|
91
91
|
<p class="text-sm text-body mt-0.5 max-w-md"><%= entry.description %></p>
|
|
@@ -103,7 +103,7 @@
|
|
|
103
103
|
</div>
|
|
104
104
|
|
|
105
105
|
<div class="flex flex-wrap items-center gap-2 mt-3">
|
|
106
|
-
<span class="badge <%= @entry.marketing? ? "bg-primary/10 text-primary border-primary/30" : "bg-inset text-muted border-subtle" %> whitespace-nowrap">
|
|
106
|
+
<span class="badge <%= @entry.marketing? ? "bg-primary/10 text-primary-ink border-primary/30" : "bg-inset text-muted border-subtle" %> whitespace-nowrap">
|
|
107
107
|
<%= @entry.type.to_s.titleize %>
|
|
108
108
|
</span>
|
|
109
109
|
<span class="<%= badge_class %> whitespace-nowrap"><%= badge_label %></span>
|
|
@@ -124,7 +124,7 @@
|
|
|
124
124
|
</div>
|
|
125
125
|
<% end %>
|
|
126
126
|
<% chrome_kickoff = capture do %>
|
|
127
|
-
<span class="inline-flex items-center gap-1 rounded border border-primary/30 bg-primary/10 px-1.5 py-0.5 text-2xs font-semibold uppercase tracking-wide text-primary">kickoff slot</span>
|
|
127
|
+
<span class="inline-flex items-center gap-1 rounded border border-primary/30 bg-primary/10 px-1.5 py-0.5 text-2xs font-semibold uppercase tracking-wide text-primary-ink">kickoff slot</span>
|
|
128
128
|
<% end %>
|
|
129
129
|
<%
|
|
130
130
|
# Per-column count_class colours (raw classes, the task_stage_count_classes shape),
|
|
@@ -117,6 +117,10 @@ module Studio
|
|
|
117
117
|
"--color-danger-ink" => status_ink(danger, surfaces, direction: :lighten),
|
|
118
118
|
"--color-warning-ink" => status_ink(warning, surfaces, direction: :lighten),
|
|
119
119
|
"--color-success-ink" => status_ink(success, surfaces, direction: :lighten),
|
|
120
|
+
# The primary role as chip TEXT (`bg-primary/10 text-primary-ink`): the
|
|
121
|
+
# brand hue, shaded per theme until it clears AA on the surfaces and on
|
|
122
|
+
# its own tint. --color-primary itself stays the brand colour.
|
|
123
|
+
"--color-primary-ink" => status_ink(primary, surfaces, direction: :lighten),
|
|
120
124
|
"--color-accent" => colors[:accent] || "#F72585"
|
|
121
125
|
}.merge(fill_vars(primary, warning, danger))
|
|
122
126
|
end
|
|
@@ -165,6 +169,16 @@ module Studio
|
|
|
165
169
|
# How strong a status role's tint is where its ink is read on it: the
|
|
166
170
|
# `bg-<role>/10 text-<role>-ink` badge and flash-panel pattern.
|
|
167
171
|
STATUS_TINT = 0.10
|
|
172
|
+
# Every tint strength a role's ink is read on. The 10% chip, as written and
|
|
173
|
+
# as an 8-bit alpha channel holds it (26/255, a little stronger), and the
|
|
174
|
+
# 15% and 20% tints the apps also put an ink on: a selected or "Entered"
|
|
175
|
+
# badge (`bg-primary/15`), the hub's workflow and verdict chips
|
|
176
|
+
# (`bg-success/20 text-success-ink`, `bg-warning/20 text-warning-ink`),
|
|
177
|
+
# turf's signer roster (`bg-danger/15 text-danger-ink`). A stronger tint
|
|
178
|
+
# sits closer to the ink, so an ink tuned to the 10% chip alone read 3.89:1
|
|
179
|
+
# on a 20% one (default warning, dark). 0.15 and 0.20 are the stronger of
|
|
180
|
+
# each written alpha and its 8-bit value (38/255 is weaker, 51/255 equal).
|
|
181
|
+
TINT_ALPHAS = [STATUS_TINT, (STATUS_TINT * 255).round / 255.0, 0.15, 0.20].freeze
|
|
168
182
|
|
|
169
183
|
# A status ink lands on the page surfaces AND on its own role's tint over
|
|
170
184
|
# each of them (the `bg-warning/10 text-warning-ink` badge). The tint is
|
|
@@ -172,9 +186,28 @@ module Studio
|
|
|
172
186
|
# to the bare surfaces alone comes out below AA inside its own badge
|
|
173
187
|
# (default theme: warning 3.91:1 dark, success 4.00:1 dark, danger 4.10:1
|
|
174
188
|
# light and 4.18:1 dark). Counting the tints as surfaces closes that.
|
|
189
|
+
#
|
|
190
|
+
# The tint is counted at every strength in TINT_ALPHAS. Chromium composites
|
|
191
|
+
# a 10% fill at 26/255, a little stronger than 0.10, and an ink tuned to
|
|
192
|
+
# 0.10 alone measured 4.48:1 on the painted pixels (danger, dark, on a
|
|
193
|
+
# #141516 base).
|
|
194
|
+
#
|
|
195
|
+
# Each tint is also counted one unit lighter and one unit darker in every
|
|
196
|
+
# channel. A browser composites in 8 bits and rounds the fill's share and
|
|
197
|
+
# the surface's share separately, so a painted tint can sit one unit off
|
|
198
|
+
# the exact blend: the default danger at 20% over #3C3853 blends to
|
|
199
|
+
# #5F3A50 and Chromium paints #603B50, which took an ink graded 4.51:1 here
|
|
200
|
+
# to 4.47:1 on screen. Contrast moves with luminance, and luminance with
|
|
201
|
+
# each channel, so the two all-channel neighbours bound every rounding.
|
|
175
202
|
def status_ink(role, surfaces, direction:)
|
|
176
|
-
tints = surfaces.map { |bg| ColorScale.blend(role, bg,
|
|
177
|
-
|
|
203
|
+
tints = TINT_ALPHAS.flat_map { |alpha| surfaces.map { |bg| ColorScale.blend(role, bg, alpha) } }
|
|
204
|
+
painted = tints.flat_map { |tint| [tint, nudge(tint, 1), nudge(tint, -1)] }
|
|
205
|
+
contrast_ink(role, direction: direction, start: 0.0, target: 4.5, against: surfaces + painted)
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# `hex` with every channel moved `units` (clamped to 0..255).
|
|
209
|
+
def nudge(hex, units)
|
|
210
|
+
ColorScale.rgb_to_hex(*ColorScale.hex_to_rgb(hex).map { |c| c + units })
|
|
178
211
|
end
|
|
179
212
|
|
|
180
213
|
# The lightest shade of `color` that carries a white label at AA: the
|
|
@@ -307,6 +340,7 @@ module Studio
|
|
|
307
340
|
"--color-danger-ink" => status_ink(danger, surfaces, direction: :darken),
|
|
308
341
|
"--color-warning-ink" => status_ink(warning, surfaces, direction: :darken),
|
|
309
342
|
"--color-success-ink" => status_ink(success, surfaces, direction: :darken),
|
|
343
|
+
"--color-primary-ink" => status_ink(primary, surfaces, direction: :darken),
|
|
310
344
|
"--color-accent" => colors[:accent] || "#F72585"
|
|
311
345
|
}.merge(fill_vars(primary, warning, danger))
|
|
312
346
|
end
|
data/lib/studio/version.rb
CHANGED
|
@@ -103,6 +103,9 @@ module.exports = {
|
|
|
103
103
|
'danger-ink': 'var(--color-danger-ink)',
|
|
104
104
|
'warning-ink': 'var(--color-warning-ink)',
|
|
105
105
|
'success-ink': 'var(--color-success-ink)',
|
|
106
|
+
// The primary role as chip text, derived the same way. text-primary
|
|
107
|
+
// stays the brand colour for links, icons and large text.
|
|
108
|
+
'primary-ink': 'var(--color-primary-ink)',
|
|
106
109
|
},
|
|
107
110
|
// The status-role FILLS: badge tints, flash panels, borders. Registered
|
|
108
111
|
// for backgrounds and borders ONLY (not `colors`), so that registering
|