studio-engine 0.74.7 → 0.74.8
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 +802 -631
- data/README.md +5 -2
- data/app/views/studio/modals/blocks/_close_x.html.erb +6 -4
- data/app/views/studio/modals/blocks/_rail_row.html.erb +3 -1
- data/app/views/style/_modals.html.erb +190 -380
- data/app/views/style/modals/_ds_email_field.html.erb +58 -0
- data/app/views/style/modals/_ds_resend_footer.html.erb +70 -0
- data/app/views/style/modals/_ds_stack_demo.html.erb +63 -0
- data/app/views/style/modals/_wallet_connect.html.erb +26 -12
- data/lib/studio/version.rb +1 -1
- data/lib/studio.rb +4 -2
- metadata +4 -6
- data/app/views/style/modals/_auth.html.erb +0 -307
- data/app/views/style/modals/_ds_onramp_hub.html.erb +0 -71
- data/app/views/style/modals/_ds_wallet_topup.html.erb +0 -69
- data/app/views/style/modals/_entry_tokens.html.erb +0 -188
- data/app/views/style/modals/_onchain_tx.html.erb +0 -86
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
<%#
|
|
2
|
-
Living style guide specimen — the Add Funds hub, every rail at once.
|
|
3
|
-
|
|
4
|
-
APP-SPECIFIC flow, engine chrome throughout (blocks/_close_x + six
|
|
5
|
-
blocks/_rail_row). This is the card the rail primitive was extracted FOR: turf
|
|
6
|
-
draws these six by hand today, which is six chances for the seventh to drift.
|
|
7
|
-
|
|
8
|
-
WHAT TO LOOK AT IS THE RANKING, and this is where it earns its keep. Six rails
|
|
9
|
-
is enough that "which one do I press" becomes a real question, and a hub where
|
|
10
|
-
every rail carries equal weight answers it by asking the person to compare
|
|
11
|
-
payment processors — which is not a question anyone can answer about their own
|
|
12
|
-
life. Exactly one rail is :primary. The other five defer to it.
|
|
13
|
-
|
|
14
|
-
AND THE THIRD SHAPE. PayPal and Venmo are announced before they are wired, so
|
|
15
|
-
they are :soon — not disabled buttons but plain <div>s, with a badge where the
|
|
16
|
-
chevron would be. A dimmed chevron would still promise somewhere to go.
|
|
17
|
-
|
|
18
|
-
Single root: the outer <div> is the host's required root.
|
|
19
|
-
%>
|
|
20
|
-
<div class="relative">
|
|
21
|
-
<%= render "studio/modals/blocks/close_x", modal_store: "dsModals" %>
|
|
22
|
-
|
|
23
|
-
<div class="text-center pt-1 mb-3">
|
|
24
|
-
<h3 class="text-heading font-bold text-lg leading-tight">Add Funds</h3>
|
|
25
|
-
</div>
|
|
26
|
-
|
|
27
|
-
<div class="space-y-3">
|
|
28
|
-
<%= render "studio/modals/blocks/rail_row",
|
|
29
|
-
emphasis: :primary, on_click: "$store.dsModals.close()",
|
|
30
|
-
icon_label: "C", icon_bg: "#0052FF",
|
|
31
|
-
title: "Coinbase", subtitle: "Buy USDC with a card or bank",
|
|
32
|
-
data: { ds_rail: "coinbase" } %>
|
|
33
|
-
|
|
34
|
-
<%= render "studio/modals/blocks/rail_row",
|
|
35
|
-
on_click: "$store.dsModals.close()",
|
|
36
|
-
icon_label: "CF", icon_bg: "#14B8A6",
|
|
37
|
-
title: "Coinflow · $19", subtitle: "Buy 1 entry token with a card",
|
|
38
|
-
data: { ds_rail: "coinflow" } %>
|
|
39
|
-
|
|
40
|
-
<%= render "studio/modals/blocks/rail_row",
|
|
41
|
-
on_click: "$store.dsModals.close()",
|
|
42
|
-
icon_label: "A", icon_bg: "#6D28D9",
|
|
43
|
-
title: "Aeropay · $19", subtitle: "Buy 1 entry token from your bank",
|
|
44
|
-
data: { ds_rail: "aeropay" } %>
|
|
45
|
-
|
|
46
|
-
<%= render "studio/modals/blocks/rail_row",
|
|
47
|
-
state: :soon,
|
|
48
|
-
icon_label: "P", icon_bg: "#003087",
|
|
49
|
-
title: "PayPal", subtitle: "Pay with your PayPal balance",
|
|
50
|
-
data: { ds_rail: "paypal" } %>
|
|
51
|
-
|
|
52
|
-
<%= render "studio/modals/blocks/rail_row",
|
|
53
|
-
state: :soon,
|
|
54
|
-
icon_label: "V", icon_bg: "#008CFF",
|
|
55
|
-
title: "Venmo", subtitle: "Pay from your Venmo balance",
|
|
56
|
-
data: { ds_rail: "venmo" } %>
|
|
57
|
-
|
|
58
|
-
<%= render "studio/modals/blocks/rail_row",
|
|
59
|
-
on_click: "$store.dsModals.close()",
|
|
60
|
-
icon_label: "S", icon_bg: "#635BFF",
|
|
61
|
-
title: "Card · $19", subtitle: "Buy one entry token with a card",
|
|
62
|
-
data: { ds_rail: "stripe" } %>
|
|
63
|
-
</div>
|
|
64
|
-
|
|
65
|
-
<%# Back, not close: the hub is always reached FROM somewhere, and landing a
|
|
66
|
-
player on nothing is not the same as returning them. %>
|
|
67
|
-
<button type="button" @click="$store.dsModals.swap('ds-wallet-topup', {})"
|
|
68
|
-
class="block mx-auto mt-4 text-sm text-secondary hover:text-heading transition">
|
|
69
|
-
← Back
|
|
70
|
-
</button>
|
|
71
|
-
</div>
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
<%#
|
|
2
|
-
Living style guide specimen — Top Up Wallet, the FIRST funds modal a player
|
|
3
|
-
meets when they try to enter without funds.
|
|
4
|
-
|
|
5
|
-
APP-SPECIFIC flow, engine chrome throughout: blocks/_close_x for the mark and
|
|
6
|
-
blocks/_rail_row for every option. The engine owns no processors and no funding
|
|
7
|
-
policy; what turf supplies is which rails exist and which one leads.
|
|
8
|
-
|
|
9
|
-
THE TOGGLE IS THE CARD. This is one modal with two faces, and the fork is a
|
|
10
|
-
SAFETY one rather than a preference. A web2 viewer running with
|
|
11
|
-
ENABLE_WEB2_USDC_ENTRY off cannot pay an entry with USDC at all — so pitching
|
|
12
|
-
"Buy USDC" to them would sell a thing that cannot do the job they came to do.
|
|
13
|
-
For exactly that audience the primary rail becomes the entry token instead.
|
|
14
|
-
Everyone else — web3, and web2 with the flag on — sees Coinbase.
|
|
15
|
-
|
|
16
|
-
Shown as ONE card with a toggle rather than two cards, because two cards would
|
|
17
|
-
read as two products. The whole point is that a player never sees both.
|
|
18
|
-
|
|
19
|
-
Single root: the outer <div> is the host's required root.
|
|
20
|
-
%>
|
|
21
|
-
<div class="relative"
|
|
22
|
-
x-data="{
|
|
23
|
-
get props() { var c = $store.dsModals.current(); return (c && c.props) || {} },
|
|
24
|
-
get tokenFallback() { return !!this.props.tokenFallback }
|
|
25
|
-
}">
|
|
26
|
-
<%= render "studio/modals/blocks/close_x", modal_store: "dsModals" %>
|
|
27
|
-
|
|
28
|
-
<div class="text-center pt-1 mb-2">
|
|
29
|
-
<h3 class="text-heading font-bold text-lg leading-tight">Top Up Wallet</h3>
|
|
30
|
-
</div>
|
|
31
|
-
|
|
32
|
-
<%# The balance line follows the fork too — the currency it names has to be the
|
|
33
|
-
one that can actually pay for the entry. %>
|
|
34
|
-
<p x-show="!tokenFallback" class="text-xs text-body mb-4 text-center">
|
|
35
|
-
USDC balance: <span class="font-mono font-semibold text-heading">$12.40</span>
|
|
36
|
-
</p>
|
|
37
|
-
<p x-show="tokenFallback" x-cloak class="text-xs text-body mb-4 text-center">
|
|
38
|
-
Entry tokens: <span class="font-mono font-semibold text-heading">0</span>
|
|
39
|
-
</p>
|
|
40
|
-
|
|
41
|
-
<template x-if="!tokenFallback">
|
|
42
|
-
<%= render "studio/modals/blocks/rail_row",
|
|
43
|
-
emphasis: :primary,
|
|
44
|
-
on_click: "$store.dsModals.close()",
|
|
45
|
-
icon_label: "C",
|
|
46
|
-
icon_bg: "#0052FF",
|
|
47
|
-
title: "Buy USDC with Coinbase",
|
|
48
|
-
subtitle: "Card or bank · funds your entry",
|
|
49
|
-
data: { ds_rail: "coinbase" } %>
|
|
50
|
-
</template>
|
|
51
|
-
|
|
52
|
-
<template x-if="tokenFallback">
|
|
53
|
-
<%= render "studio/modals/blocks/rail_row",
|
|
54
|
-
emphasis: :primary,
|
|
55
|
-
on_click: "$store.dsModals.close()",
|
|
56
|
-
icon_label: "🎟️",
|
|
57
|
-
icon_class: "text-xl",
|
|
58
|
-
title: "Buy Entry Tokens",
|
|
59
|
-
subtitle: "1 token = 1 contest entry",
|
|
60
|
-
data: { ds_rail: "tokens" } %>
|
|
61
|
-
</template>
|
|
62
|
-
|
|
63
|
-
<%# The quiet way to the full hub. Deliberately a link, not a rail: it is not
|
|
64
|
-
another way to pay, it is a way to see the others. %>
|
|
65
|
-
<button type="button" @click="$store.dsModals.swap('ds-onramp-hub', {})"
|
|
66
|
-
class="block mx-auto mt-4 text-sm text-secondary hover:text-heading transition">
|
|
67
|
-
More ways to add funds →
|
|
68
|
-
</button>
|
|
69
|
-
</div>
|
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
<%#
|
|
2
|
-
Living style guide specimen — the contest entry & eligibility flow. This
|
|
3
|
-
documents an APP-SPECIFIC flow (Turf Monster's "Get Entry Tokens" → enter);
|
|
4
|
-
the engine deliberately does NOT own the packs, pricing, payment rails, or any
|
|
5
|
-
on-chain write. The specimen composes only engine CHROME (studio/modals/blocks/
|
|
6
|
-
shell, card_header, progress_pill, solana_tx_link) and represents the packs and
|
|
7
|
-
the on-chain moments as an illustrative demo — the app owns the money + signing.
|
|
8
|
-
|
|
9
|
-
Opened on the page-scoped dsModals host with an internal step machine on
|
|
10
|
-
props.step, the full web2 walk:
|
|
11
|
-
|
|
12
|
-
picker -> confirming -> minted -> entering -> entered
|
|
13
|
-
|
|
14
|
-
Single-root templates throughout. The two load steps (confirming, entering)
|
|
15
|
-
honor the minimum-visible-duration convention (studio/modals/_load_convention):
|
|
16
|
-
the spinner holds at least MIN_LOAD_MS, then auto-advances (demo mode) —
|
|
17
|
-
resolveAt = max(min_duration, actual_completion).
|
|
18
|
-
|
|
19
|
-
On-chain model (documented, not owned here). An entry token is a PROGRAM-OWNED
|
|
20
|
-
prepaid entry credit recorded on-chain (a per-token account), NOT a fungible SPL
|
|
21
|
-
token in the user's wallet. WEB2 (card / Stripe / Coinflow / PayPal) has two
|
|
22
|
-
on-chain moments: (1) MINT at purchase, server-signed after the payment clears —
|
|
23
|
-
not on the buyer's click; (2) CONSUME at entry, when the hold-to-confirm gesture
|
|
24
|
-
spends one token to create the contest entry. WEB3 (wallet / USDC on-chain)
|
|
25
|
-
funds USDC directly and mints NO token — so the mint→consume prelude is
|
|
26
|
-
web2-only. Both paths converge at the SAME on-chain Entry PDA and the SAME
|
|
27
|
-
"Entry Confirmed" card.
|
|
28
|
-
%>
|
|
29
|
-
<%
|
|
30
|
-
# Illustrative packs only — a real app reads these from its own config
|
|
31
|
-
# (e.g. StripePurchase.available_packs), and they vary by funding mode.
|
|
32
|
-
demo_packs = [
|
|
33
|
-
{ tokens: 1, price: "$5", note: nil },
|
|
34
|
-
{ tokens: 3, price: "$12", note: "Popular" },
|
|
35
|
-
{ tokens: 10, price: "$35", note: "Best value" }
|
|
36
|
-
]
|
|
37
|
-
%>
|
|
38
|
-
<div x-data="{
|
|
39
|
-
get props() { var c = Alpine.store('dsModals').current(); return (c && c.props) || {}; },
|
|
40
|
-
buy(count, balance) {
|
|
41
|
-
Alpine.store('dsModals').advance({ step: 'confirming', mintedCount: count, mintedBalance: balance });
|
|
42
|
-
},
|
|
43
|
-
confirmEntry() {
|
|
44
|
-
Alpine.store('dsModals').advance({ step: 'entering' });
|
|
45
|
-
},
|
|
46
|
-
// Demo auto-resolve honoring the min-load convention: hold the spinner at
|
|
47
|
-
// least MIN_LOAD_MS, then advance — but only while this modal is still on
|
|
48
|
-
// the given step (guards against an early close / manual advance).
|
|
49
|
-
autoAdvance(fromStep, patch) {
|
|
50
|
-
window.StudioModals.holdAtLeast(window.StudioModals.MIN_LOAD_MS).then(function () {
|
|
51
|
-
var c = Alpine.store('dsModals').current();
|
|
52
|
-
if (c && c.id === 'entry-tokens' && c.props.step === fromStep) {
|
|
53
|
-
Alpine.store('dsModals').advance(patch);
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
}" class="relative">
|
|
58
|
-
|
|
59
|
-
<%# Shared close — top-right, above whichever step is active. %>
|
|
60
|
-
<button @click="$store.dsModals.close()"
|
|
61
|
-
class="absolute top-0 right-0 -mt-2 -mr-2 text-secondary hover:text-heading text-xl leading-none z-10"
|
|
62
|
-
aria-label="Close">×</button>
|
|
63
|
-
|
|
64
|
-
<%# ===== PICKER ===== %>
|
|
65
|
-
<template x-if="(props.step || 'picker') === 'picker'">
|
|
66
|
-
<div>
|
|
67
|
-
<div class="text-center pt-1 mb-3">
|
|
68
|
-
<h3 class="text-heading font-bold text-lg leading-tight">Get Entry Tokens</h3>
|
|
69
|
-
</div>
|
|
70
|
-
<%= render "studio/modals/blocks/progress_pill", current: 2, total: 3 %>
|
|
71
|
-
<p class="text-xs text-secondary mb-4 text-center">
|
|
72
|
-
1 token = 1 contest entry. Pick a pack to finish.
|
|
73
|
-
</p>
|
|
74
|
-
|
|
75
|
-
<div class="space-y-2.5">
|
|
76
|
-
<% demo_packs.each do |pack| %>
|
|
77
|
-
<button type="button"
|
|
78
|
-
@click="buy(<%= pack[:tokens] %>, '<%= pack[:tokens] %>')"
|
|
79
|
-
class="w-full flex items-center justify-between gap-3 rounded-lg border border-strong bg-inset px-4 py-3 text-left hover:border-primary transition">
|
|
80
|
-
<span class="flex items-center gap-2">
|
|
81
|
-
<span class="text-heading font-semibold"><%= pack[:tokens] %> token<%= "s" unless pack[:tokens] == 1 %></span>
|
|
82
|
-
<% if pack[:note] %>
|
|
83
|
-
<span class="badge" style="color: var(--color-primary); border-color: var(--color-primary)"><%= pack[:note] %></span>
|
|
84
|
-
<% end %>
|
|
85
|
-
</span>
|
|
86
|
-
<span class="text-heading font-mono font-bold"><%= pack[:price] %></span>
|
|
87
|
-
</button>
|
|
88
|
-
<% end %>
|
|
89
|
-
</div>
|
|
90
|
-
|
|
91
|
-
<%# Rails — which funding path mints tokens vs funds an entry directly. %>
|
|
92
|
-
<div class="mt-4 flex flex-wrap items-center justify-center gap-x-4 gap-y-1 text-xs text-muted">
|
|
93
|
-
<span>Pay by card</span>
|
|
94
|
-
<span aria-hidden="true">·</span>
|
|
95
|
-
<span>PayPal / Venmo</span>
|
|
96
|
-
<span aria-hidden="true">·</span>
|
|
97
|
-
<span>Coinflow</span>
|
|
98
|
-
</div>
|
|
99
|
-
<p class="text-center text-2xs text-muted mt-1">
|
|
100
|
-
These are the <strong>web2</strong> rails — they mint prepaid entry tokens.
|
|
101
|
-
The <strong>web3</strong> path funds USDC on-chain directly and mints no token.
|
|
102
|
-
</p>
|
|
103
|
-
|
|
104
|
-
<%# The seam callout — what the engine owns vs the app, plus the honest
|
|
105
|
-
web2/web3 map (a real divergence, not invented). %>
|
|
106
|
-
<div class="mt-4 rounded-lg border border-subtle bg-surface p-3 text-2xs text-secondary leading-snug">
|
|
107
|
-
<p class="text-heading font-semibold mb-1">App-specific flow, engine chrome</p>
|
|
108
|
-
<p class="mb-2">
|
|
109
|
-
The engine supplies only the shell, header, progress pill, and tx link. The
|
|
110
|
-
packs, pricing, payment rails, and every on-chain write are
|
|
111
|
-
<strong>app-owned</strong> — this specimen represents them as a demo. On-chain,
|
|
112
|
-
an entry token is a <strong>prepaid entry credit recorded on-chain</strong>
|
|
113
|
-
(a per-token account), not a wallet-held token.
|
|
114
|
-
</p>
|
|
115
|
-
<p class="text-heading font-semibold mb-1">Web2 vs web3 — where they diverge and converge</p>
|
|
116
|
-
<p class="mb-1">
|
|
117
|
-
<strong>Web2</strong> (card / Stripe / Coinflow / PayPal): a server job mints
|
|
118
|
-
one prepaid entry credit per token on-chain once payment clears, then
|
|
119
|
-
hold-to-confirm <strong>consumes</strong> one token to create the entry.
|
|
120
|
-
</p>
|
|
121
|
-
<p class="mb-1">
|
|
122
|
-
<strong>Web3</strong> (wallet / USDC on-chain): funds USDC directly and
|
|
123
|
-
<strong>mints no token</strong> — the mint → consume prelude is web2-only.
|
|
124
|
-
</p>
|
|
125
|
-
<p>
|
|
126
|
-
Both paths converge on the <strong>same on-chain Entry PDA</strong> and the
|
|
127
|
-
<strong>same “Entry Confirmed” card</strong> — divergent funding front-end,
|
|
128
|
-
one shared entry → entered finish.
|
|
129
|
-
</p>
|
|
130
|
-
</div>
|
|
131
|
-
</div>
|
|
132
|
-
</template>
|
|
133
|
-
|
|
134
|
-
<%# ===== CONFIRMING (payment processing — mint-at-purchase) ===== %>
|
|
135
|
-
<template x-if="props.step === 'confirming'">
|
|
136
|
-
<div x-init="autoAdvance('confirming', { step: 'minted' })">
|
|
137
|
-
<%= render "studio/modals/blocks/card_header",
|
|
138
|
-
spinner: true,
|
|
139
|
-
title: "Confirming your purchase…",
|
|
140
|
-
subtitle: "Payment cleared — a server job mints one prepaid entry credit per token on-chain." %>
|
|
141
|
-
</div>
|
|
142
|
-
</template>
|
|
143
|
-
|
|
144
|
-
<%# ===== MINTED (ready to consume at entry) ===== %>
|
|
145
|
-
<template x-if="props.step === 'minted'">
|
|
146
|
-
<div>
|
|
147
|
-
<%= render "studio/modals/blocks/card_header",
|
|
148
|
-
icon_color: 'primary',
|
|
149
|
-
title_key: "(props.mintedCount === 1 ? 'Entry Token Minted' : 'Entry Tokens Minted')" do %>
|
|
150
|
-
You now have <span class="font-bold text-primary font-mono" x-text="props.mintedBalance"></span> available.
|
|
151
|
-
<% end %>
|
|
152
|
-
<p class="text-xs text-secondary text-center mb-4 leading-snug">
|
|
153
|
-
Holding to confirm now <strong>consumes one token on-chain</strong> to create
|
|
154
|
-
your contest entry.
|
|
155
|
-
</p>
|
|
156
|
-
<button @click="confirmEntry()" class="btn btn-primary btn-lg w-full">Hold to Confirm Entry</button>
|
|
157
|
-
<button @click="$store.dsModals.close()"
|
|
158
|
-
class="block mx-auto mt-3 text-xs text-secondary hover:text-heading underline underline-offset-2">
|
|
159
|
-
I’ll confirm later
|
|
160
|
-
</button>
|
|
161
|
-
</div>
|
|
162
|
-
</template>
|
|
163
|
-
|
|
164
|
-
<%# ===== ENTERING (contest enter processing — the on-chain consume) ===== %>
|
|
165
|
-
<template x-if="props.step === 'entering'">
|
|
166
|
-
<div x-init="autoAdvance('entering', { step: 'entered', txSignature: '5xTrDemoEntrySignature1234567890abc' })">
|
|
167
|
-
<%= render "studio/modals/blocks/card_header",
|
|
168
|
-
spinner: true,
|
|
169
|
-
title: "Confirming your entry…",
|
|
170
|
-
subtitle: "Consuming one token on-chain to create your contest entry." %>
|
|
171
|
-
</div>
|
|
172
|
-
</template>
|
|
173
|
-
|
|
174
|
-
<%# ===== ENTERED (contest entered — the shared Entry Confirmed finish) ===== %>
|
|
175
|
-
<template x-if="props.step === 'entered'">
|
|
176
|
-
<div>
|
|
177
|
-
<%= render "studio/modals/blocks/card_header",
|
|
178
|
-
size: :lg, icon_color: 'primary',
|
|
179
|
-
title: "Good Luck", subtitle: "Entry Confirmed" %>
|
|
180
|
-
<%= render "studio/modals/blocks/solana_tx_link", tx_signature_key: "props.txSignature" %>
|
|
181
|
-
<button @click="$store.dsModals.close()" class="btn btn-primary btn-lg w-full">Contest Lobby ⚔️</button>
|
|
182
|
-
<button @click="$store.dsModals.close()"
|
|
183
|
-
class="block mx-auto mt-3 text-sm text-secondary hover:text-heading transition">
|
|
184
|
-
Dismiss
|
|
185
|
-
</button>
|
|
186
|
-
</div>
|
|
187
|
-
</template>
|
|
188
|
-
</div>
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
<%#
|
|
2
|
-
On-chain transaction modal — design-system port of turf-monster's
|
|
3
|
-
modals/_onchain_tx, wired to the living style guide's page-scoped host. Reads
|
|
4
|
-
display state from $store.dsSolanaModal (a stateless proxy over $store.dsModals
|
|
5
|
-
that keeps the show/success/error API stable — the same façade shape the real
|
|
6
|
-
app ships). The proxy's methods push/pop the dsModals stack so this partial
|
|
7
|
-
renders when opened.
|
|
8
|
-
|
|
9
|
-
Three states — processing / success / error — cover the whole non-domain-
|
|
10
|
-
specific tx flow. The DS preview always uses the GENERIC success card
|
|
11
|
-
(studio/modals/blocks/_onchain_success); the rich contest-entry celebration
|
|
12
|
-
(seeds bar + level-up + lobby drain) is turf-specific and stays in the
|
|
13
|
-
consumer app.
|
|
14
|
-
|
|
15
|
-
Single root: content lives inside one <div> so Alpine's <template x-if> clones
|
|
16
|
-
it whole.
|
|
17
|
-
%>
|
|
18
|
-
<div x-data="{
|
|
19
|
-
init() {
|
|
20
|
-
this.$watch('$store.dsSolanaModal.state', function(val) {
|
|
21
|
-
if (val === 'success') {
|
|
22
|
-
setTimeout(function() {
|
|
23
|
-
try { if (window.fireSuccessConfetti) window.fireSuccessConfetti(); } catch (_) {}
|
|
24
|
-
}, 100);
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
// Demo auto-resolve (min-load convention): a processing modal opened with
|
|
28
|
-
// demoResolve holds its spinner at least MIN_LOAD_MS, then advances to
|
|
29
|
-
// success — or to error when demoError is set (the Processing specimen's
|
|
30
|
-
// success/error toggle). Guarded to the still-open, still-processing modal.
|
|
31
|
-
var entry = Alpine.store('dsModals').current();
|
|
32
|
-
if (!entry || entry.id !== 'onchain-tx' || !entry.props ||
|
|
33
|
-
entry.props.state !== 'processing' || !entry.props.demoResolve) return;
|
|
34
|
-
var minMs = entry.props.minDuration ||
|
|
35
|
-
(window.StudioModals && window.StudioModals.MIN_LOAD_MS) || 1400;
|
|
36
|
-
window.StudioModals.holdAtLeast(minMs).then(function () {
|
|
37
|
-
var cur = Alpine.store('dsModals').current();
|
|
38
|
-
if (!cur || cur.id !== 'onchain-tx' || cur.props.state !== 'processing') return;
|
|
39
|
-
if (entry.props.demoError) {
|
|
40
|
-
Alpine.store('dsModals').advance({ state: 'error',
|
|
41
|
-
title: 'Could not confirm',
|
|
42
|
-
errorMessage: 'The transaction was rejected. Give it another try.' });
|
|
43
|
-
} else {
|
|
44
|
-
Alpine.store('dsModals').advance({ state: 'success',
|
|
45
|
-
txSignature: '5xTrDemoSignature1234567890abcXYZ',
|
|
46
|
-
successTitle: 'Mint complete',
|
|
47
|
-
successSubtitle: 'Your on-chain action confirmed.',
|
|
48
|
-
ctaLabel: 'View wallet', ctaHref: null });
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
}">
|
|
53
|
-
|
|
54
|
-
<%# === PROCESSING ====================================================== %>
|
|
55
|
-
<template x-if="$store.dsSolanaModal.state === 'processing'">
|
|
56
|
-
<%= render "studio/modals/blocks/card_header",
|
|
57
|
-
spinner: true,
|
|
58
|
-
title_key: "$store.dsSolanaModal.title",
|
|
59
|
-
subtitle_key: "$store.dsSolanaModal.message" %>
|
|
60
|
-
</template>
|
|
61
|
-
|
|
62
|
-
<%# === SUCCESS (generic) =============================================== %>
|
|
63
|
-
<template x-if="$store.dsSolanaModal.state === 'success'">
|
|
64
|
-
<%= render "studio/modals/blocks/onchain_success",
|
|
65
|
-
tx_signature_key: "$store.dsSolanaModal.txSignature",
|
|
66
|
-
title_key: "$store.dsSolanaModal.successTitle",
|
|
67
|
-
subtitle_key: "$store.dsSolanaModal.successSubtitle",
|
|
68
|
-
cta_label_key: "$store.dsSolanaModal.ctaLabel",
|
|
69
|
-
cta_href_key: "$store.dsSolanaModal.ctaHref",
|
|
70
|
-
modal_store: "dsModals" %>
|
|
71
|
-
</template>
|
|
72
|
-
|
|
73
|
-
<%# === ERROR =========================================================== %>
|
|
74
|
-
<template x-if="$store.dsSolanaModal.state === 'error'">
|
|
75
|
-
<div>
|
|
76
|
-
<%= render "studio/modals/blocks/card_header",
|
|
77
|
-
icon: :error,
|
|
78
|
-
title_key: "$store.dsSolanaModal.title",
|
|
79
|
-
subtitle_key: "$store.dsSolanaModal.errorMessage" %>
|
|
80
|
-
<button @click="$store.dsSolanaModal.close()"
|
|
81
|
-
class="block mx-auto mt-3 text-sm text-secondary hover:text-heading transition">
|
|
82
|
-
Close
|
|
83
|
-
</button>
|
|
84
|
-
</div>
|
|
85
|
-
</template>
|
|
86
|
-
</div>
|