studio-engine 0.13.1 → 0.15.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 +10 -0
- data/app/assets/tailwind/studio_engine/engine.css +43 -7
- data/app/views/sessions/new.html.erb +49 -25
- data/lib/studio/version.rb +1 -1
- data/lib/studio.rb +22 -0
- metadata +3 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4c7828a97a832ad01592ab1875eef12fc5365d1ad98e2e7c19da71b8e5a47cab
|
|
4
|
+
data.tar.gz: 8a8c6726ea00cad17bd17426184ca546c5ad3fc08c7d9d497448b76b0a5626d2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: df1f556225655c111cdb3499c0809f4495dc941421c2606a0c2c85f21f28b412f7a53a8c99fef6712e191cb3f4d8b892872fc799d3dadc3d0b666a42408b9c89
|
|
7
|
+
data.tar.gz: 1ac4533e4061b6da06319854f478d7adc5eaf01e38f04a0885cda122ea712c1f9211e4010582a6e2bfa62cbad2637e82518f28ef7ceac3d742a7cf5f9641d665
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
The format is [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). This project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html) — `MAJOR.MINOR.PATCH`. Consumer Rails apps install the released RubyGems package with `gem "studio-engine", "~> 0.6"`; bumping the gem version and updating consumer lockfiles is a release.
|
|
4
4
|
|
|
5
|
+
## 0.14.0 — 2026-07-22
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **Passwordless engine login** — the stock `sessions/new` sign-in view now
|
|
10
|
+
renders its method set from `auth_methods`, so a host app configured for
|
|
11
|
+
passwordless sign-in gets the correct engine-shipped view with no local
|
|
12
|
+
override. Fixes a 500 in the passwordless path where the view assumed a
|
|
13
|
+
password field.
|
|
14
|
+
|
|
5
15
|
## 0.13.1 — 2026-07-19
|
|
6
16
|
|
|
7
17
|
### Changed
|
|
@@ -62,6 +62,33 @@
|
|
|
62
62
|
|
|
63
63
|
/* -- Button system (standardized across all Studio apps) ------------------- */
|
|
64
64
|
|
|
65
|
+
/*
|
|
66
|
+
Overridable variants — token contract.
|
|
67
|
+
|
|
68
|
+
Most filled variants sit on a theme role and darken on hover. Two of them
|
|
69
|
+
(btn-secondary, btn-neutral) are TOKEN-DRIVEN so a consuming app can retune
|
|
70
|
+
them WITHOUT redeclaring the @utility — a local `@utility` redeclaration is
|
|
71
|
+
ADDITIVE in Tailwind v4 (both definitions emit and the engine's rules leak in),
|
|
72
|
+
so forking is not a clean override. Set these on :root in the consumer's CSS:
|
|
73
|
+
|
|
74
|
+
--btn-secondary-bg base fill (default: var(--color-success))
|
|
75
|
+
--btn-secondary-bg-hover hover fill (default: same as base)
|
|
76
|
+
--btn-secondary-hover-filter hover filter (default: brightness(0.9))
|
|
77
|
+
--btn-neutral-bg base fill (default: var(--color-surface-alt))
|
|
78
|
+
--btn-neutral-bg-hover hover fill (default: var(--color-surface))
|
|
79
|
+
--btn-neutral-hover-filter hover filter (default: none)
|
|
80
|
+
|
|
81
|
+
With no tokens set, the compiled result is visually identical to the previous
|
|
82
|
+
hard-coded rules. Example — turf-monster's violet secondary + brightness neutral:
|
|
83
|
+
|
|
84
|
+
:root {
|
|
85
|
+
--btn-secondary-bg: #8e82fe; --btn-secondary-bg-hover: #7b6ef6;
|
|
86
|
+
--btn-secondary-hover-filter: none;
|
|
87
|
+
--btn-neutral-bg-hover: var(--color-surface-alt);
|
|
88
|
+
--btn-neutral-hover-filter: brightness(1.3);
|
|
89
|
+
}
|
|
90
|
+
*/
|
|
91
|
+
|
|
65
92
|
@utility btn {
|
|
66
93
|
@apply inline-flex items-center justify-center font-bold rounded-lg transition px-6 py-2 text-sm disabled:opacity-50 disabled:cursor-not-allowed;
|
|
67
94
|
&:focus-visible {
|
|
@@ -78,14 +105,17 @@
|
|
|
78
105
|
}
|
|
79
106
|
}
|
|
80
107
|
|
|
81
|
-
/*
|
|
82
|
-
|
|
83
|
-
|
|
108
|
+
/* btn-secondary DEFAULTS to the success role — with no tokens set it compiles
|
|
109
|
+
like btn-success, preserving the hub-canonical alias every consumer relies on.
|
|
110
|
+
It is token-overridable (see the contract above) so an app whose secondary
|
|
111
|
+
action diverges from success (turf-monster's violet) retunes it via
|
|
112
|
+
--btn-secondary-* instead of forking the @utility. */
|
|
84
113
|
@utility btn-secondary {
|
|
85
114
|
@apply text-white;
|
|
86
|
-
background-color: var(--color-success);
|
|
115
|
+
background-color: var(--btn-secondary-bg, var(--color-success));
|
|
87
116
|
&:hover {
|
|
88
|
-
|
|
117
|
+
background-color: var(--btn-secondary-bg-hover, var(--btn-secondary-bg, var(--color-success)));
|
|
118
|
+
filter: var(--btn-secondary-hover-filter, brightness(0.9));
|
|
89
119
|
}
|
|
90
120
|
}
|
|
91
121
|
|
|
@@ -130,10 +160,16 @@
|
|
|
130
160
|
}
|
|
131
161
|
}
|
|
132
162
|
|
|
163
|
+
/* btn-neutral DEFAULTS to the surface-alt base / surface hover pair, token-
|
|
164
|
+
overridable the same way (--btn-neutral-*): turf-monster keeps its
|
|
165
|
+
brightness(1.3) hover by setting --btn-neutral-hover-filter and pinning
|
|
166
|
+
--btn-neutral-bg-hover back to the base so the fill does not change. */
|
|
133
167
|
@utility btn-neutral {
|
|
134
|
-
@apply
|
|
168
|
+
@apply text-heading border border-strong;
|
|
169
|
+
background-color: var(--btn-neutral-bg, var(--color-surface-alt));
|
|
135
170
|
&:hover {
|
|
136
|
-
|
|
171
|
+
background-color: var(--btn-neutral-bg-hover, var(--color-surface));
|
|
172
|
+
filter: var(--btn-neutral-hover-filter, none);
|
|
137
173
|
}
|
|
138
174
|
}
|
|
139
175
|
|
|
@@ -35,36 +35,60 @@
|
|
|
35
35
|
<%= render "sessions/sso_continue" if defined?(sso_user_available?) && sso_user_available? %>
|
|
36
36
|
<% end %>
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
38
|
+
<%# The primary email form renders from the app's configured auth_methods: a PASSWORD
|
|
39
|
+
form only when passwords are available (Studio.password_login_available? — enabled AND
|
|
40
|
+
the User supports `authenticate`), otherwise the passwordless MAGIC-LINK request form.
|
|
41
|
+
The old hardcoded password field 500'd on every passwordless app's only sign-in path. %>
|
|
42
|
+
<% if Studio.password_login_available? %>
|
|
43
|
+
<%= form_tag login_path, method: :post do %>
|
|
44
|
+
<div class="mb-5">
|
|
45
|
+
<label for="email" class="block text-sm text-secondary mb-2 font-medium">Email</label>
|
|
46
|
+
<input type="email" name="email" id="email" value="<%= params[:email] %>" <%= 'autofocus' unless has_sso %>
|
|
47
|
+
x-ref="emailField"
|
|
48
|
+
class="input-field"
|
|
49
|
+
placeholder="you@example.com">
|
|
50
|
+
</div>
|
|
46
51
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
52
|
+
<div class="mb-6">
|
|
53
|
+
<label for="password" class="block text-sm text-secondary mb-2 font-medium">Password</label>
|
|
54
|
+
<input type="password" name="password" id="password"
|
|
55
|
+
class="input-field"
|
|
56
|
+
placeholder="Your password">
|
|
57
|
+
</div>
|
|
53
58
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
59
|
+
<button type="submit" class="btn btn-primary btn-lg w-full">
|
|
60
|
+
Log In
|
|
61
|
+
</button>
|
|
62
|
+
<% end %>
|
|
63
|
+
<% elsif Studio.auth_method?(:magic_link) %>
|
|
64
|
+
<%= form_tag magic_link_request_path, method: :post do %>
|
|
65
|
+
<div class="mb-5">
|
|
66
|
+
<label for="email" class="block text-sm text-secondary mb-2 font-medium">Email</label>
|
|
67
|
+
<input type="email" name="email" id="email" value="<%= params[:email] %>" <%= 'autofocus' unless has_sso %>
|
|
68
|
+
x-ref="emailField"
|
|
69
|
+
class="input-field"
|
|
70
|
+
placeholder="you@example.com">
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
<button type="submit" class="btn btn-primary btn-lg w-full">
|
|
74
|
+
Send sign-in link
|
|
75
|
+
</button>
|
|
76
|
+
<% end %>
|
|
57
77
|
<% end %>
|
|
58
78
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
79
|
+
<% if Studio.auth_method?(:google) %>
|
|
80
|
+
<% if Studio.password_login_available? || Studio.auth_method?(:magic_link) %>
|
|
81
|
+
<div class="relative my-6">
|
|
82
|
+
<div class="absolute inset-0 flex items-center"><div class="w-full border-t border-subtle"></div></div>
|
|
83
|
+
<div class="relative flex justify-center text-sm"><span class="bg-surface px-3 text-secondary">or</span></div>
|
|
84
|
+
</div>
|
|
85
|
+
<% end %>
|
|
63
86
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
87
|
+
<%= button_to "/auth/google_oauth2", method: :post, data: { turbo: false },
|
|
88
|
+
class: "btn btn-google btn-lg w-full gap-3" do %>
|
|
89
|
+
<%= render "components/google_logo" %>
|
|
90
|
+
Sign in with Google
|
|
91
|
+
<% end %>
|
|
68
92
|
<% end %>
|
|
69
93
|
|
|
70
94
|
<p class="text-center text-secondary text-sm mt-6">
|
data/lib/studio/version.rb
CHANGED
data/lib/studio.rb
CHANGED
|
@@ -152,6 +152,28 @@ module Studio
|
|
|
152
152
|
auth_methods.include?(method.to_sym)
|
|
153
153
|
end
|
|
154
154
|
|
|
155
|
+
# True when the engine login should render a PASSWORD field/form: passwords are enabled
|
|
156
|
+
# (`:password` in auth_methods) AND the host User model actually supports them (responds to
|
|
157
|
+
# `authenticate` — i.e. `has_secure_password`). Both are required, and the second is the
|
|
158
|
+
# belt-and-suspenders: without it, a passwordless app (User with no `authenticate`) rendered
|
|
159
|
+
# the hardcoded password field and 500'd on submit via `user.authenticate` — the whole fleet
|
|
160
|
+
# having moved off passwords, this made the engine default wrong for every consumer. The User
|
|
161
|
+
# check is defensive of a mis-set auth_methods; the contract validation normally guarantees it
|
|
162
|
+
# (validate_user_contract! requires PASSWORD_USER_INSTANCE_METHODS iff auth_method?(:password)).
|
|
163
|
+
def self.password_login_available?
|
|
164
|
+
auth_method?(:password) && user_supports_password?
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Does the host User model respond to `authenticate` (has_secure_password)? Safe when no User
|
|
168
|
+
# is defined (an engine-only boot / a test with no host model) — answers false rather than raise.
|
|
169
|
+
def self.user_supports_password?
|
|
170
|
+
return false unless defined?(::User) && ::User.respond_to?(:instance_methods)
|
|
171
|
+
|
|
172
|
+
PASSWORD_USER_INSTANCE_METHODS.all? { |m| ::User.instance_methods.include?(m) }
|
|
173
|
+
rescue StandardError
|
|
174
|
+
false
|
|
175
|
+
end
|
|
176
|
+
|
|
155
177
|
# True when the emailed/inbox magic-link URL is the short /l/<token> — i.e.
|
|
156
178
|
# magic links are Studio::Link rows AND this app draws the /l routes. False =
|
|
157
179
|
# the legacy /magic_link/<token> path: the :signed store, OR an app on the
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: studio-engine
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.15.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alex McRitchie
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: rails
|
|
@@ -298,7 +297,6 @@ metadata:
|
|
|
298
297
|
source_code_uri: https://github.com/amcritchie/studio-engine/tree/main
|
|
299
298
|
bug_tracker_uri: https://github.com/amcritchie/studio-engine/issues
|
|
300
299
|
changelog_uri: https://github.com/amcritchie/studio-engine/blob/main/CHANGELOG.md
|
|
301
|
-
post_install_message:
|
|
302
300
|
rdoc_options: []
|
|
303
301
|
require_paths:
|
|
304
302
|
- lib
|
|
@@ -313,8 +311,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
313
311
|
- !ruby/object:Gem::Version
|
|
314
312
|
version: '0'
|
|
315
313
|
requirements: []
|
|
316
|
-
rubygems_version:
|
|
317
|
-
signing_key:
|
|
314
|
+
rubygems_version: 4.0.9
|
|
318
315
|
specification_version: 4
|
|
319
316
|
summary: Shared Rails engine providing auth, SSO, error logging, theming, and S3-backed
|
|
320
317
|
image caching
|