studio-engine 0.80.0 → 0.81.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +20 -0
- data/app/assets/tailwind/studio_engine/engine.css +8 -2
- data/app/views/components/_admin_dropdown.html.erb +5 -1
- data/app/views/components/_user_nav.html.erb +5 -3
- data/app/views/style/_theme.html.erb +2 -2
- data/app/views/theme_settings/edit.html.erb +7 -0
- data/lib/studio/theme_resolver.rb +26 -10
- data/lib/studio/version.rb +1 -1
- 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: 3ba5fe314a5d1bbb6b2b95d12a2561bf3f87c2e302ced48eb365e2587c7ba7ee
|
|
4
|
+
data.tar.gz: de2c065be4ed44da716d10331c23edfda0ca08c05f333b0324457b860d4db073
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1eac79405823182fa089630acf41324de6238af3dead7f97136a97db2a0062f1443ae2538446cecace96bbe30655c3b889dbf1bba05478492d59c514bbcb3238
|
|
7
|
+
data.tar.gz: 56637c4be0db6c8701eaab6397bd6631f34f609ba986574d48382b458e52e415b3854598efc24b1894b1cfd43fdb8e81298754b57026657d8816a4e351a2bdad
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,26 @@ The format is [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). This pro
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.81.0 — 2026-09-30
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- **Default warning and danger buttons clear WCAG AA under their white label.**
|
|
12
|
+
While an app leaves its warning at the engine default `#FF7C47` (2.55:1 under
|
|
13
|
+
white), the resolver emits `--color-warning-fill` (`#B85933`, 4.65:1); while it
|
|
14
|
+
leaves danger at `#EF4444` (3.76:1), it emits `--color-danger-fill`
|
|
15
|
+
(`#D73D3D`, 4.54:1). `btn-warning` and `btn-danger` paint the fill and fall back
|
|
16
|
+
to `--color-warning` / `--color-danger`, so a configured colour paints as
|
|
17
|
+
before. The role colours themselves, their borders and rings, and the
|
|
18
|
+
`--color-warning-ink` / `--color-danger-ink` text inks are unchanged. Labels
|
|
19
|
+
stay white.
|
|
20
|
+
- **An admin sees one admin cog at every width.** `components/_user_nav` draws its
|
|
21
|
+
admin menu from `md` up only, as it already did the theme toggle: below `md` the
|
|
22
|
+
navbar's phone row draws the cog, so an admin's phone showed two.
|
|
23
|
+
`components/_admin_dropdown` takes an optional `display_class:` for this. Apps
|
|
24
|
+
that shadow `_user_nav` (mcritchie-studio, turf-monster, cyvasse) are unaffected
|
|
25
|
+
until they drop their copy.
|
|
26
|
+
|
|
7
27
|
## 0.80.0 — 2026-09-30
|
|
8
28
|
|
|
9
29
|
### Added
|
|
@@ -265,17 +265,23 @@ body.modal-open .studio-app-banner {
|
|
|
265
265
|
}
|
|
266
266
|
}
|
|
267
267
|
|
|
268
|
+
/* The fill is --color-danger-fill when the resolver emits one (only while the
|
|
269
|
+
app leaves its danger colour at the engine default, which fails AA under the
|
|
270
|
+
white label), otherwise the app's own --color-danger. */
|
|
268
271
|
@utility btn-danger {
|
|
269
272
|
@apply text-white;
|
|
270
|
-
background-color: var(--color-danger);
|
|
273
|
+
background-color: var(--color-danger-fill, var(--color-danger));
|
|
271
274
|
&:hover {
|
|
272
275
|
filter: brightness(0.9);
|
|
273
276
|
}
|
|
274
277
|
}
|
|
275
278
|
|
|
279
|
+
/* The fill is --color-warning-fill when the resolver emits one (only while the
|
|
280
|
+
app leaves its warning colour at the engine default, which fails AA under the
|
|
281
|
+
white label), otherwise the app's own --color-warning. */
|
|
276
282
|
@utility btn-warning {
|
|
277
283
|
@apply text-white;
|
|
278
|
-
background-color: var(--color-warning);
|
|
284
|
+
background-color: var(--color-warning-fill, var(--color-warning));
|
|
279
285
|
&:hover {
|
|
280
286
|
filter: brightness(0.9);
|
|
281
287
|
}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
<%# ADMIN chrome: renders only for admin? viewers. Signed-out and
|
|
2
2
|
non-admin visitors get nothing — this partial once leaked admin
|
|
3
3
|
links onto a public landing page. %>
|
|
4
|
+
<%# display_class: optional display utilities for the root. The user nav
|
|
5
|
+
passes "hidden md:block" because below md the navbar's phone row draws
|
|
6
|
+
its own cog, and two read as a double gear (engine-button-contrast-admin-cog). %>
|
|
7
|
+
<% display_class = local_assigns.fetch(:display_class, nil) %>
|
|
4
8
|
<% if respond_to?(:admin?) && admin? %>
|
|
5
|
-
<div x-data="{ open: false }" class="relative leading-none">
|
|
9
|
+
<div x-data="{ open: false }" class="<%= ["relative leading-none", display_class].compact.join(" ") %>">
|
|
6
10
|
<button @click="open = !open" class="flex text-secondary hover:text-heading transition" title="Admin">
|
|
7
11
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4">
|
|
8
12
|
<path stroke-linecap="round" stroke-linejoin="round" d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.325.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 0 1 1.37.49l1.296 2.247a1.125 1.125 0 0 1-.26 1.431l-1.003.827c-.293.241-.438.613-.43.992a7.723 7.723 0 0 1 0 .255c-.008.378.137.75.43.991l1.004.827c.424.35.534.955.26 1.43l-1.298 2.247a1.125 1.125 0 0 1-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.47 6.47 0 0 1-.22.128c-.331.183-.581.495-.644.869l-.213 1.281c-.09.543-.56.941-1.11.941h-2.594c-.55 0-1.019-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 0 1-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 0 1-1.369-.49l-1.297-2.247a1.125 1.125 0 0 1 .26-1.431l1.004-.827c.292-.24.437-.613.43-.991a6.932 6.932 0 0 1 0-.255c.007-.38-.138-.751-.43-.992l-1.004-.827a1.125 1.125 0 0 1-.26-1.43l1.297-2.247a1.125 1.125 0 0 1 1.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.086.22-.128.332-.183.582-.495.644-.869l.214-1.28Z" />
|
|
@@ -86,8 +86,10 @@
|
|
|
86
86
|
<div class="flex items-center gap-2 ml-auto self-end">
|
|
87
87
|
<%= studio_nav_slot.call(extra_icons_slot, extra_icons_html) %>
|
|
88
88
|
<%# Skipped when the link sidebar carries the admin menu — two cog
|
|
89
|
-
glyphs side by side read as a double gear.
|
|
90
|
-
|
|
89
|
+
glyphs side by side read as a double gear. Desktop only, like
|
|
90
|
+
the theme toggle: below md the navbar's phone row draws the cog,
|
|
91
|
+
so a second one here put two on an admin's phone. %>
|
|
92
|
+
<%= render "components/admin_dropdown", display_class: "hidden md:block" unless respond_to?(:studio_sidebar_replaces_admin_menu?) && studio_sidebar_replaces_admin_menu? %>
|
|
91
93
|
<%# Desktop only. Below md the engine navbar's phone row draws the
|
|
92
94
|
theme toggle, so a second one here put two on every phone. The
|
|
93
95
|
signed-out bar has always done it this way (layouts/_navbar). %>
|
|
@@ -219,7 +221,7 @@
|
|
|
219
221
|
<span class="<%= account_classes %>" data-nav-account x-bind:style="$store.devMode && 'background: lightgreen'"><%= account_inner %></span>
|
|
220
222
|
<% end %>
|
|
221
223
|
<% else %>
|
|
222
|
-
<%= render "components/admin_dropdown" unless respond_to?(:studio_sidebar_replaces_admin_menu?) && studio_sidebar_replaces_admin_menu? %>
|
|
224
|
+
<%= render "components/admin_dropdown", display_class: "hidden md:block" unless respond_to?(:studio_sidebar_replaces_admin_menu?) && studio_sidebar_replaces_admin_menu? %>
|
|
223
225
|
<%# Desktop only, as above: the phone row carries the toggle below md. %>
|
|
224
226
|
<span class="hidden md:flex" data-nav-theme-toggle="desktop"><%= render "components/theme_toggle_morph" %></span>
|
|
225
227
|
<div class="flex items-center gap-3 ml-auto">
|
|
@@ -191,8 +191,8 @@
|
|
|
191
191
|
d.setProperty('--color-cta', this.colors.primary);
|
|
192
192
|
d.setProperty('--color-cta-fill', this.colors.primary);
|
|
193
193
|
if (this.colors.success) d.setProperty('--color-success', this.colors.success);
|
|
194
|
-
if (this.colors.warning) d.setProperty('--color-warning', this.colors.warning);
|
|
195
|
-
if (this.colors.danger) d.setProperty('--color-danger', this.colors.danger);
|
|
194
|
+
if (this.colors.warning) { d.setProperty('--color-warning', this.colors.warning); d.setProperty('--color-warning-fill', this.colors.warning); }
|
|
195
|
+
if (this.colors.danger) { d.setProperty('--color-danger', this.colors.danger); d.setProperty('--color-danger-fill', this.colors.danger); }
|
|
196
196
|
},
|
|
197
197
|
persist(form, label) {
|
|
198
198
|
if (this.saving) return;
|
|
@@ -337,6 +337,13 @@
|
|
|
337
337
|
document.documentElement.style.setProperty('--color-success', this.colors.success);
|
|
338
338
|
document.documentElement.style.setProperty('--color-warning', this.colors.warning || '#FF7C47');
|
|
339
339
|
document.documentElement.style.setProperty('--color-danger', this.colors.danger || '#EF4444');
|
|
340
|
+
// btn-warning/btn-danger paint --color-<role>-fill first (the resolver
|
|
341
|
+
// emits it for the engine defaults), so a typed colour must set it too
|
|
342
|
+
// or the specimens keep the default fill. Cleared: drop the override.
|
|
343
|
+
['warning', 'danger'].forEach((role) => {
|
|
344
|
+
if (this.colors[role]) document.documentElement.style.setProperty(`--color-${role}-fill`, this.colors[role]);
|
|
345
|
+
else document.documentElement.style.removeProperty(`--color-${role}-fill`);
|
|
346
|
+
});
|
|
340
347
|
},
|
|
341
348
|
|
|
342
349
|
darkPreviewStyle() {
|
|
@@ -9,6 +9,12 @@ module Studio
|
|
|
9
9
|
# green measured 2.78:1 under the white label btn-success draws on it. This
|
|
10
10
|
# is the same hue at 5.0:1 (the shade cyvasse chose for its own success).
|
|
11
11
|
DEFAULT_SUCCESS = "#367E3A"
|
|
12
|
+
# The default warning and danger stay these hexes as ROLE colours (borders,
|
|
13
|
+
# rings, the -ink derivations start from them). Their button fills are
|
|
14
|
+
# derived separately, see #fill_vars: #FF7C47 is 2.55:1 and #EF4444 3.76:1
|
|
15
|
+
# under the white label btn-warning and btn-danger draw.
|
|
16
|
+
DEFAULT_WARNING = "#FF7C47"
|
|
17
|
+
DEFAULT_DANGER = "#EF4444"
|
|
12
18
|
|
|
13
19
|
# WCAG AA for normal-size text. Every filled button draws a 14px bold white
|
|
14
20
|
# label, which is not "large" text, so its fill owes 4.5:1 against white.
|
|
@@ -44,8 +50,8 @@ module Studio
|
|
|
44
50
|
primary = colors[:primary] || DEFAULT_PRIMARY
|
|
45
51
|
border_rgb = ColorScale.lighten(dark_base, 0.30)
|
|
46
52
|
success = colors[:success] || DEFAULT_SUCCESS
|
|
47
|
-
warning = colors[:warning] ||
|
|
48
|
-
danger = colors[:danger] ||
|
|
53
|
+
warning = colors[:warning] || DEFAULT_WARNING
|
|
54
|
+
danger = colors[:danger] || DEFAULT_DANGER
|
|
49
55
|
surfaces = dark_surfaces(dark_base)
|
|
50
56
|
|
|
51
57
|
secondary_ink = contrast_ink(dark_base, direction: :lighten, start: 0.70, target: 4.5, against: surfaces)
|
|
@@ -114,7 +120,7 @@ module Studio
|
|
|
114
120
|
"--color-warning-ink" => status_ink(warning, surfaces, direction: :lighten),
|
|
115
121
|
"--color-success-ink" => status_ink(success, surfaces, direction: :lighten),
|
|
116
122
|
"--color-accent" => colors[:accent] || "#F72585"
|
|
117
|
-
}.merge(fill_vars(primary,
|
|
123
|
+
}.merge(fill_vars(primary, warning, danger))
|
|
118
124
|
end
|
|
119
125
|
|
|
120
126
|
# Every dark-mode background a text var can sit on (page, surface,
|
|
@@ -197,13 +203,23 @@ module Studio
|
|
|
197
203
|
# label with its orange (a darkened fill would drop it to 3.3:1), and
|
|
198
204
|
# cyvasse sets --color-cta itself.
|
|
199
205
|
#
|
|
206
|
+
# --color-warning-fill and --color-danger-fill are the same contract for
|
|
207
|
+
# btn-warning and btn-danger (engine-button-contrast-admin-cog): emitted
|
|
208
|
+
# only while the role is at its engine default (#FF7C47 at 2.55:1, #EF4444
|
|
209
|
+
# at 3.76:1 under white), so a CONFIGURED colour paints as-is through the
|
|
210
|
+
# var(--color-<role>) fallback — mcritchie-industries' yellow warning is
|
|
211
|
+
# its own call. The role colour itself is not darkened: it is also a
|
|
212
|
+
# border, a ring and the start of its -ink search, which text reads.
|
|
213
|
+
#
|
|
200
214
|
# Success needs no fill var: its DEFAULT is already AA under white
|
|
201
215
|
# (DEFAULT_SUCCESS), and a configured success colour is the app's own —
|
|
202
216
|
# turf-monster's suite pins that a configured #4BAF50 still paints as-is.
|
|
203
|
-
def fill_vars(primary,
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
217
|
+
def fill_vars(primary, warning, danger)
|
|
218
|
+
{
|
|
219
|
+
"--color-cta-fill" => (white_label_fill(primary) if primary.to_s.casecmp?(DEFAULT_PRIMARY)),
|
|
220
|
+
"--color-warning-fill" => (white_label_fill(warning) if warning.to_s.casecmp?(DEFAULT_WARNING)),
|
|
221
|
+
"--color-danger-fill" => (white_label_fill(danger) if danger.to_s.casecmp?(DEFAULT_DANGER))
|
|
222
|
+
}.compact
|
|
207
223
|
end
|
|
208
224
|
|
|
209
225
|
# The hover fill is always derived, so it is always held to AA under white:
|
|
@@ -251,8 +267,8 @@ module Studio
|
|
|
251
267
|
light_base = colors[:light] || "#f8fafc"
|
|
252
268
|
primary = colors[:primary] || DEFAULT_PRIMARY
|
|
253
269
|
success = colors[:success] || DEFAULT_SUCCESS
|
|
254
|
-
warning = colors[:warning] ||
|
|
255
|
-
danger = colors[:danger] ||
|
|
270
|
+
warning = colors[:warning] || DEFAULT_WARNING
|
|
271
|
+
danger = colors[:danger] || DEFAULT_DANGER
|
|
256
272
|
surfaces = light_surfaces(light_base)
|
|
257
273
|
|
|
258
274
|
secondary_ink = contrast_ink(light_base, direction: :darken, start: 0.55, target: 4.5, against: surfaces)
|
|
@@ -303,7 +319,7 @@ module Studio
|
|
|
303
319
|
"--color-warning-ink" => status_ink(warning, surfaces, direction: :darken),
|
|
304
320
|
"--color-success-ink" => status_ink(success, surfaces, direction: :darken),
|
|
305
321
|
"--color-accent" => colors[:accent] || "#F72585"
|
|
306
|
-
}.merge(fill_vars(primary,
|
|
322
|
+
}.merge(fill_vars(primary, warning, danger))
|
|
307
323
|
end
|
|
308
324
|
end
|
|
309
325
|
end
|
data/lib/studio/version.rb
CHANGED