studio-engine 0.108.0.rc2 → 0.109.0.rc1
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 +16 -0
- data/README.md +66 -1
- data/app/assets/tailwind/studio_engine/engine.css +112 -0
- data/app/views/style/_scrims.html.erb +67 -0
- data/app/views/style/_tricks.html.erb +5 -2
- data/lib/studio/theme_resolver.rb +39 -2
- data/lib/studio/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1a916913ae747d410986fa4bc0f8abef5379e749678542100a0c396a954ff05e
|
|
4
|
+
data.tar.gz: 8816f7f0bc15437c3f509ce93c38e9d4d52b2425c81ed1f63a48f8022e21d0e9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 105b1f39b9c67041a6bae67a769f65ecb54f75abad1cea11088df3d69e98c83c75fd5c705eb17c8384a513f6d58488ffb36633a6af6955ca242bc504c4881670
|
|
7
|
+
data.tar.gz: 2dd6e01fc32d25b69558452f39351c5e3bc5e98b35da3064ea12eb10f8a4f1aba9fcee8f39cbe57cb325109ab64e5624c65ed50d035156e050dcf152ff8ef2e6
|
data/CHANGELOG.md
CHANGED
|
@@ -4,8 +4,24 @@ The format is [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). This pro
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.109.0 — 2026-10-15
|
|
8
|
+
|
|
7
9
|
### Added
|
|
8
10
|
|
|
11
|
+
- **Tints and shades: the `.scrim` primitive.** A scrim is the wash laid over
|
|
12
|
+
media so text reads on it. A **shade** lays the dark base over the media and
|
|
13
|
+
takes light ink; a **tint** lays the light base over it and takes dark ink.
|
|
14
|
+
`.scrim` picks by theme (a tint in light mode, a shade in dark),
|
|
15
|
+
`.scrim-tint` / `.scrim-shade` force a tone in either theme, `.scrim-soft` /
|
|
16
|
+
`.scrim-strong` step the strength from the tone's default (tint 75/58, shade
|
|
17
|
+
85/70; the default dark shade is the old navy `rgba(26,21,53,.85/.7/.85)`
|
|
18
|
+
exactly), and `.scrim-ink` / `.scrim-ink-muted` pick the ink for the tone.
|
|
19
|
+
The tone classes set inherited custom properties, so a tone on the parent
|
|
20
|
+
reaches both the wash and its sibling text. `Studio::ThemeResolver` now emits
|
|
21
|
+
the theme-independent `--color-shade`, `--color-tint` and their ink pairs
|
|
22
|
+
(`--color-{shade,tint}-ink`, `--color-{shade,tint}-ink-muted`) in both theme
|
|
23
|
+
blocks, following a custom `dark` / `light` colour. Specimen at
|
|
24
|
+
`/admin/style` → Tricks → Tints & shades; README "Tints and shades".
|
|
9
25
|
- **`GET /_studio/health_report`: the daily health report as JSON, for the
|
|
10
26
|
hub's central pull.** McRitchie Studio runs one 07:00 America/Denver job that
|
|
11
27
|
pulls every app's report and posts it to Discord, so a satellite needs no
|
data/README.md
CHANGED
|
@@ -209,6 +209,69 @@ flag — it cannot know where the reader is sitting, so only the reader's machin
|
|
|
209
209
|
may assert one. A host that omits the script still gets working stamps, just
|
|
210
210
|
frozen in the app's timezone. Specimen: `/admin/style` → Tricks → Time stamps.
|
|
211
211
|
|
|
212
|
+
### Tints and shades — `.scrim`
|
|
213
|
+
|
|
214
|
+
Text laid over media on a PAGE (a hero photo, a video, a banner) reads through
|
|
215
|
+
a **scrim**, a wash between the two. (The transactional email banner's scrim,
|
|
216
|
+
below, is a separate inline shade built for mail clients.) A scrim comes in one of two tones, and the tone is the
|
|
217
|
+
design decision:
|
|
218
|
+
|
|
219
|
+
| Tone | What it lays over the media | Ink that reads on it | Token |
|
|
220
|
+
|------|-----------------------------|----------------------|-------|
|
|
221
|
+
| **Shade** | the dark base; it darkens the media | light | `--color-shade` |
|
|
222
|
+
| **Tint** | the light base; it lightens the media | dark | `--color-tint` |
|
|
223
|
+
|
|
224
|
+
The shade is the dark theme's natural scrim and the tint the light theme's, so
|
|
225
|
+
`.scrim` on its own picks by theme. Force a tone when the media needs it, not
|
|
226
|
+
the theme: a pale photo that only a shade can carry, or a brand moment that
|
|
227
|
+
wants dark ink in both themes.
|
|
228
|
+
|
|
229
|
+
```erb
|
|
230
|
+
<section class="relative overflow-hidden">
|
|
231
|
+
<img src="/hero.avif" alt="" class="absolute inset-0 w-full h-full object-cover">
|
|
232
|
+
<div class="scrim absolute inset-0"></div>
|
|
233
|
+
<div class="relative z-10 text-center">
|
|
234
|
+
<h1 class="scrim-ink text-5xl font-extrabold">Solutions For Business</h1>
|
|
235
|
+
<p class="scrim-ink-muted">An acquisition entrepreneur ...</p>
|
|
236
|
+
</div>
|
|
237
|
+
</section>
|
|
238
|
+
|
|
239
|
+
<%# Forced: a shade in both themes. The tone goes on the shared PARENT. %>
|
|
240
|
+
<section class="scrim-shade relative overflow-hidden"> ... </section>
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
| Class | Effect |
|
|
244
|
+
|-------|--------|
|
|
245
|
+
| `.scrim` | Paints the wash: a 135deg gradient, heavier at both corners than in the middle. Theme-aware with no tone class: a tint in light mode, a shade in dark. |
|
|
246
|
+
| `.scrim-tint` · `.scrim-shade` | Force the tone, in either theme. |
|
|
247
|
+
| `.scrim-soft` · `.scrim-strong` | Step the strength: 15 points lighter, or 10 heavier, from the tone's default. |
|
|
248
|
+
| `.scrim-ink` | The strong ink for the tone (headlines): the dark text colour on a tint, white on a shade. |
|
|
249
|
+
| `.scrim-ink-muted` | The quieter ink (subtitles): the body ink at weight 600 on a tint, the secondary ink at 400 on a shade. |
|
|
250
|
+
|
|
251
|
+
- **Put the tone on the shared parent.** The tone classes set custom
|
|
252
|
+
properties, which inherit. The wash and the text are usually siblings (an
|
|
253
|
+
`absolute inset-0` scrim, then a `relative z-10` content box), so a tone on the
|
|
254
|
+
wash alone leaves the text on the theme's ink.
|
|
255
|
+
- **Default strengths.** A tint is 75% at the corners and 58% in the middle (the
|
|
256
|
+
hub hero's approved light treatment); a shade is 85% and 70%, which on the
|
|
257
|
+
default theme is the old hero navy, `rgba(26,21,53,.85/.7/.85)`, exactly. For an
|
|
258
|
+
exact value set `--scrim-edge` and `--scrim-mid` on the scrim element.
|
|
259
|
+
- **Muted ink on a tint is bolder, not greyer.** The secondary grey washes into
|
|
260
|
+
the media behind a pale tint, so the tint's muted ink is the body colour at
|
|
261
|
+
semibold. `.scrim-ink-muted` sets that weight; do not add a `font-*` beside it.
|
|
262
|
+
- **Tokens.** `Studio::ThemeResolver` emits `--color-shade` (the dark base) and
|
|
263
|
+
`--color-tint` (the light base) with the SAME value in both theme blocks, plus
|
|
264
|
+
their ink pairs `--color-{shade,tint}-ink` and `--color-{shade,tint}-ink-muted`.
|
|
265
|
+
They follow a custom theme's `dark` and `light` colours. Each ink clears WCAG AA
|
|
266
|
+
on its own base; contrast over a busy photo depends on the photo, so pick
|
|
267
|
+
`.scrim-strong` for small or long text.
|
|
268
|
+
- A scrim needs no theme switch of its own: there is no `dark:` variant, because
|
|
269
|
+
the tone is read from `:root` and the root `.dark` class.
|
|
270
|
+
|
|
271
|
+
Specimen: `/admin/style` → Tricks → Tints & shades. Definitions and the
|
|
272
|
+
reasoning: `engine.css` (Scrims: tints and shades). Browser proof:
|
|
273
|
+
`e2e/scrim_tones.spec.js`.
|
|
274
|
+
|
|
212
275
|
### Smooth-load header pin — `.vt-pinned-header`
|
|
213
276
|
|
|
214
277
|
When `Studio.smooth_load` is on, put `vt-pinned-header` on the app's sticky
|
|
@@ -875,7 +938,9 @@ generated at send time.
|
|
|
875
938
|
**The scrim** is a wash between artwork and type, on by default at 0.40.
|
|
876
939
|
Background art is chosen to look good, not to guarantee contrast, and white text
|
|
877
940
|
over a pale sky cannot be read. Pass `scrim: 0` for artwork dark enough to carry
|
|
878
|
-
the type itself.
|
|
941
|
+
the type itself. This email scrim is its own fixed shade (`24,16,64`, inline for
|
|
942
|
+
mail clients); it is not the page primitive in [Tints and shades](#tints-and-shades--scrim),
|
|
943
|
+
which mail clients could not render.
|
|
879
944
|
|
|
880
945
|
**The markup is deliberately old-fashioned.** Outlook on Windows renders through
|
|
881
946
|
Word and ignores `background-image`, so the picture is carried by the `<td
|
|
@@ -178,6 +178,118 @@ body.modal-open .studio-app-banner {
|
|
|
178
178
|
@apply bg-inset rounded-xl border border-subtle p-4 overflow-x-auto;
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
+
/* -- Scrims: tints and shades ----------------------------------------------
|
|
182
|
+
A scrim is the wash laid over media (a photo, a video) so text reads on it.
|
|
183
|
+
It comes in two TONES, and the tone is a design decision, not a colour pick:
|
|
184
|
+
|
|
185
|
+
SHADE the dark base (--color-shade) over the media. It DARKENS it, and
|
|
186
|
+
LIGHT ink reads on it. The dark theme's natural scrim.
|
|
187
|
+
TINT the light base (--color-tint) over the media. It LIGHTENS it, and
|
|
188
|
+
DARK ink reads on it. The light theme's natural scrim.
|
|
189
|
+
|
|
190
|
+
Both tokens are theme-INDEPENDENT (Studio::ThemeResolver#tone_vars emits
|
|
191
|
+
each with one value in both theme blocks), so a forced tone paints the same
|
|
192
|
+
in either theme. They follow the theme's own bases, so a custom dark or
|
|
193
|
+
light colour carries through.
|
|
194
|
+
|
|
195
|
+
THE CLASSES
|
|
196
|
+
.scrim paints the wash. With no tone class it is
|
|
197
|
+
theme-aware: a tint in light mode, a shade in dark.
|
|
198
|
+
.scrim-tint forces a tint, in either theme.
|
|
199
|
+
.scrim-shade forces a shade, in either theme.
|
|
200
|
+
.scrim-soft a lighter wash (-15 points on both stops).
|
|
201
|
+
.scrim-strong a heavier wash (+10 points on both stops).
|
|
202
|
+
.scrim-ink the strong ink for text on the tone (headlines).
|
|
203
|
+
.scrim-ink-muted the quieter ink (subtitles): on a tint, the body
|
|
204
|
+
ink at 600, because the secondary grey washes into
|
|
205
|
+
the media; on a shade, the secondary ink at 400.
|
|
206
|
+
|
|
207
|
+
THE TONE IS INHERITED CONTEXT, NOT A PROPERTY OF THE WASH. The usual layout
|
|
208
|
+
puts the scrim and the text as SIBLINGS (an `absolute inset-0` scrim, then
|
|
209
|
+
a `relative z-10` content box), so the text cannot read anything off the
|
|
210
|
+
scrim element itself. The tone classes therefore only set custom
|
|
211
|
+
properties, and those inherit: put `.scrim-shade` on the section and both
|
|
212
|
+
the wash and every `.scrim-ink` inside it take the shade. With no tone
|
|
213
|
+
class anywhere, :root and .dark supply the theme-aware default.
|
|
214
|
+
|
|
215
|
+
STRENGTH. Each tone carries its own default stops (--scrim-tone-edge /
|
|
216
|
+
--scrim-tone-mid): a tint 75% / 58% (approved on the hub's landing hero),
|
|
217
|
+
a shade 85% / 70%. The gradient reads --scrim-edge / --scrim-mid first, so
|
|
218
|
+
a caller sets either inline for an exact value, and .scrim-soft /
|
|
219
|
+
.scrim-strong derive them from the tone's own default. Put a strength class
|
|
220
|
+
on the scrim element itself: --scrim-edge inherits like any custom property.
|
|
221
|
+
|
|
222
|
+
THE GRADIENT runs corner to corner (135deg), heavier at both ends than in
|
|
223
|
+
the middle, so the media shows through where the eye lands least. The
|
|
224
|
+
default shade is exactly rgba(26,21,53, .85 / .70 / .85) on the default
|
|
225
|
+
theme: color-mix against `transparent` keeps the colour and scales alpha.
|
|
226
|
+
|
|
227
|
+
Every token carries the engine default as a fallback, so an app that sets
|
|
228
|
+
its own theme vars without studio_theme_css_tag still gets a working wash. */
|
|
229
|
+
:root {
|
|
230
|
+
--scrim-color: var(--color-tint, #f8fafc);
|
|
231
|
+
--scrim-tone-edge: 75%;
|
|
232
|
+
--scrim-tone-mid: 58%;
|
|
233
|
+
--scrim-ink: var(--color-tint-ink, #0f172a);
|
|
234
|
+
--scrim-ink-muted: var(--color-tint-ink-muted, #334155);
|
|
235
|
+
--scrim-ink-muted-weight: 600;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.dark {
|
|
239
|
+
--scrim-color: var(--color-shade, #1A1535);
|
|
240
|
+
--scrim-tone-edge: 85%;
|
|
241
|
+
--scrim-tone-mid: 70%;
|
|
242
|
+
--scrim-ink: var(--color-shade-ink, #ffffff);
|
|
243
|
+
--scrim-ink-muted: var(--color-shade-ink-muted, #BAB9C2);
|
|
244
|
+
--scrim-ink-muted-weight: 400;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
@utility scrim {
|
|
248
|
+
background-image: linear-gradient(
|
|
249
|
+
135deg,
|
|
250
|
+
color-mix(in srgb, var(--scrim-color) var(--scrim-edge, var(--scrim-tone-edge)), transparent) 0%,
|
|
251
|
+
color-mix(in srgb, var(--scrim-color) var(--scrim-mid, var(--scrim-tone-mid)), transparent) 50%,
|
|
252
|
+
color-mix(in srgb, var(--scrim-color) var(--scrim-edge, var(--scrim-tone-edge)), transparent) 100%
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
@utility scrim-tint {
|
|
257
|
+
--scrim-color: var(--color-tint, #f8fafc);
|
|
258
|
+
--scrim-tone-edge: 75%;
|
|
259
|
+
--scrim-tone-mid: 58%;
|
|
260
|
+
--scrim-ink: var(--color-tint-ink, #0f172a);
|
|
261
|
+
--scrim-ink-muted: var(--color-tint-ink-muted, #334155);
|
|
262
|
+
--scrim-ink-muted-weight: 600;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
@utility scrim-shade {
|
|
266
|
+
--scrim-color: var(--color-shade, #1A1535);
|
|
267
|
+
--scrim-tone-edge: 85%;
|
|
268
|
+
--scrim-tone-mid: 70%;
|
|
269
|
+
--scrim-ink: var(--color-shade-ink, #ffffff);
|
|
270
|
+
--scrim-ink-muted: var(--color-shade-ink-muted, #BAB9C2);
|
|
271
|
+
--scrim-ink-muted-weight: 400;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
@utility scrim-soft {
|
|
275
|
+
--scrim-edge: calc(var(--scrim-tone-edge) - 15%);
|
|
276
|
+
--scrim-mid: calc(var(--scrim-tone-mid) - 15%);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
@utility scrim-strong {
|
|
280
|
+
--scrim-edge: calc(var(--scrim-tone-edge) + 10%);
|
|
281
|
+
--scrim-mid: calc(var(--scrim-tone-mid) + 10%);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
@utility scrim-ink {
|
|
285
|
+
color: var(--scrim-ink);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
@utility scrim-ink-muted {
|
|
289
|
+
color: var(--scrim-ink-muted);
|
|
290
|
+
font-weight: var(--scrim-ink-muted-weight);
|
|
291
|
+
}
|
|
292
|
+
|
|
181
293
|
/* -- Text + form ----------------------------------------------------------- */
|
|
182
294
|
|
|
183
295
|
@utility badge {
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<%# Tints and shades: the scrim primitive's group on the living style guide's
|
|
2
|
+
Tricks board (admin/style). Rendered by style/_tricks, and by the e2e lab
|
|
3
|
+
page e2e_lab/scrims, which grades the painted wash and ink in a browser.
|
|
4
|
+
|
|
5
|
+
A SHADE lays the dark base over media and light ink reads on it; a TINT
|
|
6
|
+
lays the light base over media and dark ink reads on it. .scrim alone is
|
|
7
|
+
theme-aware (a tint in light mode, a shade in dark); .scrim-tint and
|
|
8
|
+
.scrim-shade force a tone in either theme. The tone classes only set
|
|
9
|
+
custom properties, which inherit, so each specimen puts its tone on the
|
|
10
|
+
STAGE and the wash and the text, which are siblings, both take it.
|
|
11
|
+
|
|
12
|
+
The striped panel stands in for a photo: vivid and busy, drawn in the role
|
|
13
|
+
colours, which are the same in both themes, so what changes between
|
|
14
|
+
specimens is the scrim alone. The
|
|
15
|
+
definitions and the strength numbers live in engine.css (Scrims: tints
|
|
16
|
+
and shades) and the README section of the same name. %>
|
|
17
|
+
<%
|
|
18
|
+
media_style = "background-image: repeating-linear-gradient(135deg, var(--color-primary) 0 18px, var(--color-accent) 18px 36px, var(--color-warning) 36px 54px, var(--color-success) 54px 72px)"
|
|
19
|
+
|
|
20
|
+
specimens = [
|
|
21
|
+
{ key: "theme", tone: nil, scrim: "scrim",
|
|
22
|
+
klass: ".scrim",
|
|
23
|
+
note: "Theme-aware: a tint in light mode, a shade in dark." },
|
|
24
|
+
{ key: "tint", tone: "scrim-tint", scrim: "scrim",
|
|
25
|
+
klass: ".scrim-tint .scrim",
|
|
26
|
+
note: "Forced tint, in either theme. Dark ink." },
|
|
27
|
+
{ key: "shade", tone: "scrim-shade", scrim: "scrim",
|
|
28
|
+
klass: ".scrim-shade .scrim",
|
|
29
|
+
note: "Forced shade, in either theme. Light ink." },
|
|
30
|
+
{ key: "soft", tone: nil, scrim: "scrim scrim-soft",
|
|
31
|
+
klass: ".scrim .scrim-soft",
|
|
32
|
+
note: "A lighter wash: more of the media shows." },
|
|
33
|
+
{ key: "strong", tone: nil, scrim: "scrim scrim-strong",
|
|
34
|
+
klass: ".scrim .scrim-strong",
|
|
35
|
+
note: "A heavier wash, for long or small text." }
|
|
36
|
+
]
|
|
37
|
+
%>
|
|
38
|
+
<section id="scrims" class="space-y-5" data-scrim-group>
|
|
39
|
+
<div class="space-y-1">
|
|
40
|
+
<h3 class="text-xl font-bold text-heading">Tints & shades</h3>
|
|
41
|
+
<p class="text-muted text-sm max-w-2xl">
|
|
42
|
+
A <strong>shade</strong> lays the dark base over media and light ink reads on it; a
|
|
43
|
+
<strong>tint</strong> lays the light base over media and dark ink reads on it.
|
|
44
|
+
<code class="font-mono text-2xs">.scrim</code> picks by theme;
|
|
45
|
+
<code class="font-mono text-2xs">.scrim-tint</code> / <code class="font-mono text-2xs">.scrim-shade</code>
|
|
46
|
+
force one. Put the tone on the shared parent so the wash and the
|
|
47
|
+
<code class="font-mono text-2xs">.scrim-ink</code> text both take it.
|
|
48
|
+
</p>
|
|
49
|
+
</div>
|
|
50
|
+
<div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
|
51
|
+
<% specimens.each do |s| %>
|
|
52
|
+
<% tone_attr = s[:tone] ? %( class="#{s[:tone]} relative ...") : %( class="relative ...") %>
|
|
53
|
+
<%= render layout: "style/specimen",
|
|
54
|
+
locals: { klass: s[:klass],
|
|
55
|
+
usage: %(<section#{tone_attr}>\n <img class="absolute inset-0 ..." src="...">\n <div class="#{s[:scrim]} absolute inset-0"></div>\n <div class="relative z-10">\n <h2 class="scrim-ink">Headline</h2>\n <p class="scrim-ink-muted">Subtitle</p>\n </div>\n</section>) } do %>
|
|
56
|
+
<div class="relative w-full max-w-xs h-36 rounded-lg overflow-hidden <%= s[:tone] %>" data-scrim-specimen="<%= s[:key] %>">
|
|
57
|
+
<div class="absolute inset-0" style="<%= media_style %>" aria-hidden="true"></div>
|
|
58
|
+
<div class="<%= s[:scrim] %> absolute inset-0" data-scrim-wash></div>
|
|
59
|
+
<div class="relative z-10 h-full flex flex-col items-center justify-center gap-1 px-4 text-center">
|
|
60
|
+
<p class="scrim-ink text-lg font-extrabold" data-scrim-ink>Solutions For Business</p>
|
|
61
|
+
<p class="scrim-ink-muted text-sm" data-scrim-ink-muted><%= s[:note] %></p>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
<% end %>
|
|
65
|
+
<% end %>
|
|
66
|
+
</div>
|
|
67
|
+
</section>
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
<p class="text-muted text-sm max-w-2xl">
|
|
35
35
|
A board of style tricks you can see and hand to an agent to use out of the box.
|
|
36
36
|
Each specimen surfaces the rendered primitive, its <strong>class name (one-click
|
|
37
|
-
copy)</strong>, and a copyable usage snippet - the button, surface,
|
|
38
|
-
and leveling primitives. The color tokens live in <a href="#theme" class="underline">Theme</a>.
|
|
37
|
+
copy)</strong>, and a copyable usage snippet - the button, surface, scrim, motion,
|
|
38
|
+
effect, and leveling primitives. The color tokens live in <a href="#theme" class="underline">Theme</a>.
|
|
39
39
|
</p>
|
|
40
40
|
</div>
|
|
41
41
|
|
|
@@ -113,6 +113,9 @@
|
|
|
113
113
|
</div>
|
|
114
114
|
</section>
|
|
115
115
|
|
|
116
|
+
<!-- Tints and shades: the scrim primitive -->
|
|
117
|
+
<%= render "style/scrims" %>
|
|
118
|
+
|
|
116
119
|
<!-- Time stamps: the "at" format -->
|
|
117
120
|
<section class="space-y-5">
|
|
118
121
|
<div class="space-y-1">
|
|
@@ -28,23 +28,60 @@ module Studio
|
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
def to_css
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
dark = dark_mode_vars
|
|
32
|
+
light = light_mode_vars
|
|
33
|
+
dark_vars = dark.map { |k, v| " #{k}: #{v};" }.join("\n")
|
|
34
|
+
light_vars = light.map { |k, v| " #{k}: #{v};" }.join("\n")
|
|
33
35
|
palette_vars = primary_palette_vars.map { |k, v| " #{k}: #{v};" }.join("\n")
|
|
36
|
+
tone_css = tone_vars(dark, light).map { |k, v| " #{k}: #{v};" }.join("\n")
|
|
34
37
|
|
|
35
38
|
<<~CSS
|
|
36
39
|
:root, .dark {
|
|
37
40
|
#{dark_vars}
|
|
38
41
|
#{palette_vars}
|
|
42
|
+
#{tone_css}
|
|
39
43
|
}
|
|
40
44
|
|
|
41
45
|
html:not(.dark) {
|
|
42
46
|
#{light_vars}
|
|
43
47
|
#{palette_vars}
|
|
48
|
+
#{tone_css}
|
|
44
49
|
}
|
|
45
50
|
CSS
|
|
46
51
|
end
|
|
47
52
|
|
|
53
|
+
# THE SHADE AND THE TINT — the two tones the scrim primitive lays over
|
|
54
|
+
# media (engine.css `.scrim`, README "Tints and shades").
|
|
55
|
+
#
|
|
56
|
+
# A SHADE is the dark base over a photo: it darkens it, and light ink reads
|
|
57
|
+
# on it. A TINT is the light base over a photo: it lightens it, and dark
|
|
58
|
+
# ink reads on it. They are the same pair as the two themes' page colours,
|
|
59
|
+
# but these tokens are THEME-INDEPENDENT: emitted with one value in both
|
|
60
|
+
# blocks, so a forced `.scrim-shade` is the dark base in light mode too.
|
|
61
|
+
# --color-page cannot serve, because it flips with the theme.
|
|
62
|
+
#
|
|
63
|
+
# Each tone carries its ink pair, also theme-independent, because text on a
|
|
64
|
+
# forced tone in the opposite theme cannot use --color-text (it would be
|
|
65
|
+
# light ink on a tint). The pairs are the two themes' own inks, chosen so
|
|
66
|
+
# the theme-aware `.scrim` matches the page's text exactly:
|
|
67
|
+
# shade: --color-text (#fff) and the dark --color-text-secondary;
|
|
68
|
+
# tint: --color-text (#0f172a) and the light --color-text-BODY, which
|
|
69
|
+
# `.scrim-ink-muted` sets at 600. Not the light secondary grey:
|
|
70
|
+
# on the hub hero it washed into the skyline behind the tint, and
|
|
71
|
+
# the body ink at semibold is the treatment Alex approved.
|
|
72
|
+
# Takes the two mode hashes when the caller already built them (to_css),
|
|
73
|
+
# so the contrast searches behind them run once per render, not twice.
|
|
74
|
+
def tone_vars(dark = dark_mode_vars, light = light_mode_vars)
|
|
75
|
+
{
|
|
76
|
+
"--color-shade" => dark["--color-page"],
|
|
77
|
+
"--color-shade-ink" => dark["--color-text"],
|
|
78
|
+
"--color-shade-ink-muted" => dark["--color-text-secondary"],
|
|
79
|
+
"--color-tint" => light["--color-page"],
|
|
80
|
+
"--color-tint-ink" => light["--color-text"],
|
|
81
|
+
"--color-tint-ink-muted" => light["--color-text-body"]
|
|
82
|
+
}
|
|
83
|
+
end
|
|
84
|
+
|
|
48
85
|
def dark_mode_vars
|
|
49
86
|
dark_base = colors[:dark] || "#1A1535"
|
|
50
87
|
primary = colors[:primary] || DEFAULT_PRIMARY
|
data/lib/studio/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: studio-engine
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.109.0.rc1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alex McRitchie
|
|
@@ -674,6 +674,7 @@ files:
|
|
|
674
674
|
- app/views/style/_host.html.erb
|
|
675
675
|
- app/views/style/_modal_specimen.html.erb
|
|
676
676
|
- app/views/style/_modals.html.erb
|
|
677
|
+
- app/views/style/_scrims.html.erb
|
|
677
678
|
- app/views/style/_site_footer.html.erb
|
|
678
679
|
- app/views/style/_specimen.html.erb
|
|
679
680
|
- app/views/style/_tasks.html.erb
|