studio-engine 0.117.0 → 0.118.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 +12 -0
- data/README.md +41 -0
- data/app/assets/tailwind/studio_engine/engine.css +44 -0
- data/app/helpers/studio_theme_helper.rb +1 -1
- data/lib/studio/type_scale.rb +64 -0
- data/lib/studio/version.rb +1 -1
- data/lib/studio.rb +10 -0
- 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: 48ec929ff6a1178b1f5d031f591f3e6f90f4e3257feb303063e40dcd9b142eeb
|
|
4
|
+
data.tar.gz: c4215b12c48ac7dbcb829e53faca80412007f2da8c0d785641412d375f847f74
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 898cba360f134fbc33f800b329e0914a82ed6ecb2af4306dc907361a246845d7974f70f80b2f3740bace96bd2ea7d08ff93b3a4523e27e3a30c223445e442c95
|
|
7
|
+
data.tar.gz: df32d0a535175c62b3390e8cbbbbc1df96d1be5ac4479711ee388cdbb3643914ec37ca3b04a43c79d1a4d12279145baa2777143079a633f7ba844bb141d9a99c
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,18 @@ The format is [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). This pro
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.118.0 — 2026-10-28
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **The type scale: five text roles every app draws from.** `type-title` (6x),
|
|
12
|
+
`type-heading` (3x), `type-subhead` (1.5x), `type-body` (1x) and `type-fine`
|
|
13
|
+
(0.75x), each a multiple of `--type-base`, which the theme tag sets from
|
|
14
|
+
`Studio.type_base` (16). A `type-dense` container swaps in
|
|
15
|
+
`Studio.type_dense_base` (14) for admin and ops pages. Title and heading take
|
|
16
|
+
`Studio.type_display_weight` (800), the rest `Studio.type_text_weight` (400).
|
|
17
|
+
Nothing changes on a page until it uses a role. README "Type scale".
|
|
18
|
+
|
|
7
19
|
## 0.117.0 — 2026-10-28
|
|
8
20
|
|
|
9
21
|
### Changed
|
data/README.md
CHANGED
|
@@ -310,6 +310,47 @@ flag — it cannot know where the reader is sitting, so only the reader's machin
|
|
|
310
310
|
may assert one. A host that omits the script still gets working stamps, just
|
|
311
311
|
frozen in the app's timezone. Specimen: `/admin/style` → Tricks → Time stamps.
|
|
312
312
|
|
|
313
|
+
### Type scale — `type-*`
|
|
314
|
+
|
|
315
|
+
The one set of text sizes every Studio app uses (Alex McRitchie's standard,
|
|
316
|
+
2026-10-28; the hub's `/logos/<brand>` Type Scale card shows it per brand).
|
|
317
|
+
Each role is a multiple of one base:
|
|
318
|
+
|
|
319
|
+
| Utility | Multiple | Public base (16 px) | Dense base (14 px) | Weight |
|
|
320
|
+
|---|---|---|---|---|
|
|
321
|
+
| `type-title` | 6x | 96 px | 84 px | display |
|
|
322
|
+
| `type-heading` | 3x | 48 px | 42 px | display |
|
|
323
|
+
| `type-subhead` | 1.5x | 24 px | 21 px | text |
|
|
324
|
+
| `type-body` | 1x | 16 px | 14 px | text |
|
|
325
|
+
| `type-fine` | 0.75x | 12 px | 10.5 px | text |
|
|
326
|
+
|
|
327
|
+
```erb
|
|
328
|
+
<h1 class="type-title text-heading">Winter Run 2026</h1>
|
|
329
|
+
<p class="type-body text-body">Since 2016 ...</p>
|
|
330
|
+
|
|
331
|
+
<%# an admin or ops page: everything inside takes the dense base %>
|
|
332
|
+
<main class="type-dense">
|
|
333
|
+
<h1 class="type-heading text-heading">Releases</h1>
|
|
334
|
+
</main>
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
- **Public pages** use the public base. **Admin and ops pages** put
|
|
338
|
+
`type-dense` on their container: the roles inside keep their ratios on the
|
|
339
|
+
dense base.
|
|
340
|
+
- **Set the base and weights from the brand kit**, in
|
|
341
|
+
`config/initializers/studio.rb`: `Studio.type_base`,
|
|
342
|
+
`Studio.type_dense_base`, `Studio.type_display_weight`,
|
|
343
|
+
`Studio.type_text_weight`. The theme tag (`studio_theme_css_tag`) writes them
|
|
344
|
+
as `--type-base`, `--type-dense-base`, `--type-display-weight` and
|
|
345
|
+
`--type-text-weight`; a bad value raises, naming the setting.
|
|
346
|
+
- **A role sets size, weight and line height only.** Colour stays with
|
|
347
|
+
`text-heading`, `text-body` and the rest, which are colour utilities, not
|
|
348
|
+
sizes.
|
|
349
|
+
- **Nothing is smaller than `type-fine`.** A new page uses the roles, not
|
|
350
|
+
`text-xs` or `text-2xs`; existing pages move over app by app.
|
|
351
|
+
- The multiples live in `Studio::TypeScale::ROLES` and in `engine.css`;
|
|
352
|
+
`test/lib/type_scale_contract_test.rb` keeps the two the same.
|
|
353
|
+
|
|
313
354
|
### Tints and shades — `.scrim`
|
|
314
355
|
|
|
315
356
|
Text laid over media on a PAGE (a hero photo, a video, a banner) reads through
|
|
@@ -179,6 +179,50 @@ body.modal-open .studio-app-banner {
|
|
|
179
179
|
@apply bg-inset rounded-xl border border-subtle p-4 overflow-x-auto;
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
+
/* -- Type scale ------------------------------------------------------------
|
|
183
|
+
The one set of text sizes every app draws from (Studio::TypeScale, README
|
|
184
|
+
"Type scale"). Each role is a multiple of --type-base: title 6x, heading 3x,
|
|
185
|
+
subhead 1.5x, body 1x, fine print 0.75x. The theme tag sets the app's base
|
|
186
|
+
(Studio.type_base, 16px) and weights; `type-dense` swaps in the dense base
|
|
187
|
+
(Studio.type_dense_base, 14px) for everything inside it, for admin and ops
|
|
188
|
+
pages. The fallbacks are the engine defaults, for a page with no theme tag.
|
|
189
|
+
The multiples here must match Studio::TypeScale::ROLES
|
|
190
|
+
(test/lib/type_scale_contract_test.rb). */
|
|
191
|
+
|
|
192
|
+
@utility type-dense {
|
|
193
|
+
--type-base: var(--type-dense-base, 14px);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
@utility type-title {
|
|
197
|
+
font-size: calc(var(--type-base, 16px) * 6);
|
|
198
|
+
font-weight: var(--type-display-weight, 800);
|
|
199
|
+
line-height: 1.05;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
@utility type-heading {
|
|
203
|
+
font-size: calc(var(--type-base, 16px) * 3);
|
|
204
|
+
font-weight: var(--type-display-weight, 800);
|
|
205
|
+
line-height: 1.1;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
@utility type-subhead {
|
|
209
|
+
font-size: calc(var(--type-base, 16px) * 1.5);
|
|
210
|
+
font-weight: var(--type-text-weight, 400);
|
|
211
|
+
line-height: 1.25;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
@utility type-body {
|
|
215
|
+
font-size: calc(var(--type-base, 16px) * 1);
|
|
216
|
+
font-weight: var(--type-text-weight, 400);
|
|
217
|
+
line-height: 1.5;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
@utility type-fine {
|
|
221
|
+
font-size: calc(var(--type-base, 16px) * 0.75);
|
|
222
|
+
font-weight: var(--type-text-weight, 400);
|
|
223
|
+
line-height: 1.4;
|
|
224
|
+
}
|
|
225
|
+
|
|
182
226
|
/* -- Scrims: tints and shades ----------------------------------------------
|
|
183
227
|
A scrim is the wash laid over media (a photo, a video) so text reads on it.
|
|
184
228
|
It comes in two TONES, and the tone is a design decision, not a colour pick:
|
|
@@ -10,6 +10,6 @@ module StudioThemeHelper
|
|
|
10
10
|
Studio::ThemeResolver.new(colors).to_css
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
tag.style("#{css}\n#{Studio::UiPrimitives.css}".html_safe, nonce: content_security_policy_nonce)
|
|
13
|
+
tag.style("#{css}\n#{Studio::TypeScale.css}\n#{Studio::UiPrimitives.css}".html_safe, nonce: content_security_policy_nonce)
|
|
14
14
|
end
|
|
15
15
|
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Studio
|
|
4
|
+
# THE TYPE SCALE — the one set of text sizes every Studio app draws from
|
|
5
|
+
# (task engine-type-scale-roles). Alex McRitchie ruled it the standard for
|
|
6
|
+
# every app on 2026-10-28; the hub's /logos/<brand> Type Scale card shows the
|
|
7
|
+
# same multiples per brand.
|
|
8
|
+
#
|
|
9
|
+
# Each role is a multiple of one base: title 6x, heading 3x, subhead 1.5x,
|
|
10
|
+
# body 1x, fine print 0.75x. engine.css draws the roles as the utilities
|
|
11
|
+
# `type-title`, `type-heading`, `type-subhead`, `type-body` and `type-fine`
|
|
12
|
+
# (not `text-heading` / `text-body`: those are colour utilities).
|
|
13
|
+
#
|
|
14
|
+
# An app has TWO bases:
|
|
15
|
+
# Studio.type_base (16) public and marketing pages: 96/48/24/16/12
|
|
16
|
+
# Studio.type_dense_base (14) admin and ops pages, under a `type-dense`
|
|
17
|
+
# container: 84/42/21/14/10.5
|
|
18
|
+
# The ratios never change; a page picks its base by where it sits.
|
|
19
|
+
#
|
|
20
|
+
# This module emits the per-app variables the utilities read, in the theme
|
|
21
|
+
# tag (StudioThemeHelper#studio_theme_css_tag):
|
|
22
|
+
#
|
|
23
|
+
# Studio::TypeScale.css
|
|
24
|
+
# # => ":root {\n --type-base: 16px;\n --type-dense-base: 14px; ..."
|
|
25
|
+
module TypeScale
|
|
26
|
+
# [utility, multiple, weight] — weight :display or :text picks the app's
|
|
27
|
+
# Studio.type_display_weight or Studio.type_text_weight.
|
|
28
|
+
ROLES = [
|
|
29
|
+
["type-title", 6, :display],
|
|
30
|
+
["type-heading", 3, :display],
|
|
31
|
+
["type-subhead", 1.5, :text],
|
|
32
|
+
["type-body", 1, :text],
|
|
33
|
+
["type-fine", 0.75, :text]
|
|
34
|
+
].freeze
|
|
35
|
+
|
|
36
|
+
WEIGHTS = (100..900).step(100).to_a.freeze
|
|
37
|
+
|
|
38
|
+
def self.css
|
|
39
|
+
<<~CSS
|
|
40
|
+
:root {
|
|
41
|
+
--type-base: #{px(Studio.type_base, 'type_base')};
|
|
42
|
+
--type-dense-base: #{px(Studio.type_dense_base, 'type_dense_base')};
|
|
43
|
+
--type-display-weight: #{weight(Studio.type_display_weight, 'type_display_weight')};
|
|
44
|
+
--type-text-weight: #{weight(Studio.type_text_weight, 'type_text_weight')};
|
|
45
|
+
}
|
|
46
|
+
CSS
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# The sizes a base gives, in pixels, largest first.
|
|
50
|
+
def self.sizes(base) = ROLES.to_h { |utility, multiple, _| [utility, base * multiple] }
|
|
51
|
+
|
|
52
|
+
def self.px(value, setting)
|
|
53
|
+
raise ArgumentError, "Studio.#{setting} must be a positive number of pixels, got #{value.inspect}" unless value.is_a?(Numeric) && value.positive?
|
|
54
|
+
|
|
55
|
+
"#{value.to_s.delete_suffix('.0')}px"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def self.weight(value, setting)
|
|
59
|
+
raise ArgumentError, "Studio.#{setting} must be one of #{WEIGHTS.join(', ')}, got #{value.inspect}" unless WEIGHTS.include?(value)
|
|
60
|
+
|
|
61
|
+
value.to_s
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
data/lib/studio/version.rb
CHANGED
data/lib/studio.rb
CHANGED
|
@@ -27,6 +27,7 @@ require "studio/color_scale"
|
|
|
27
27
|
require "studio/environment_banner"
|
|
28
28
|
require "studio/theme_resolver"
|
|
29
29
|
require "studio/ui_primitives"
|
|
30
|
+
require "studio/type_scale"
|
|
30
31
|
require "studio/js_literal"
|
|
31
32
|
require "studio/js_identifier"
|
|
32
33
|
require "studio/hold_button"
|
|
@@ -1269,6 +1270,15 @@ module Studio
|
|
|
1269
1270
|
mattr_accessor :theme_danger, default: "#EF4444"
|
|
1270
1271
|
mattr_accessor :theme_accent, default: "#F72585"
|
|
1271
1272
|
|
|
1273
|
+
# Type scale (Studio::TypeScale): the body size every type-* role multiplies.
|
|
1274
|
+
# type_base for public pages, type_dense_base inside a `type-dense` container
|
|
1275
|
+
# (admin and ops pages). Weights: title and heading take the display weight,
|
|
1276
|
+
# subhead, body and fine print the text weight. Set them from the brand kit.
|
|
1277
|
+
mattr_accessor :type_base, default: 16
|
|
1278
|
+
mattr_accessor :type_dense_base, default: 14
|
|
1279
|
+
mattr_accessor :type_display_weight, default: 800
|
|
1280
|
+
mattr_accessor :type_text_weight, default: 400
|
|
1281
|
+
|
|
1272
1282
|
# S3 / object storage — host apps MUST set s3_bucket_prefix explicitly in
|
|
1273
1283
|
# config/initializers/studio.rb before any S3-touching code runs (ImageCache,
|
|
1274
1284
|
# Studio::S3.upload, etc.). Default is nil so external users don't accidentally
|
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.118.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alex McRitchie
|
|
@@ -812,6 +812,7 @@ files:
|
|
|
812
812
|
- lib/studio/survey/export.rb
|
|
813
813
|
- lib/studio/tailwind_entry.rb
|
|
814
814
|
- lib/studio/theme_resolver.rb
|
|
815
|
+
- lib/studio/type_scale.rb
|
|
815
816
|
- lib/studio/ui_primitives.rb
|
|
816
817
|
- lib/studio/username_generator.rb
|
|
817
818
|
- lib/studio/version.rb
|