studio-engine 0.4.8 → 0.4.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 +14 -0
- data/app/views/studio/modals/_host.html.erb +8 -0
- data/app/views/studio/modals/blocks/_success_card.html.erb +140 -53
- 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: 1815c9f9ea9e2b75d83b6873802726bd1a3aeee90ac556db5454c0f98adb9c26
|
|
4
|
+
data.tar.gz: 70ef1cfae8480f366fd135544ff20453ecb939c30e8f584878beb06c1cbb8efc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8046beba0b56403dcb54557949b64f9779b581b0c82f729a96fccfe562bedb8fd168345b84fe9c2ce9be3683d743a8f9d6102b2147615f33fc81d9e4a1c95ccd
|
|
7
|
+
data.tar.gz: 4e3a7f33ae0b7d9b549f1c9dd9443de68511c66eee29a43a9e296c235adddf38f4c9ba1b13521f8f8aec9581e9ef098381b4cbbc68e59c0f20ab9933e50ecb1f
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
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`. Both consumer Rails apps pin to a tag in their `Gemfile`; bumping the tag is a release.
|
|
4
4
|
|
|
5
|
+
## v0.4.9 (2026-05-23)
|
|
6
|
+
|
|
7
|
+
Modal success_card upgrades — canonical "celebration" look for any modal that needs an Entry / Action / Payment confirmed card. All options additive; existing callers unaffected.
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- **`_success_card` — `large_title:`** boolean. Bumps the headline from `text-lg` to `text-3xl` (the celebration look).
|
|
11
|
+
- **`_success_card` — `title_key:` / `message_key:`** Alpine-expression locals for live-driven headline + subtitle. Lets a card track a store as labels mutate without re-mounting (paired with the same option on `_processing_card` in v0.4.6).
|
|
12
|
+
- **`_success_card` — `tx_solana:`** boolean. Upgrades the tx-signature explorer link from the plain underlined-hash style to a boxed pill with the Solana brand mark (gradient SVG, three diagonal bars) on the left and a launch arrow on the right. Same `tx_signature_key` Alpine expression drives both variants.
|
|
13
|
+
- **`_success_card` — `cta_drain:`** boolean. When paired with `auto_redirect_url_key`, the countdown drains as a translucent overlay on the CTA button itself — no separate progress bar / "Redirecting in Xs…" text. The celebration look. Uses the new `@keyframes studio-modal-drain` defined in the host's style block.
|
|
14
|
+
- **`_success_card` — yield block.** Callers can pass an inline block; the card renders it below the CTA. Used by turf-monster's onchain-tx modal to slot in the seeds-bar + level-up celebration without forking the partial.
|
|
15
|
+
|
|
16
|
+
### Migration
|
|
17
|
+
None required. Apps that don't set the new options keep the existing default look.
|
|
18
|
+
|
|
5
19
|
## v0.4.8 (2026-05-23)
|
|
6
20
|
|
|
7
21
|
Bugfix follow-up to v0.4.7. The v0.4.7 fix removed the ERB-escape example from the doc comment, but the same comment still referenced the bug it had just fixed using literal ERB-tag characters (the words "ERB <%# %> terminates at the first %> sequence" sit inside an ERB comment that uses `%>` as its terminator — recursive footgun). The first inline `%>` ended the outer comment and the rest leaked again.
|
|
@@ -13,6 +13,14 @@
|
|
|
13
13
|
Combined with the fixed backdrop on the host below, this keeps the
|
|
14
14
|
page beneath any modal from scrolling on wheel / touch / spacebar. */
|
|
15
15
|
body.modal-open { overflow: hidden; }
|
|
16
|
+
|
|
17
|
+
/* Drain-bar keyframe used by studio/modals/blocks/_success_card when
|
|
18
|
+
cta_drain is set — the CTA button hosts a translucent overlay that
|
|
19
|
+
shrinks from full to empty over the auto-redirect duration. */
|
|
20
|
+
@keyframes studio-modal-drain {
|
|
21
|
+
from { transform: scaleX(1); }
|
|
22
|
+
to { transform: scaleX(0); }
|
|
23
|
+
}
|
|
16
24
|
</style>
|
|
17
25
|
|
|
18
26
|
<script>
|
|
@@ -1,53 +1,75 @@
|
|
|
1
1
|
<%#
|
|
2
|
-
Reusable success card
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
Locals — every one is optional EXCEPT title:
|
|
10
|
-
|
|
11
|
-
title:
|
|
12
|
-
|
|
2
|
+
Reusable success card. The default style is the studio-canonical
|
|
3
|
+
"Entry / Action confirmed" celebration screen: green check (or
|
|
4
|
+
custom icon), title, message, optional explorer link, primary CTA
|
|
5
|
+
with optional drain-bar countdown, optional confetti. Apps
|
|
6
|
+
compose this inside a modal content partial; the host shell
|
|
7
|
+
(backdrop, card chrome, transitions) is provided by the modal host.
|
|
8
|
+
|
|
9
|
+
Locals — every one is optional EXCEPT title (or title_key):
|
|
10
|
+
|
|
11
|
+
title: static headline string
|
|
12
|
+
title_key: Alpine expression for the headline
|
|
13
|
+
(e.g. "$store.solanaModal.title") rendered
|
|
14
|
+
via x-text. Takes priority over title.
|
|
15
|
+
message: static sub-headline string
|
|
16
|
+
message_key: Alpine expression for the message
|
|
17
|
+
(e.g. "$store.solanaModal.message").
|
|
18
|
+
large_title: boolean. Bigger text-3xl headline; the
|
|
19
|
+
default is text-lg.
|
|
13
20
|
|
|
14
21
|
icon_emoji: renders the given emoji as the icon instead
|
|
15
|
-
of the default green check
|
|
16
|
-
icon_color:
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
of the default green check.
|
|
23
|
+
icon_color: color token for the default check; one of
|
|
24
|
+
'primary' (default), 'success', 'warning',
|
|
25
|
+
'mint' (when an explicit Solana-ish accent
|
|
26
|
+
is wanted).
|
|
27
|
+
|
|
28
|
+
tx_signature_key: Alpine expression for a Solana tx signature
|
|
29
|
+
(e.g. "props.txSignature"). When truthy,
|
|
30
|
+
renders an explorer link. Default style is
|
|
31
|
+
a plain underlined hash; set tx_solana to
|
|
32
|
+
upgrade to the boxed branded variant.
|
|
33
|
+
tx_solana: boolean. Renders the tx_signature_key link
|
|
34
|
+
as a boxed pill with the Solana brand mark
|
|
35
|
+
on the left and a launch arrow on the
|
|
36
|
+
right. The "canonical" tx link.
|
|
24
37
|
|
|
25
38
|
cta_label: primary CTA button text.
|
|
26
|
-
cta_href_key: Alpine expression for the button's href
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
39
|
+
cta_href_key: Alpine expression for the button's href.
|
|
40
|
+
Mutually exclusive with cta_event.
|
|
41
|
+
cta_event: window event name dispatched on click.
|
|
42
|
+
Mutually exclusive with cta_href_key.
|
|
43
|
+
cta_drain: boolean. When set together with
|
|
44
|
+
auto_redirect_url_key, the countdown
|
|
45
|
+
drains as a translucent overlay on the CTA
|
|
46
|
+
button itself (no separate progress bar /
|
|
47
|
+
"Redirecting in Xs…" line). The canonical
|
|
48
|
+
celebration look.
|
|
32
49
|
|
|
33
50
|
secondary_label: optional secondary action label.
|
|
34
51
|
secondary_event: optional secondary action dispatch event.
|
|
35
52
|
|
|
36
|
-
auto_redirect_url_key: Alpine expression for the redirect URL.
|
|
37
|
-
set, an internal countdown ticks down
|
|
38
|
-
navigates when it hits zero.
|
|
39
|
-
|
|
53
|
+
auto_redirect_url_key: Alpine expression for the redirect URL.
|
|
54
|
+
When set, an internal countdown ticks down
|
|
55
|
+
and navigates when it hits zero. Pairs
|
|
56
|
+
with cta_drain.
|
|
40
57
|
auto_redirect_seconds: total seconds for the countdown. Default 5.
|
|
41
58
|
|
|
42
|
-
confetti:
|
|
43
|
-
|
|
44
|
-
|
|
59
|
+
confetti: fires window.fireSuccessConfetti() ~100ms
|
|
60
|
+
after the card mounts.
|
|
61
|
+
|
|
62
|
+
Block: callers can pass an inline block that the card renders below
|
|
63
|
+
the CTA — used by turf-monster's onchain-tx modal to inject the
|
|
64
|
+
seeds bar + level-up celebration, which is product-specific UI.
|
|
45
65
|
%>
|
|
46
66
|
<%
|
|
47
67
|
icon_color = local_assigns[:icon_color] || 'primary'
|
|
48
68
|
redirect_secs = local_assigns[:auto_redirect_seconds] || 5
|
|
49
69
|
has_redirect = !!local_assigns[:auto_redirect_url_key]
|
|
50
70
|
fire_confetti = !!local_assigns[:confetti]
|
|
71
|
+
large_title = !!local_assigns[:large_title]
|
|
72
|
+
use_drain = has_redirect && !!local_assigns[:cta_drain]
|
|
51
73
|
|
|
52
74
|
data_attr = "{
|
|
53
75
|
_remaining: #{redirect_secs},
|
|
@@ -92,29 +114,66 @@
|
|
|
92
114
|
</div>
|
|
93
115
|
<% end %>
|
|
94
116
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
117
|
+
<%# Title — large_title swaps text-lg for text-3xl. Either static or
|
|
118
|
+
Alpine-expression-driven via title_key. %>
|
|
119
|
+
<% title_class = large_title ? "text-3xl font-bold text-heading mb-2" : "text-lg font-bold text-heading mb-1" %>
|
|
120
|
+
<% if local_assigns[:title_key] %>
|
|
121
|
+
<p class="<%= title_class %>" x-text="<%= title_key %>"></p>
|
|
122
|
+
<% else %>
|
|
123
|
+
<p class="<%= title_class %>"><%= title %></p>
|
|
124
|
+
<% end %>
|
|
125
|
+
|
|
126
|
+
<% if local_assigns[:message_key] %>
|
|
127
|
+
<p class="text-sm text-secondary mb-4" x-text="<%= message_key %>"></p>
|
|
128
|
+
<% elsif local_assigns[:message] %>
|
|
129
|
+
<p class="text-sm text-secondary mb-4"><%= message %></p>
|
|
98
130
|
<% end %>
|
|
99
131
|
|
|
100
|
-
<%# Explorer link —
|
|
101
|
-
|
|
132
|
+
<%# Explorer link — boxed branded variant when tx_solana is set,
|
|
133
|
+
plain underlined hash otherwise. Both controlled by the same
|
|
134
|
+
tx_signature_key. %>
|
|
102
135
|
<% if local_assigns[:tx_signature_key] %>
|
|
103
|
-
|
|
104
|
-
<
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
<
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
136
|
+
<% if local_assigns[:tx_solana] %>
|
|
137
|
+
<div x-show="<%= tx_signature_key %>" class="mb-3">
|
|
138
|
+
<a :href="'https://explorer.solana.com/tx/' + (<%= tx_signature_key %>) + (typeof clusterParam !== 'undefined' ? clusterParam : '')"
|
|
139
|
+
target="_blank" rel="noopener"
|
|
140
|
+
class="inline-flex items-center gap-2 px-3 py-1.5 rounded-lg border border-subtle hover:border-primary/50 transition group"
|
|
141
|
+
style="background: rgba(var(--color-primary-500-rgb), 0.06);">
|
|
142
|
+
<svg width="14" height="11" viewBox="0 0 397 311" fill="none">
|
|
143
|
+
<defs>
|
|
144
|
+
<linearGradient id="studio-solana-grad" x1="361" y1="-9" x2="153" y2="389" gradientUnits="userSpaceOnUse">
|
|
145
|
+
<stop offset="0" stop-color="#00FFA3"/>
|
|
146
|
+
<stop offset="1" stop-color="#DC1FFF"/>
|
|
147
|
+
</linearGradient>
|
|
148
|
+
</defs>
|
|
149
|
+
<path d="M65 234c2-2 6-4 9-4h317c6 0 9 7 5 11l-63 63c-2 2-6 4-9 4H6c-6 0-9-7-5-11l64-63z" fill="url(#studio-solana-grad)"/>
|
|
150
|
+
<path d="M65 4c2-2 6-4 9-4h317c6 0 9 7 5 11l-63 63c-2 2-6 4-9 4H6c-6 0-9-7-5-11L65 4z" fill="url(#studio-solana-grad)"/>
|
|
151
|
+
<path d="M333 119c-2-2-6-4-9-4H7c-6 0-9 7-5 11l63 63c2 2 6 4 9 4h317c6 0 9-7 5-11l-63-63z" fill="url(#studio-solana-grad)"/>
|
|
152
|
+
</svg>
|
|
153
|
+
<span class="font-mono text-[11px] text-secondary group-hover:text-primary transition" x-text="(<%= tx_signature_key %>) ? ((<%= tx_signature_key %>).substring(0, 16) + '…') : ''"></span>
|
|
154
|
+
<svg class="w-3 h-3 text-muted group-hover:text-primary transition" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"/></svg>
|
|
155
|
+
</a>
|
|
156
|
+
</div>
|
|
157
|
+
<% else %>
|
|
158
|
+
<div x-show="<%= tx_signature_key %>" class="mb-5">
|
|
159
|
+
<a :href="'https://explorer.solana.com/tx/' + (<%= tx_signature_key %>) + (typeof clusterParam !== 'undefined' ? clusterParam : '')"
|
|
160
|
+
target="_blank" rel="noopener"
|
|
161
|
+
class="inline-flex items-center gap-1.5 text-xs font-mono text-secondary hover:text-primary underline underline-offset-2">
|
|
162
|
+
<span x-text="(<%= tx_signature_key %>) ? ((<%= tx_signature_key %>).slice(0, 8) + '…' + (<%= tx_signature_key %>).slice(-4)) : ''"></span>
|
|
163
|
+
<svg class="w-3 h-3" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
|
164
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M14 5l7 7m0 0l-7 7m7-7H3"/>
|
|
165
|
+
</svg>
|
|
166
|
+
</a>
|
|
167
|
+
</div>
|
|
168
|
+
<% end %>
|
|
113
169
|
<% end %>
|
|
114
170
|
|
|
115
|
-
<%# Auto-redirect countdown —
|
|
116
|
-
|
|
117
|
-
|
|
171
|
+
<%# Auto-redirect countdown — two layouts.
|
|
172
|
+
cta_drain: countdown drains as overlay on the CTA button itself
|
|
173
|
+
(the celebration look, no separate progress bar).
|
|
174
|
+
default: separate progress bar above + "Redirecting in Xs…"
|
|
175
|
+
text + standard CTA below. %>
|
|
176
|
+
<% if has_redirect && !use_drain %>
|
|
118
177
|
<div class="w-full rounded-full overflow-hidden mb-2" style="height:6px;background:rgba(128,128,128,0.2)">
|
|
119
178
|
<div :style="'height:100%;border-radius:9999px;background:var(--color-cta);transition:width 1s linear;width:' + (_remaining / _total * 100) + '%'"></div>
|
|
120
179
|
</div>
|
|
@@ -123,9 +182,30 @@
|
|
|
123
182
|
</p>
|
|
124
183
|
<% end %>
|
|
125
184
|
|
|
126
|
-
<%# Primary CTA —
|
|
185
|
+
<%# Primary CTA — three flavors:
|
|
186
|
+
1. cta_drain + auto_redirect: countdown drains over the button
|
|
187
|
+
2. cta_href_key: anchor
|
|
188
|
+
3. cta_event: button dispatching event %>
|
|
127
189
|
<% if local_assigns[:cta_label] %>
|
|
128
|
-
<% if local_assigns[:cta_href_key] %>
|
|
190
|
+
<% if use_drain && local_assigns[:cta_href_key] %>
|
|
191
|
+
<a :href="<%= cta_href_key %>"
|
|
192
|
+
class="relative overflow-hidden block w-full px-4 py-2.5 rounded-lg font-bold text-sm text-white text-center transition no-underline"
|
|
193
|
+
style="background: var(--color-cta);">
|
|
194
|
+
<div class="absolute inset-0 pointer-events-none origin-left"
|
|
195
|
+
style="background: rgba(255,255,255,0.18);"
|
|
196
|
+
:style="{ animation: 'studio-modal-drain ' + _total + 's linear forwards' }"></div>
|
|
197
|
+
<span class="relative z-10"><%= cta_label %></span>
|
|
198
|
+
</a>
|
|
199
|
+
<% elsif use_drain && local_assigns[:cta_event] %>
|
|
200
|
+
<button @click="$dispatch('<%= cta_event %>')"
|
|
201
|
+
class="relative overflow-hidden block w-full px-4 py-2.5 rounded-lg font-bold text-sm text-white text-center transition no-underline"
|
|
202
|
+
style="background: var(--color-cta);">
|
|
203
|
+
<div class="absolute inset-0 pointer-events-none origin-left"
|
|
204
|
+
style="background: rgba(255,255,255,0.18);"
|
|
205
|
+
:style="{ animation: 'studio-modal-drain ' + _total + 's linear forwards' }"></div>
|
|
206
|
+
<span class="relative z-10"><%= cta_label %></span>
|
|
207
|
+
</button>
|
|
208
|
+
<% elsif local_assigns[:cta_href_key] %>
|
|
129
209
|
<a :href="<%= cta_href_key %>" class="btn btn-primary w-full"><%= cta_label %></a>
|
|
130
210
|
<% elsif local_assigns[:cta_event] %>
|
|
131
211
|
<button @click="$dispatch('<%= cta_event %>')" class="btn btn-primary w-full"><%= cta_label %></button>
|
|
@@ -138,4 +218,11 @@
|
|
|
138
218
|
<%= secondary_label %>
|
|
139
219
|
</button>
|
|
140
220
|
<% end %>
|
|
221
|
+
|
|
222
|
+
<%# Optional inline block — appended below the CTA so callers can
|
|
223
|
+
slot in product-specific celebration UI (seeds bar, badges,
|
|
224
|
+
stat increments) without forking the partial. %>
|
|
225
|
+
<% if block_given? %>
|
|
226
|
+
<div class="mt-3"><%= yield %></div>
|
|
227
|
+
<% end %>
|
|
141
228
|
</div>
|
data/lib/studio/version.rb
CHANGED