studio-engine 0.62.1 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d7bb00518e41485eb5c86076482d82bf7e178c3de53ebe7e7cb86b727d2ebdf2
4
- data.tar.gz: a56bfe30c698b1943312c078e6030e4224540adf074832d942997d0812303824
3
+ metadata.gz: 822c72023af8d108848e67535194fa5a115443b4faaeebd7d9adc931ffcc7678
4
+ data.tar.gz: a1ef68303215291461d2e07b5237506c57fc6ab83e4fd8b9edc9f18a39e19e51
5
5
  SHA512:
6
- metadata.gz: 0c9e71c552cbb8078ca4b6e01d18de197e7a6ec6bb633ce6987d63793610f01387466f653584e5acd3c4a6e0da85d7692b941e0358591e429e51ee29aea46b20
7
- data.tar.gz: 4f4f23cc7ce10e40da54465a29f9022c234848a481cd99138ec2946c281bbc11e293279a10136019db19c1de57a779c21d552f3728b7a7ffb212d36e6daefc45
6
+ metadata.gz: dac77f69b4c34943fe3bd8f8a790dbbadfd8ebbc4e80a17595af78fff7f054e9321ea92062769c474ae56b70da09d051a9d45801f0f0aff2197fedc794deaaba
7
+ data.tar.gz: 723edaf2959e13979ede94523e578ce1d612cbe9911dfd4f1340de8a77b73fa2a2a2ee2c866f3f8078a780455af3baeafd5f369fb232a90a024987ed409a84e1
@@ -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
@@ -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 %>"
@@ -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 &amp; 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 &amp; 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>
@@ -1,3 +1,3 @@
1
1
  module Studio
2
- VERSION = "0.62.1"
2
+ VERSION = "0.62.2"
3
3
  end
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.62.1
4
+ version: 0.62.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex McRitchie