studio-engine 0.62.0 → 0.62.2
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/app/views/studio/modals/_crop_photo.html.erb +1 -1
- data/app/views/studio/modals/_web3_step_up.html.erb +1 -1
- data/app/views/studio/modals/auth/_resend_footer.html.erb +1 -1
- data/app/views/studio/modals/blocks/_birthday.html.erb +1 -1
- data/app/views/studio/modals/blocks/_entry_confirmed.html.erb +20 -0
- data/app/views/studio/modals/blocks/_error_card.html.erb +5 -1
- data/app/views/studio/modals/blocks/_leveling_activity.html.erb +1 -1
- data/app/views/studio/modals/blocks/_rail_row.html.erb +15 -1
- data/app/views/studio/modals/onboarding/_first_name.html.erb +1 -1
- data/app/views/studio/modals/shared/_age_attestation.html.erb +1 -1
- data/app/views/style/_modals.html.erb +8 -8
- data/app/views/style/modals/_auth.html.erb +2 -2
- data/app/views/style/modals/_wallet_connect.html.erb +1 -1
- data/lib/studio/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 822c72023af8d108848e67535194fa5a115443b4faaeebd7d9adc931ffcc7678
|
|
4
|
+
data.tar.gz: a1ef68303215291461d2e07b5237506c57fc6ab83e4fd8b9edc9f18a39e19e51
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dac77f69b4c34943fe3bd8f8a790dbbadfd8ebbc4e80a17595af78fff7f054e9321ea92062769c474ae56b70da09d051a9d45801f0f0aff2197fedc794deaaba
|
|
7
|
+
data.tar.gz: 723edaf2959e13979ede94523e578ce1d612cbe9911dfd4f1340de8a77b73fa2a2a2ee2c866f3f8078a780455af3baeafd5f369fb232a90a024987ed409a84e1
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
<h3 class="text-heading font-bold text-lg text-center mb-4">Crop Photo</h3>
|
|
31
31
|
|
|
32
32
|
<template x-if="error">
|
|
33
|
-
<p class="text-red-400 text-sm mb-3 text-center" x-text="error"></p>
|
|
33
|
+
<p role="alert" class="text-red-400 text-sm mb-3 text-center" x-text="error"></p>
|
|
34
34
|
</template>
|
|
35
35
|
|
|
36
36
|
<input type="file" x-ref="filePicker" @change="onFilePicked($event)" accept="image/*" class="hidden">
|
|
@@ -261,7 +261,7 @@
|
|
|
261
261
|
</template>
|
|
262
262
|
|
|
263
263
|
<template x-if="error">
|
|
264
|
-
<p class="text-red-400 text-sm mt-3 text-center" x-text="error"></p>
|
|
264
|
+
<p role="alert" class="text-red-400 text-sm mt-3 text-center" x-text="error"></p>
|
|
265
265
|
</template>
|
|
266
266
|
|
|
267
267
|
<%# SECONDARY — always reachable, so a user whose remembered wallet is the
|
|
@@ -21,5 +21,5 @@
|
|
|
21
21
|
<span x-text="props.submitting === 'magic-link' ? 'Resending…' : ((props.resendCooldown || 0) > 0 ? ('Resend available in ' + props.resendCooldown + 's') : 'Resend link')"></span>
|
|
22
22
|
</span>
|
|
23
23
|
</button>
|
|
24
|
-
<p x-show="props.resendError" x-cloak class="text-xs text-red-400 mt-3 text-center" x-text="props.resendError"></p>
|
|
24
|
+
<p role="alert" x-show="props.resendError" x-cloak class="text-xs text-red-400 mt-3 text-center" x-text="props.resendError"></p>
|
|
25
25
|
<button @click="$store.<%= modal_store %>.close()" class="block mx-auto mt-3 text-sm text-secondary hover:text-heading transition">Close</button>
|
|
@@ -112,7 +112,7 @@
|
|
|
112
112
|
A refusal is not an error, and showing them in the same red paragraph is
|
|
113
113
|
what let the dead end hide. %>
|
|
114
114
|
<template x-if="error">
|
|
115
|
-
<p class="text-red-400 text-sm mb-3" x-text="error"></p>
|
|
115
|
+
<p role="alert" class="text-red-400 text-sm mb-3" x-text="error"></p>
|
|
116
116
|
</template>
|
|
117
117
|
|
|
118
118
|
<%# Disabled ONLY for an incomplete date or an in-flight submit. It used to be
|
|
@@ -51,6 +51,13 @@
|
|
|
51
51
|
seeds_total_key — Alpine expr: new seeds total. Default "props.seedsTotal".
|
|
52
52
|
seeds_per_level — Integer seeds per level. Default 100.
|
|
53
53
|
free_entry_label — reward copy on a level-up. Default "Free Entry Earned 🎟️".
|
|
54
|
+
secondary_label — optional secondary action label under the CTA (e.g.
|
|
55
|
+
"Dismiss"). Forwarded to _success_card, which renders a
|
|
56
|
+
button dispatching secondary_event.
|
|
57
|
+
secondary_event — window event name for that button. BOTH are required or
|
|
58
|
+
NEITHER renders, matching how _success_card and _error_card
|
|
59
|
+
already gate the pair — a label with no event is a button
|
|
60
|
+
that does nothing.
|
|
54
61
|
%>
|
|
55
62
|
<%
|
|
56
63
|
modal_store = local_assigns.fetch(:modal_store, "modals")
|
|
@@ -70,6 +77,8 @@
|
|
|
70
77
|
seeds_total_key = local_assigns.fetch(:seeds_total_key, "props.seedsTotal")
|
|
71
78
|
seeds_per_level = local_assigns.fetch(:seeds_per_level, 100)
|
|
72
79
|
free_entry_label = local_assigns.fetch(:free_entry_label, "Free Entry Earned 🎟️")
|
|
80
|
+
secondary_label = local_assigns[:secondary_label]
|
|
81
|
+
secondary_event = local_assigns[:secondary_event]
|
|
73
82
|
|
|
74
83
|
sc_locals = {
|
|
75
84
|
large_title: true,
|
|
@@ -89,6 +98,17 @@
|
|
|
89
98
|
else
|
|
90
99
|
sc_locals[:message] = subtitle
|
|
91
100
|
end
|
|
101
|
+
|
|
102
|
+
# BOTH OR NEITHER, deliberately. sc_locals was a FIXED hash, so a consumer
|
|
103
|
+
# adopting this card in place of its own fork lost any secondary action it had
|
|
104
|
+
# SILENTLY — there was no error, the button simply stopped existing. That is
|
|
105
|
+
# what blocked turf-monster's entry-confirmed defork: its card ends in a
|
|
106
|
+
# "Dismiss" link, and the call site sits inside a <template x-if>, which takes
|
|
107
|
+
# ONE root, so the button cannot be kept outside the block either.
|
|
108
|
+
if secondary_label.present? && secondary_event.present?
|
|
109
|
+
sc_locals[:secondary_label] = secondary_label
|
|
110
|
+
sc_locals[:secondary_event] = secondary_event
|
|
111
|
+
end
|
|
92
112
|
%>
|
|
93
113
|
<%# props getter + clusterParam live on the root scope so _success_card's nested
|
|
94
114
|
Alpine expressions (props.txSignature, props.lobbyUrl, clusterParam) resolve up
|
|
@@ -25,7 +25,11 @@
|
|
|
25
25
|
icon_emoji = local_assigns[:icon_emoji] || "⏳" # ⏳
|
|
26
26
|
cta_label = local_assigns[:cta_label] || 'Refresh'
|
|
27
27
|
%>
|
|
28
|
-
|
|
28
|
+
<%# role="alert" on the CARD, not on its message: the message is server-rendered
|
|
29
|
+
static text, so it never "changes" for a live region to notice. The modal host
|
|
30
|
+
renders content through <template x-if>, so this whole card ENTERS the DOM when
|
|
31
|
+
the failure happens — which is the event a screen reader can announce. %>
|
|
32
|
+
<div role="alert" class="text-center py-6">
|
|
29
33
|
<div class="text-5xl mb-4 leading-none"><%= icon_emoji %></div>
|
|
30
34
|
<p class="text-sm text-heading font-semibold mb-2"><%= title %></p>
|
|
31
35
|
|
|
@@ -131,7 +131,7 @@
|
|
|
131
131
|
<% end %>
|
|
132
132
|
|
|
133
133
|
<template x-if="error">
|
|
134
|
-
<p class="text-red-400 text-sm mb-3" x-text="error"></p>
|
|
134
|
+
<p role="alert" class="text-red-400 text-sm mb-3" x-text="error"></p>
|
|
135
135
|
</template>
|
|
136
136
|
|
|
137
137
|
<form @submit.prevent="save()" class="space-y-4">
|
|
@@ -78,8 +78,22 @@
|
|
|
78
78
|
tile_style = icon_bg.present? ? "background-color:#{icon_bg}" : nil
|
|
79
79
|
tile_bg_class = icon_bg.present? ? nil : "bg-primary"
|
|
80
80
|
%>
|
|
81
|
+
<%# on_click is marked html_safe because it is CODE, not content. content_tag
|
|
82
|
+
escapes through ERB::Util.unwrapped_html_escape, which no-ops on an html_safe
|
|
83
|
+
String, so the handler reaches the attribute exactly as the caller wrote it:
|
|
84
|
+
f('a'), not the entity-escaped form. A browser recovered from the escaped
|
|
85
|
+
version and Alpine fired either way, so this was invisible on screen; what it
|
|
86
|
+
broke was every consumer test that reads the markup.
|
|
87
|
+
|
|
88
|
+
IT IS STILL SAFE FOR DOUBLE QUOTES. content_tag quote-escapes an attribute
|
|
89
|
+
VALUE regardless of html_safe, so a double-quoted expression is entity-encoded
|
|
90
|
+
and still works. An earlier attempt emitted the handler through raw in literal
|
|
91
|
+
ERB instead, which had no such protection: it broke out of the attribute and
|
|
92
|
+
silently narrowed the contract to single quotes only.
|
|
93
|
+
|
|
94
|
+
Everything else here stays escaped, because everything else is content. %>
|
|
81
95
|
<%= content_tag(soon ? :div : :button, type: (soon ? nil : "button"),
|
|
82
|
-
"@click": on_click,
|
|
96
|
+
"@click": on_click&.html_safe,
|
|
83
97
|
class: "w-full flex items-center gap-4 p-4 rounded-xl #{border_class} bg-inset#{soon ? '' : ' transition text-left'}",
|
|
84
98
|
data: data_attrs.presence) do %>
|
|
85
99
|
<span class="shrink-0 w-10 h-10 rounded-lg flex items-center justify-center <%= icon_class %> <%= tile_bg_class %>"
|
|
@@ -122,7 +122,7 @@
|
|
|
122
122
|
class="input-field">
|
|
123
123
|
</div>
|
|
124
124
|
<template x-if="error">
|
|
125
|
-
<p class="text-red-400 text-xs mb-3" x-text="error"></p>
|
|
125
|
+
<p role="alert" class="text-red-400 text-xs mb-3" x-text="error"></p>
|
|
126
126
|
</template>
|
|
127
127
|
<button type="submit" :disabled="submitting"
|
|
128
128
|
class="btn btn-primary btn-lg w-full gap-2 disabled:cursor-wait">
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
state (18+ in most states; 19+ in AL/NE; 21+ in IA/MA/VA).
|
|
29
29
|
</span>
|
|
30
30
|
</label>
|
|
31
|
-
<p x-show="<%= error_model %>" x-cloak class="text-xs text-red-400 mt-1.5 ml-6">
|
|
31
|
+
<p role="alert" x-show="<%= error_model %>" x-cloak class="text-xs text-red-400 mt-1.5 ml-6">
|
|
32
32
|
Please confirm you are of legal age to continue.
|
|
33
33
|
</p>
|
|
34
34
|
</div>
|
|
@@ -566,7 +566,7 @@
|
|
|
566
566
|
|
|
567
567
|
<%# 1. AUTH suite %>
|
|
568
568
|
<%# ===================================================================== %>
|
|
569
|
-
<section class="space-y-5">
|
|
569
|
+
<section id="modals-auth" class="space-y-5">
|
|
570
570
|
<div class="space-y-1">
|
|
571
571
|
<h3 class="text-xl font-bold text-heading">Auth</h3>
|
|
572
572
|
<p class="text-muted text-sm">
|
|
@@ -650,7 +650,7 @@
|
|
|
650
650
|
owns: the person's name, their birthday, their picture. Grouping by
|
|
651
651
|
subject rather than by moment also stops the guide claiming a chain it
|
|
652
652
|
cannot show, now that the wallet step lives with the wallet cards. %>
|
|
653
|
-
<section class="space-y-5">
|
|
653
|
+
<section id="modals-profile" class="space-y-5">
|
|
654
654
|
<div class="space-y-1">
|
|
655
655
|
<h3 class="text-xl font-bold text-heading">Profile</h3>
|
|
656
656
|
<p class="text-muted text-sm">
|
|
@@ -838,7 +838,7 @@
|
|
|
838
838
|
"Quest N of N" counter — the with/without fork is gone. The two "updated"
|
|
839
839
|
cards open the same modal id straight at the celebrate state (props.celebrate),
|
|
840
840
|
exactly like the Auth cards open a given step. %>
|
|
841
|
-
<section class="space-y-5">
|
|
841
|
+
<section id="modals-profile-leveling" class="space-y-5">
|
|
842
842
|
<div class="space-y-1">
|
|
843
843
|
<div class="flex flex-wrap items-center gap-3">
|
|
844
844
|
<h3 class="text-xl font-bold text-heading">Profile Leveling</h3>
|
|
@@ -1046,7 +1046,7 @@
|
|
|
1046
1046
|
<%# 2. WEB3 — the wallet + on-chain modals, in the order a player meets them. %>
|
|
1047
1047
|
<%# Gated by :web3; off = disabled-but-present-yet-openable. %>
|
|
1048
1048
|
<%# ===================================================================== %>
|
|
1049
|
-
<section class="space-y-5">
|
|
1049
|
+
<section id="modals-web3" class="space-y-5">
|
|
1050
1050
|
<div class="space-y-1">
|
|
1051
1051
|
<div class="flex flex-wrap items-center gap-3">
|
|
1052
1052
|
<h3 class="text-xl font-bold text-heading">Web3</h3>
|
|
@@ -1447,7 +1447,7 @@
|
|
|
1447
1447
|
<%# 3. CONTEST ENTRY & ELIGIBILITY — moved directly under Web3. The %>
|
|
1448
1448
|
<%# walked entry flow (glow follows), plus the honest web2/web3 map. %>
|
|
1449
1449
|
<%# ===================================================================== %>
|
|
1450
|
-
<section class="space-y-5">
|
|
1450
|
+
<section id="modals-contest-entry" class="space-y-5">
|
|
1451
1451
|
<div class="space-y-1">
|
|
1452
1452
|
<div class="flex flex-wrap items-center gap-3">
|
|
1453
1453
|
<h3 class="text-xl font-bold text-heading">Contest entry & eligibility</h3>
|
|
@@ -1597,7 +1597,7 @@
|
|
|
1597
1597
|
<%# ===================================================================== %>
|
|
1598
1598
|
<%# 5. SYSTEM AND STATUS (reusable card blocks) %>
|
|
1599
1599
|
<%# ===================================================================== %>
|
|
1600
|
-
<section class="space-y-5">
|
|
1600
|
+
<section id="modals-system-status" class="space-y-5">
|
|
1601
1601
|
<div class="space-y-1">
|
|
1602
1602
|
<h3 class="text-xl font-bold text-heading">System & status</h3>
|
|
1603
1603
|
<p class="text-muted text-sm">
|
|
@@ -1713,7 +1713,7 @@
|
|
|
1713
1713
|
<%# ===================================================================== %>
|
|
1714
1714
|
<%# 6. TEMPLATES (copy-from archetypes) %>
|
|
1715
1715
|
<%# ===================================================================== %>
|
|
1716
|
-
<section class="space-y-5">
|
|
1716
|
+
<section id="modals-templates" class="space-y-5">
|
|
1717
1717
|
<div class="space-y-1">
|
|
1718
1718
|
<h3 class="text-xl font-bold text-heading">Templates</h3>
|
|
1719
1719
|
<p class="text-muted text-sm">
|
|
@@ -1747,7 +1747,7 @@
|
|
|
1747
1747
|
<%# ===================================================================== %>
|
|
1748
1748
|
<%# 7. REWARDS / leveling (gated by Studio.feature?(:leveling)) %>
|
|
1749
1749
|
<%# ===================================================================== %>
|
|
1750
|
-
<section class="space-y-5">
|
|
1750
|
+
<section id="modals-rewards" class="space-y-5">
|
|
1751
1751
|
<div class="space-y-1">
|
|
1752
1752
|
<div class="flex flex-wrap items-center gap-3">
|
|
1753
1753
|
<h3 class="text-xl font-bold text-heading">Rewards</h3>
|
|
@@ -164,7 +164,7 @@
|
|
|
164
164
|
<span x-text="props.submitting === 'google' ? 'Waiting for Google…' : 'Google'"></span>
|
|
165
165
|
</button>
|
|
166
166
|
<template x-if="props.googleError">
|
|
167
|
-
<p class="text-red-400 text-xs -mt-2 mb-3" x-text="props.googleError"></p>
|
|
167
|
+
<p role="alert" class="text-red-400 text-xs -mt-2 mb-3" x-text="props.googleError"></p>
|
|
168
168
|
</template>
|
|
169
169
|
|
|
170
170
|
<%# 2. Solana — progresses to the Connect Wallet picker modal. Gated on
|
|
@@ -200,7 +200,7 @@
|
|
|
200
200
|
disabled_expr: "!!props.submitting" %>
|
|
201
201
|
</div>
|
|
202
202
|
<template x-if="props.formError">
|
|
203
|
-
<p class="text-red-400 text-xs mb-3" x-text="props.formError"></p>
|
|
203
|
+
<p role="alert" class="text-red-400 text-xs mb-3" x-text="props.formError"></p>
|
|
204
204
|
</template>
|
|
205
205
|
<button type="submit" :disabled="!!props.submitting"
|
|
206
206
|
class="btn btn-neutral btn-lg w-full gap-2 disabled:cursor-wait">
|
|
@@ -166,7 +166,7 @@
|
|
|
166
166
|
</div>
|
|
167
167
|
|
|
168
168
|
<template x-if="error">
|
|
169
|
-
<p class="text-red-400 text-sm mt-3 text-center" x-text="error"></p>
|
|
169
|
+
<p role="alert" class="text-red-400 text-sm mt-3 text-center" x-text="error"></p>
|
|
170
170
|
</template>
|
|
171
171
|
|
|
172
172
|
<button type="button" @click="back()" :disabled="connecting"
|
data/lib/studio/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: studio-engine
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.62.
|
|
4
|
+
version: 0.62.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alex McRitchie
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-08-
|
|
11
|
+
date: 2026-08-27 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|