studio-engine 0.74.8 → 0.74.9
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 +38 -3
- data/README.md +78 -32
- data/app/assets/tailwind/studio_engine/engine-motion.css +7 -0
- data/app/views/studio/modals/_host.html.erb +5 -1
- data/app/views/studio/modals/_scoped_host.html.erb +6 -5
- data/app/views/studio/modals/auth/_resend_footer.html.erb +26 -2
- data/app/views/studio/modals/blocks/_birthday.html.erb +1 -1
- data/app/views/studio/modals/blocks/_leveling_activity.html.erb +1 -1
- data/app/views/studio/modals/onboarding/_first_name.html.erb +1 -1
- 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: 54ff8e7d4414fba9258118e2e467a259121eaab850d8ec8cfb574b95acdf8b22
|
|
4
|
+
data.tar.gz: fdac442335eaa412bc6084ca82b9bc3b9bd7a89eb110a3857d528f89109835dd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5c1619cd191b89affc30ca2182e1cd2f09963afd2c822a9ef335fe67baa8064c21420451dcd046f5fb26258cc14caca45d5cab9e4800e2e64ba74682e8afc311
|
|
7
|
+
data.tar.gz: 24a428027cc14be60d49771a2721bc31b974ab456fd6c553d97c78463d23de1effa6aa2f56eb4231b4df0b6cff73ca0bc2c171d21f702f42e29de1e9375413a3
|
data/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
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 and pin the floor each one needs — the pins differ on purpose, and every consumer records why beside its own. Bumping the gem version and updating consumer lockfiles is a release; `bin/release prepare` allocates the version and does both (see [`docs/RELEASE.md`](./docs/RELEASE.md)). `prepare`
|
|
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 and pin the floor each one needs — the pins differ on purpose, and every consumer records why beside its own. Bumping the gem version and updating consumer lockfiles is a release; `bin/release prepare` allocates the version and does both (see [`docs/RELEASE.md`](./docs/RELEASE.md)). Write entries under `## Unreleased` and never write a version heading: when `prepare` allocates a version it rolls this file in the same commit, moving everything under `## Unreleased` beneath a new `## <version> — <date>` heading (written even when the bucket is empty) and leaving `## Unreleased` first and empty. It refuses the sweep, with nothing published, when the roll would lie or it cannot read this file; when it skips allocation, nothing rolls. [`docs/RELEASE.md`](./docs/RELEASE.md), *Rolling `Unreleased` into a version*, says when each happens and what to do by hand. `test/docs/changelog_structure_test.rb` guards the shape.
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- **The auth resend footer's error line failed WCAG AA in both themes; it now
|
|
10
|
+
uses the danger ink.** `studio/modals/auth/_resend_footer` painted its
|
|
11
|
+
`role="alert"` paragraph with the static `text-red-400`, which Tailwind v4
|
|
12
|
+
compiles to about `#FF6467`: 3.86:1 on the dark modal card and 2.89:1 on the
|
|
13
|
+
light one, both under the 4.5:1 that 12px text needs. It is now
|
|
14
|
+
`text-danger-ink`, the red `Studio::ThemeResolver` derives per theme to clear
|
|
15
|
+
4.5:1 on every surface: 4.50:1 dark and 5.76:1 light on the default modal
|
|
16
|
+
card. The resend spinner stays the engine's `.spinner`, tuned to
|
|
17
|
+
turf-monster's currentColor ring (`--spinner-track: currentColor;
|
|
18
|
+
--spinner-color: transparent`), so a host that drops its fork sees no change.
|
|
19
|
+
Guarded by `test/views/resend_footer_error_contrast_test.rb`.
|
|
20
|
+
|
|
7
21
|
### Docs
|
|
8
22
|
|
|
9
23
|
- **Thirty-five minor versions of shipped entries left `## Unreleased` and moved
|
|
@@ -32,8 +46,29 @@ The format is [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). This pro
|
|
|
32
46
|
fails loudly rather than passing vacuously, and — the one that would have caught
|
|
33
47
|
this in week one — `Studio::VERSION` no more than two minor versions ahead of the
|
|
34
48
|
newest heading. Against the pre-change file it reports "35 minor versions of
|
|
35
|
-
entries are still filed under `## Unreleased`". Automating the roll inside
|
|
36
|
-
`bin/release prepare` (mcritchie-studio) is the real fix and is not done
|
|
49
|
+
entries are still filed under `## Unreleased`". ~~Automating the roll inside
|
|
50
|
+
`bin/release prepare` (mcritchie-studio) is the real fix and is not done.~~ —
|
|
51
|
+
**superseded after 0.74.8:** mcritchie-studio#1344 made `prepare` roll this
|
|
52
|
+
file whenever it allocates a version, so "it never touches this file" above
|
|
53
|
+
describes the tooling as of 0.74.8. See the entry on the automatic roll below.
|
|
54
|
+
|
|
55
|
+
- **The docs called the `## Unreleased` roll a manual conductor step; `bin/release
|
|
56
|
+
prepare` does it now, and the docs say exactly when it does not.**
|
|
57
|
+
mcritchie-studio#1344 made prepare roll this file into the allocated version in
|
|
58
|
+
the commit that sets `lib/studio/version.rb` and `Gemfile.lock`, and REFUSE the
|
|
59
|
+
sweep, with nothing published, when the roll would lie. `docs/RELEASE.md`
|
|
60
|
+
(*Rolling `Unreleased` into a version*), this file's preamble and the README's
|
|
61
|
+
release paragraph still said the roll was yours, by hand. They now name the
|
|
62
|
+
three outcomes (ALLOCATE rolls, SKIP rolls nothing, REFUSE aborts), each
|
|
63
|
+
refusal and its fix, and the reach limit: a SKIP (a version set by hand, or a
|
|
64
|
+
re-run after an abort before the tag) rolls nothing. They also settle three
|
|
65
|
+
conventions. An entry-less release still gets its heading; a heading never
|
|
66
|
+
lands before its version does, because `accepted` lags `release`; and a merge
|
|
67
|
+
that crosses a roll gets checked, because git can merge a new bullet CLEAN
|
|
68
|
+
under a version that shipped without it. The manual procedure stays, as the
|
|
69
|
+
remedy for those cases. No runtime code changed;
|
|
70
|
+
`test/docs/changelog_structure_test.rb` changed only its comments and its
|
|
71
|
+
failure message.
|
|
37
72
|
|
|
38
73
|
## 0.74.3 — 2026-09-08
|
|
39
74
|
|
data/README.md
CHANGED
|
@@ -240,35 +240,78 @@ the block:
|
|
|
240
240
|
|
|
241
241
|
#### Writing a modal's content partial — two rules the host imposes
|
|
242
242
|
|
|
243
|
-
Both
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
243
|
+
Both rules let the card render and then do less than it looks like it does.
|
|
244
|
+
They differ in whether anything reaches the CONSOLE, which is the first thing
|
|
245
|
+
to check when a registered partial misbehaves.
|
|
246
|
+
|
|
247
|
+
**1. SINGLE ROOT — fails in total silence.** A content partial's outer `<div>`
|
|
248
|
+
is the host's required root. Alpine's `<template x-if>` clones only the FIRST
|
|
249
|
+
root element of its content, so a second top-level sibling — a stray `<span>`,
|
|
250
|
+
a trailing `<style>` block, a comment-turned-node — is dropped on the floor.
|
|
251
|
+
Nothing raises and nothing logs: `x-if` takes `.firstElementChild` and asks no
|
|
252
|
+
questions. (Alpine DOES warn on a multi-root `x-for` template — *"x-for
|
|
253
|
+
templates require a single root element, additional elements will be ignored"*
|
|
254
|
+
— which is exactly why this one catches people out. The modal host is `x-if`,
|
|
255
|
+
and `x-if` ships no such check.) Bake anything extra inside the wrapping
|
|
256
|
+
`<div>`.
|
|
257
|
+
|
|
258
|
+
**2. NO DOUBLE QUOTE INSIDE `x-data` — this one LOGS.** The attribute is
|
|
259
|
+
double-quoted, so an inner double quote CLOSES it. Alpine then mounts a
|
|
260
|
+
component whose expression is truncated mid-statement: every element still
|
|
261
|
+
renders and every handler does nothing. It is NOT silent. The truncation
|
|
262
|
+
leaves a JavaScript syntax error, Alpine's evaluator catches it, and the
|
|
263
|
+
default handler prints `Alpine Expression Error: …` together with the
|
|
264
|
+
offending expression — a `console.warn`, followed by an async rethrow. That
|
|
265
|
+
warning is the best clue this rule was broken, so send a debugging engineer to
|
|
266
|
+
the console rather than to the markup. Single-quote everything inside
|
|
267
|
+
`x-data`.
|
|
268
|
+
|
|
269
|
+
Interpolated values are the same rule arriving from the server, and Rails
|
|
270
|
+
already guards the ordinary case: `<%= value %>` inside `x-data` renders a
|
|
271
|
+
double quote as `"`, and the HTML tokenizer never reads a character
|
|
272
|
+
reference as the closing quote — it decodes it straight into the value — so
|
|
273
|
+
the attribute survives. The vector is a value that SKIPS that escaping —
|
|
274
|
+
`raw`, `.html_safe`, or a helper returning a SafeBuffer — which puts a bare
|
|
275
|
+
`"` into the attribute and closes it exactly as a typed one would.
|
|
276
|
+
`escape_javascript` (`j`) is NOT the guard here: it escapes for a JavaScript
|
|
277
|
+
string literal (`\"`) and PRESERVES the html_safe flag, so the raw quote still
|
|
278
|
+
reaches the attribute. Let Rails escape it.
|
|
279
|
+
|
|
280
|
+
That settles the ATTRIBUTE, not the JavaScript inside it. A value spliced into
|
|
281
|
+
a single-quoted JS string — the shape rule 2 steers you to — has a second way
|
|
282
|
+
out: a `'`. ERB escapes it to `'`, the parser decodes that straight back
|
|
283
|
+
into the value, and the bare `'` ends the string: the same
|
|
284
|
+
`Alpine Expression Error`. Route such a value through
|
|
285
|
+
`Studio::JsLiteral.in_attribute(value)`, which runs both escapers in the order
|
|
286
|
+
that works; `lib/studio/js_literal.rb` carries the full contract, identifier
|
|
287
|
+
position (`Studio::JsIdentifier`) included.
|
|
256
288
|
|
|
257
289
|
These are properties of the HOST, not of any one card, and they apply to every
|
|
258
|
-
consumer partial an app registers — not only to the specimens in this gem.
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
290
|
+
consumer partial an app registers — not only to the specimens in this gem.
|
|
291
|
+
|
|
292
|
+
They are recorded HERE because this is the host's CONTRACT, and nothing else
|
|
293
|
+
in the repo is. Plenty of files state one or both rules, but each of them is
|
|
294
|
+
describing ITSELF — a specimen header explaining its own markup, an asset
|
|
295
|
+
partial explaining its own root. Someone writing a NEW partial has no specimen
|
|
296
|
+
to read; they read the host's documentation, so that is where the rules have
|
|
297
|
+
to live.
|
|
298
|
+
|
|
299
|
+
And a specimen could not carry rule 1 even in principle, which is what settles
|
|
300
|
+
it: the style guide wraps EVERY registration's partial in a `<div>` of its own
|
|
301
|
+
— `<template x-if="…"><div><%= render … %></div></template>` — and that
|
|
302
|
+
wrapper supplies the single root the rule is about. A specimen that broke the
|
|
303
|
+
rule would still render correctly in the guide, so the specimens cannot
|
|
304
|
+
demonstrate the failure they would be documenting. Pinned by
|
|
305
|
+
`test/docs/modal_host_contract_docs_test.rb`.
|
|
306
|
+
|
|
307
|
+
#### Wallet modals moved to `solana-studio`
|
|
308
|
+
|
|
309
|
+
The Connect Wallet picker, the Web3 step-up card and the Phantom deep link used
|
|
310
|
+
to ship here as `studio/modals/wallet_connect`, `studio/modals/web3_step_up`
|
|
311
|
+
and `studio/solana/phantom_deeplink`. They now live in the **solana-studio**
|
|
312
|
+
gem as `solana_studio/modals/wallet_connect`, `solana_studio/modals/web3_step_up`
|
|
313
|
+
and `solana_studio/phantom_deeplink`; render them from those paths and read
|
|
314
|
+
that gem's README for their locals and hooks.
|
|
272
315
|
|
|
273
316
|
This is the two-template split: **BASE** is studio-engine + mcritchie-studio,
|
|
274
317
|
**WEB3 ADD** is solana-studio + turf-monster. The engine has no business
|
|
@@ -815,11 +858,14 @@ let it allocate the version — it derives the bump, commits `lib/studio/version
|
|
|
815
858
|
with its `Gemfile.lock` onto **`origin/release`**, then publishes, tags, and bumps
|
|
816
859
|
each consumer's lock. **Do not set the version by hand.** A hand-set number makes
|
|
817
860
|
the allocation read the current version as already past the last tag and skip, so
|
|
818
|
-
the hand number silently wins over the derived one
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
861
|
+
the hand number silently wins over the derived one, and the skip rolls no
|
|
862
|
+
changelog. **When it allocates, `prepare` also rolls
|
|
863
|
+
[`CHANGELOG.md`](./CHANGELOG.md)** in the same commit: everything under
|
|
864
|
+
`## Unreleased` moves beneath the new version's heading, written even when the
|
|
865
|
+
bucket is empty, and `## Unreleased` stays first and empty. It refuses the sweep,
|
|
866
|
+
with nothing published, when the roll would lie or it cannot read the file.
|
|
867
|
+
[`docs/RELEASE.md`](./docs/RELEASE.md), *Rolling `Unreleased` into a version*,
|
|
868
|
+
says exactly when it rolls, refuses or skips, and what to do by hand.
|
|
823
869
|
|
|
824
870
|
**Semver guide** — the release *derives* the bump from its members (a `breaking`
|
|
825
871
|
risk tag → major, a `feature` → minor, otherwise patch), so this is what those
|
|
@@ -191,6 +191,13 @@
|
|
|
191
191
|
Usage: <span class="spinner"></span>
|
|
192
192
|
<span class="spinner" style="--spinner-size: 2rem"></span>
|
|
193
193
|
on a colored button: <span class="spinner" style="--spinner-color: currentColor"></span>
|
|
194
|
+
the currentColor RING the engine's own CTA blocks use, matching the
|
|
195
|
+
ring turf-monster's host-only .cta-spinner draws:
|
|
196
|
+
<span class="spinner" style="--spinner-track: currentColor; --spinner-color: transparent; opacity: 0.85"></span>
|
|
197
|
+
Mind the mapping, it reads backwards: --spinner-track paints the
|
|
198
|
+
WHOLE ring and --spinner-color only the leading segment. Untuned on a
|
|
199
|
+
.btn-primary, the head is --color-cta, the button's own fill, so the
|
|
200
|
+
spinner shows nothing but its faint track.
|
|
194
201
|
Tune: --spinner-size / --spinner-thickness / --spinner-track /
|
|
195
202
|
--spinner-color / --spinner-speed
|
|
196
203
|
========================================================================== */
|
|
@@ -32,7 +32,11 @@
|
|
|
32
32
|
IMPOSES on the content partials registered in its block: a SINGLE ROOT
|
|
33
33
|
element (a template x-if clones only the first one; later siblings are
|
|
34
34
|
dropped) and NO double quote inside x-data (it closes the attribute and
|
|
35
|
-
Alpine mounts a
|
|
35
|
+
Alpine mounts a no-op). NEITHER STOPS THE RENDER, BUT ONLY ONE IS SILENT:
|
|
36
|
+
the single-root miss logs nothing at all, while the truncated x-data prints
|
|
37
|
+
"Alpine Expression Error" to the console (and rethrows it async). That
|
|
38
|
+
warning is the clue rule one never gives you, so check the console before
|
|
39
|
+
you re-read the markup.
|
|
36
40
|
%>
|
|
37
41
|
<style>
|
|
38
42
|
/* Scroll lock applied by $store.modals._sync() when the stack is non-empty.
|
|
@@ -41,11 +41,12 @@
|
|
|
41
41
|
chaining (`current()?.id`): the outer template unmounts one tick AFTER the
|
|
42
42
|
stack empties, so a bare `.id` throws on every close.
|
|
43
43
|
|
|
44
|
-
THE CONTENT PARTIALS OBEY THE SAME TWO RULES AS THE SHARED HOST'S, and
|
|
45
|
-
fail
|
|
46
|
-
one) and NO double quote inside x-data (it closes the
|
|
47
|
-
mounts a component that renders everything and does
|
|
48
|
-
|
|
44
|
+
THE CONTENT PARTIALS OBEY THE SAME TWO RULES AS THE SHARED HOST'S, and they
|
|
45
|
+
fail DIFFERENTLY: a SINGLE ROOT element (a template x-if clones only the
|
|
46
|
+
first one, logging nothing) and NO double quote inside x-data (it closes the
|
|
47
|
+
attribute and Alpine mounts a component that renders everything and does
|
|
48
|
+
nothing -- but LOGS "Alpine Expression Error" on the way). Stated in full in
|
|
49
|
+
the gem README's "Modal host" section.
|
|
49
50
|
|
|
50
51
|
AND EVERY ID REGISTERED HERE MUST BE REACHABLE, both ways round. A card that
|
|
51
52
|
opens an id no template registers shows an EMPTY panel; a template no card
|
|
@@ -10,6 +10,29 @@
|
|
|
10
10
|
|
|
11
11
|
Locals:
|
|
12
12
|
modal_store — Alpine store name backing close(). Default "modals".
|
|
13
|
+
|
|
14
|
+
ERROR INK, not a static red. The error paragraph is text-danger-ink, the
|
|
15
|
+
per-theme red Studio::ThemeResolver derives to a 4.5:1 target. It replaced
|
|
16
|
+
text-red-400. Measured through the resolver on turf-monster's real palette
|
|
17
|
+
(primary 4BAF50), on the modal card, which is bg-surface: danger-ink is 4.50
|
|
18
|
+
on the dark card 3C3853 and 5.76 on the light card ffffff, clearing AA on
|
|
19
|
+
both; text-red-400 was 3.86 and 2.89, failing both. Those are Tailwind v4's
|
|
20
|
+
red-400, about FF6467, which is what these apps compile; the v3 hex F87171
|
|
21
|
+
gives 4.03 and 2.77 and fails the same way. No STATIC red clears AA
|
|
22
|
+
on BOTH themes — theme_resolver.rb carries the measured table and derives
|
|
23
|
+
--color-danger-ink precisely to be the text red. --color-danger is the brand
|
|
24
|
+
FILL and is free to be vivid; it is not this. Guarded, executably, by
|
|
25
|
+
test/views/resend_footer_error_contrast_test.rb.
|
|
26
|
+
|
|
27
|
+
SPINNER, tuned rather than re-named. This is the engine's canonical .spinner
|
|
28
|
+
primitive (engine-motion.css), tuned through its OWN documented custom
|
|
29
|
+
properties to the currentColor ring turf-monster paints with its host-only
|
|
30
|
+
.cta-spinner — so the block looks unchanged once turf renders it, and the
|
|
31
|
+
engine names no class it cannot define. Read the mapping carefully, because
|
|
32
|
+
it looks backwards: --spinner-track colours the WHOLE ring and
|
|
33
|
+
--spinner-color colours only the leading segment. A currentColor ring with a
|
|
34
|
+
transparent gap is therefore track currentColor plus color transparent, NOT
|
|
35
|
+
the reverse, which would draw a lone quarter-arc instead.
|
|
13
36
|
%>
|
|
14
37
|
<%
|
|
15
38
|
# IDENTIFIER position ($store.<name>) — VALIDATED, never escaped: Studio::JsIdentifier.
|
|
@@ -19,9 +42,10 @@
|
|
|
19
42
|
<button @click="resendMagicLink()" :disabled="props.submitting === 'magic-link' || (props.resendCooldown || 0) > 0"
|
|
20
43
|
class="block mx-auto text-sm text-primary hover:text-primary-300 underline underline-offset-2 disabled:opacity-50 disabled:no-underline">
|
|
21
44
|
<span class="inline-flex items-center justify-center gap-1.5">
|
|
22
|
-
<span x-show="props.submitting === 'magic-link'" class="spinner" aria-hidden="true"
|
|
45
|
+
<span x-show="props.submitting === 'magic-link'" class="spinner" aria-hidden="true"
|
|
46
|
+
style="--spinner-track: currentColor; --spinner-color: transparent; opacity: 0.85"></span>
|
|
23
47
|
<span x-text="props.submitting === 'magic-link' ? 'Resending…' : ((props.resendCooldown || 0) > 0 ? ('Resend available in ' + props.resendCooldown + 's') : 'Resend link')"></span>
|
|
24
48
|
</span>
|
|
25
49
|
</button>
|
|
26
|
-
<p role="alert" x-show="props.resendError" x-cloak class="text-xs text-
|
|
50
|
+
<p role="alert" x-show="props.resendError" x-cloak class="text-xs text-danger-ink mt-3 text-center" x-text="props.resendError"></p>
|
|
27
51
|
<button @click="$store.<%= modal_store %>.close()" class="block mx-auto mt-3 text-sm text-secondary hover:text-heading transition">Close</button>
|
|
@@ -131,7 +131,7 @@
|
|
|
131
131
|
:disabled="!complete || submitting">
|
|
132
132
|
<span x-show="!submitting">Confirm & Continue</span>
|
|
133
133
|
<span x-show="submitting" class="inline-flex items-center justify-center gap-2" style="display: none;">
|
|
134
|
-
<span class="
|
|
134
|
+
<span class="spinner" aria-hidden="true" style="--spinner-track: currentColor; --spinner-color: transparent; opacity: 0.85"></span>
|
|
135
135
|
Verifying…
|
|
136
136
|
</span>
|
|
137
137
|
</button>
|
|
@@ -168,7 +168,7 @@
|
|
|
168
168
|
<button type="submit" class="btn btn-primary btn-lg w-full" :disabled="saving || !changed">
|
|
169
169
|
<span x-show="!saving" x-text="changed ? '<%= j cta_label %>' : '<%= j saved_label %>'"><%= cta_label %></span>
|
|
170
170
|
<span x-show="saving" class="inline-flex items-center justify-center gap-2" style="display: none;">
|
|
171
|
-
<span class="
|
|
171
|
+
<span class="spinner" aria-hidden="true" style="--spinner-track: currentColor; --spinner-color: transparent; opacity: 0.85"></span>
|
|
172
172
|
<span x-text="progressLabel || '<%= j saving_label %>'"><%= saving_label %></span>
|
|
173
173
|
</span>
|
|
174
174
|
</button>
|
|
@@ -377,7 +377,7 @@
|
|
|
377
377
|
</template>
|
|
378
378
|
<button type="submit" :disabled="submitting"
|
|
379
379
|
class="btn btn-primary btn-lg w-full gap-2 disabled:cursor-wait">
|
|
380
|
-
<span x-show="submitting" class="
|
|
380
|
+
<span x-show="submitting" class="spinner" aria-hidden="true" style="--spinner-track: currentColor; --spinner-color: transparent; opacity: 0.85"></span>
|
|
381
381
|
<span x-text="submitting ? 'Saving…' : 'Save and continue'"></span>
|
|
382
382
|
</button>
|
|
383
383
|
</form>
|
data/lib/studio/version.rb
CHANGED