studio-engine 0.60.2 → 0.61.0
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/blocks/_close_x.html.erb +32 -0
- data/app/views/studio/modals/blocks/_rail_row.html.erb +109 -0
- data/app/views/style/_modals.html.erb +98 -0
- data/app/views/style/modals/_ds_close_x.html.erb +30 -0
- data/app/views/style/modals/_ds_onramp_hub.html.erb +71 -0
- data/app/views/style/modals/_ds_rail_row.html.erb +68 -0
- data/app/views/style/modals/_ds_wallet_topup.html.erb +69 -0
- data/lib/studio/version.rb +1 -1
- metadata +7 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 64bf6960f2f9100da2fa8a1a38bd1ca62733d348b7393ca6bc279b2a223ad11b
|
|
4
|
+
data.tar.gz: 3b33af6cd3b2ca2f48e18b05b1cea868458c793663da2a887f2afbd3c795a4b8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 28ce9d9910b4f4eb3f96ea64bb27d415988065b3c6609b489ef737811eba2ad9bb818edddf5ab504c9e077c8104f1c15d979b1fdc61f4a540d0330f04697d42b
|
|
7
|
+
data.tar.gz: 0d303ef8c72f4927c78bba6ef585bd299d0af420e259c8f65273e13b1d01663d590b81b651d64f553be685a0a65af8d6766b8f8de7df0d7057ed5efd893955f8
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<%#
|
|
2
|
+
Top-right close × for a modal that centres its own title.
|
|
3
|
+
|
|
4
|
+
WHY THIS EXISTS ALONGSIDE blocks/_shell, which already offers a title row and a
|
|
5
|
+
close. The shell puts the title on the LEFT with the close beside it; the
|
|
6
|
+
funding modals centre their title and absolutely-position the close above it.
|
|
7
|
+
Both are legitimate, and retrofitting _shell onto the centred family would move
|
|
8
|
+
eight titles — a visual change wearing a refactor's clothes. So this homes the
|
|
9
|
+
mark those eight already draw, byte for byte, and leaves the layout question
|
|
10
|
+
alone.
|
|
11
|
+
|
|
12
|
+
PORTED FROM turf-monster, where this exact markup appears in EIGHT files:
|
|
13
|
+
modals/_wallet_deposit, _wallet_topup, _cdp_ramp, _onramp_hub, _buy_entry_token
|
|
14
|
+
and three under modals/auth/ (_paypal_tokens, _usdc_funding, _tokens).
|
|
15
|
+
|
|
16
|
+
THE PARENT MUST BE POSITIONED. This is `absolute`, so it anchors to the nearest
|
|
17
|
+
positioned ancestor — every callsite wraps its card in `class="relative"`. On an
|
|
18
|
+
unpositioned parent the × climbs to whatever is positioned above it, which in a
|
|
19
|
+
modal is the host's backdrop, and lands in the page corner. Nothing errors.
|
|
20
|
+
|
|
21
|
+
Locals:
|
|
22
|
+
modal_store — Alpine store name backing close(). Default "modals". The style
|
|
23
|
+
guide passes "dsModals" (its own page-scoped host).
|
|
24
|
+
label — aria-label. Default "Close".
|
|
25
|
+
%>
|
|
26
|
+
<%
|
|
27
|
+
modal_store = local_assigns.fetch(:modal_store, "modals")
|
|
28
|
+
label = local_assigns.fetch(:label, "Close")
|
|
29
|
+
%>
|
|
30
|
+
<button type="button" @click="$store.<%= modal_store %>.close()"
|
|
31
|
+
class="absolute top-0 right-0 -mt-2 -mr-2 text-secondary hover:text-heading text-xl leading-none z-10"
|
|
32
|
+
aria-label="<%= label %>">×</button>
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
<%#
|
|
2
|
+
A funding RAIL ROW — icon tile, title, subtitle, chevron; the whole row is the
|
|
3
|
+
button. Used where a modal offers several ways to do one thing and the choice
|
|
4
|
+
itself is the screen.
|
|
5
|
+
|
|
6
|
+
PORTED FROM turf-monster, where this markup appears TEN times across three
|
|
7
|
+
files: modals/_onramp_hub (x6), _buy_entry_token (x2) and _wallet_topup (x2).
|
|
8
|
+
All ten share the same base class string and differ only in EMPHASIS, which is
|
|
9
|
+
why that is a named local rather than a class passthrough — a passthrough would
|
|
10
|
+
have let the eleventh copy drift on day one, which is how ten happened.
|
|
11
|
+
|
|
12
|
+
THE EMPHASIS IS A RANKING, not decoration. A hub full of equally-weighted rails
|
|
13
|
+
asks the person to compare payment processors, which is not a question they can
|
|
14
|
+
answer. Exactly one rail should be :primary — the one the app wants taken —
|
|
15
|
+
and it reads louder in three places at once (a doubled border, a filled hover,
|
|
16
|
+
a coloured chevron) because one of the three alone is not visible on a 56px row.
|
|
17
|
+
|
|
18
|
+
Locals:
|
|
19
|
+
on_click (String, REQUIRED) — Alpine expression run on click.
|
|
20
|
+
title (String, REQUIRED) — the rail's name.
|
|
21
|
+
subtitle (String, optional) — the one line under it.
|
|
22
|
+
emphasis (:primary | :neutral) — default :neutral.
|
|
23
|
+
icon_label (String, optional) — short letters ("CF") or an emoji, drawn in
|
|
24
|
+
the tile. Omit for a tile with no glyph.
|
|
25
|
+
icon_bg (String, optional) — a CSS colour for the tile (e.g. "#0052FF"),
|
|
26
|
+
which is how a brand mark is carried without shipping an asset.
|
|
27
|
+
Absent = the app's primary token.
|
|
28
|
+
icon_class (String, optional) — extra classes on the tile. Default suits
|
|
29
|
+
letters ("text-white font-extrabold text-lg"); an EMOJI tile wants
|
|
30
|
+
"text-xl" instead, because the bold-white treatment renders an
|
|
31
|
+
emoji as a fuzzy white blob.
|
|
32
|
+
badge (String, optional) — a small uppercase pill beside the title
|
|
33
|
+
("New"). Dropped when absent rather than rendered empty.
|
|
34
|
+
data (Hash, optional) — data-* attributes, for the app's own test
|
|
35
|
+
hooks (turf uses data-onramp-rail / data-buy-rail / data-topup-rail).
|
|
36
|
+
state (:available | :soon) — default :available. :soon renders the
|
|
37
|
+
ANNOUNCED-BUT-NOT-WIRED rail: a non-interactive <div>, dimmed,
|
|
38
|
+
with a muted badge where the chevron goes. on_click is then
|
|
39
|
+
OPTIONAL and ignored.
|
|
40
|
+
soon_label (String, optional) — the badge text for :soon. Default "Soon".
|
|
41
|
+
|
|
42
|
+
:soon IS A THIRD SHAPE, not a disabled button, and the distinction is the
|
|
43
|
+
reason it is here. turf's onramp hub announces PayPal and Venmo before they are
|
|
44
|
+
wired, and it does so with a <div> rather than a `disabled` <button> — so there
|
|
45
|
+
is no focus stop, no pointer, and nothing for a keyboard user to land on and
|
|
46
|
+
wonder about. The chevron is replaced rather than dimmed, because a chevron
|
|
47
|
+
says "this goes somewhere" and that is the one thing this row must not say.
|
|
48
|
+
|
|
49
|
+
NOT A LINK. An :available rail is a <button> running an Alpine expression,
|
|
50
|
+
because every real callsite either swaps modals or calls a JS funding helper —
|
|
51
|
+
none navigates. A rail that must navigate should be a plain <a> and not this.
|
|
52
|
+
%>
|
|
53
|
+
<%
|
|
54
|
+
state = local_assigns.fetch(:state, :available).to_sym
|
|
55
|
+
soon = state == :soon
|
|
56
|
+
# on_click is required for a rail that DOES something, and meaningless for one
|
|
57
|
+
# that only announces itself — fetching it unconditionally would force every
|
|
58
|
+
# placeholder callsite to invent a no-op.
|
|
59
|
+
on_click = soon ? nil : local_assigns.fetch(:on_click)
|
|
60
|
+
soon_label = local_assigns.fetch(:soon_label, "Soon")
|
|
61
|
+
title = local_assigns.fetch(:title)
|
|
62
|
+
subtitle = local_assigns[:subtitle]
|
|
63
|
+
emphasis = local_assigns.fetch(:emphasis, :neutral).to_sym
|
|
64
|
+
icon_label = local_assigns[:icon_label]
|
|
65
|
+
icon_bg = local_assigns[:icon_bg]
|
|
66
|
+
icon_class = local_assigns.fetch(:icon_class, "text-white font-extrabold text-lg")
|
|
67
|
+
badge = local_assigns[:badge]
|
|
68
|
+
data_attrs = local_assigns.fetch(:data, {})
|
|
69
|
+
|
|
70
|
+
border_class = if soon
|
|
71
|
+
"border border-subtle opacity-60"
|
|
72
|
+
elsif emphasis == :primary
|
|
73
|
+
"border-2 border-primary hover:bg-surface"
|
|
74
|
+
else
|
|
75
|
+
"border border-strong hover:border-primary"
|
|
76
|
+
end
|
|
77
|
+
chevron_class = emphasis == :primary ? "text-primary" : "text-muted"
|
|
78
|
+
tile_style = icon_bg.present? ? "background-color:#{icon_bg}" : nil
|
|
79
|
+
tile_bg_class = icon_bg.present? ? nil : "bg-primary"
|
|
80
|
+
%>
|
|
81
|
+
<%= content_tag(soon ? :div : :button, type: (soon ? nil : "button"),
|
|
82
|
+
"@click": on_click,
|
|
83
|
+
class: "w-full flex items-center gap-4 p-4 rounded-xl #{border_class} bg-inset#{soon ? '' : ' transition text-left'}",
|
|
84
|
+
data: data_attrs.presence) do %>
|
|
85
|
+
<span class="shrink-0 w-10 h-10 rounded-lg flex items-center justify-center <%= icon_class %> <%= tile_bg_class %>"
|
|
86
|
+
style="<%= tile_style %>"><%= icon_label %></span>
|
|
87
|
+
<span class="flex-1 min-w-0">
|
|
88
|
+
<% if badge.present? %>
|
|
89
|
+
<span class="flex items-center gap-2">
|
|
90
|
+
<span class="text-heading font-semibold text-sm"><%= title %></span>
|
|
91
|
+
<span class="shrink-0 text-[10px] uppercase tracking-widest font-bold text-primary bg-surface border border-primary rounded-full px-2 py-0.5"><%= badge %></span>
|
|
92
|
+
</span>
|
|
93
|
+
<% else %>
|
|
94
|
+
<span class="block text-heading font-semibold text-sm"><%= title %></span>
|
|
95
|
+
<% end %>
|
|
96
|
+
<% if subtitle.present? %>
|
|
97
|
+
<span class="block text-xs text-secondary"><%= subtitle %></span>
|
|
98
|
+
<% end %>
|
|
99
|
+
</span>
|
|
100
|
+
<% if soon %>
|
|
101
|
+
<%# A badge where the chevron would be. Replacing it, not dimming it: a
|
|
102
|
+
chevron says "this goes somewhere", and that is what this row must not say. %>
|
|
103
|
+
<span class="shrink-0 text-[10px] uppercase tracking-widest font-bold text-muted bg-surface border border-subtle rounded-full px-2 py-0.5"><%= soon_label %></span>
|
|
104
|
+
<% else %>
|
|
105
|
+
<svg class="shrink-0 w-4 h-4 <%= chevron_class %>" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24">
|
|
106
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5"/>
|
|
107
|
+
</svg>
|
|
108
|
+
<% end %>
|
|
109
|
+
<% end %>
|
|
@@ -376,6 +376,20 @@
|
|
|
376
376
|
<template x-if="$store.dsModals.current().id === 'network-guard'">
|
|
377
377
|
<div><%= render "style/modals/network_guard" %></div>
|
|
378
378
|
</template>
|
|
379
|
+
<%# --- funding chrome primitives (extract-funding-modal-chrome) --- %>
|
|
380
|
+
<template x-if="$store.dsModals.current().id === 'ds-rail-row'">
|
|
381
|
+
<div><%= render "style/modals/ds_rail_row" %></div>
|
|
382
|
+
</template>
|
|
383
|
+
<template x-if="$store.dsModals.current().id === 'ds-close-x'">
|
|
384
|
+
<div><%= render "style/modals/ds_close_x" %></div>
|
|
385
|
+
</template>
|
|
386
|
+
<%# --- the funding modals those primitives were extracted for --- %>
|
|
387
|
+
<template x-if="$store.dsModals.current().id === 'ds-wallet-topup'">
|
|
388
|
+
<div><%= render "style/modals/ds_wallet_topup" %></div>
|
|
389
|
+
</template>
|
|
390
|
+
<template x-if="$store.dsModals.current().id === 'ds-onramp-hub'">
|
|
391
|
+
<div><%= render "style/modals/ds_onramp_hub" %></div>
|
|
392
|
+
</template>
|
|
379
393
|
<template x-if="$store.dsModals.current().id === 'rate-limit-general'">
|
|
380
394
|
<div><%= render "style/modals/rate_limit_general" %></div>
|
|
381
395
|
</template>
|
|
@@ -1243,6 +1257,53 @@
|
|
|
1243
1257
|
</div>
|
|
1244
1258
|
<% end %>
|
|
1245
1259
|
|
|
1260
|
+
<%# ds-wallet-topup — the FIRST funds modal, and a safety fork. %>
|
|
1261
|
+
<%= render layout: "style/modal_specimen", locals: {
|
|
1262
|
+
label: "Top up wallet",
|
|
1263
|
+
reference: %(the first funds modal a player meets (style/modals/_ds_wallet_topup) — turf-monster's modals/_wallet_topup, built here from blocks/_close_x and blocks/_rail_row. THE TOGGLE IS THE CARD: this is one modal with two faces, and the fork is a SAFETY one rather than a preference. A web2 viewer running with ENABLE_WEB2_USDC_ENTRY off cannot pay an entry with USDC at all, so pitching "Buy USDC" would sell them a thing that cannot do the job they came to do — for exactly that audience the primary rail becomes the entry token, and the balance line follows, because the currency it names has to be the one that can pay. Shown as ONE card with a toggle rather than two, because two would read as two products and the point is that a player never sees both. Open with $store.dsModals.open('ds-wallet-topup', { tokenFallback: false })),
|
|
1264
|
+
card_data: "opts: { tokenFallback: false }",
|
|
1265
|
+
toggles: [{ model: "opts.tokenFallback", label: "web2 kill-switch" }],
|
|
1266
|
+
open_expr: "$store.dsModals.open('ds-wallet-topup', { tokenFallback: opts.tokenFallback })",
|
|
1267
|
+
glow_when: ds_glow.call("ds-wallet-topup"),
|
|
1268
|
+
disabled: !web3_on, openable: true } do %>
|
|
1269
|
+
<div class="pointer-events-none w-40 rounded-lg bg-surface border border-subtle shadow p-4 space-y-2">
|
|
1270
|
+
<span class="block h-2 w-20 mx-auto rounded" style="background: var(--color-text); opacity: .18"></span>
|
|
1271
|
+
<span class="flex items-center gap-1.5 rounded-md p-1.5" style="border: 2px solid var(--color-primary)">
|
|
1272
|
+
<span class="block h-4 w-4 rounded" style="background: var(--color-cta)"></span>
|
|
1273
|
+
<span class="block h-1.5 flex-1 rounded" style="background: var(--color-text); opacity: .3"></span>
|
|
1274
|
+
</span>
|
|
1275
|
+
<span class="block h-1.5 w-24 mx-auto rounded" style="background: var(--color-text); opacity: .18"></span>
|
|
1276
|
+
</div>
|
|
1277
|
+
<% end %>
|
|
1278
|
+
|
|
1279
|
+
<%# ds-onramp-hub — every rail at once, which is where ranking earns its keep. %>
|
|
1280
|
+
<%= render layout: "style/modal_specimen", locals: {
|
|
1281
|
+
label: "Add funds hub",
|
|
1282
|
+
reference: %(the full Add Funds hub (style/modals/_ds_onramp_hub) — turf-monster's modals/_onramp_hub, and the card blocks/_rail_row was extracted FOR: turf draws these six by hand today, which is six chances for the seventh to drift. Six rails is enough that "which one do I press" becomes a real question, and a hub where every rail carries equal weight answers it by asking the person to compare payment processors — not a question anyone can answer about their own life. Exactly ONE rail is :primary and the other five defer to it. PayPal and Venmo show the THIRD shape, :soon — announced before they are wired, so plain divs rather than disabled buttons, with a badge where the chevron would be, because even a dimmed chevron still promises somewhere to go. Open with $store.dsModals.open('ds-onramp-hub')),
|
|
1283
|
+
open_expr: "$store.dsModals.open('ds-onramp-hub')",
|
|
1284
|
+
glow_when: ds_glow.call("ds-onramp-hub"),
|
|
1285
|
+
disabled: !web3_on, openable: true } do %>
|
|
1286
|
+
<div class="pointer-events-none w-40 rounded-lg bg-surface border border-subtle shadow p-3 space-y-1.5">
|
|
1287
|
+
<span class="flex items-center gap-1.5 rounded p-1" style="border: 2px solid var(--color-primary)">
|
|
1288
|
+
<span class="block h-3 w-3 rounded-sm" style="background: var(--color-cta)"></span>
|
|
1289
|
+
<span class="block h-1 flex-1 rounded" style="background: var(--color-text); opacity: .3"></span>
|
|
1290
|
+
</span>
|
|
1291
|
+
<% 3.times do %>
|
|
1292
|
+
<span class="flex items-center gap-1.5 rounded p-1 border border-subtle">
|
|
1293
|
+
<span class="block h-3 w-3 rounded-sm" style="background: var(--color-text); opacity: .25"></span>
|
|
1294
|
+
<span class="block h-1 flex-1 rounded" style="background: var(--color-text); opacity: .18"></span>
|
|
1295
|
+
</span>
|
|
1296
|
+
<% end %>
|
|
1297
|
+
<%# the two :soon rails, dimmed %>
|
|
1298
|
+
<% 2.times do %>
|
|
1299
|
+
<span class="flex items-center gap-1.5 rounded p-1 border border-subtle" style="opacity: .5">
|
|
1300
|
+
<span class="block h-3 w-3 rounded-sm" style="background: var(--color-text); opacity: .25"></span>
|
|
1301
|
+
<span class="block h-1 flex-1 rounded" style="background: var(--color-text); opacity: .12"></span>
|
|
1302
|
+
</span>
|
|
1303
|
+
<% end %>
|
|
1304
|
+
</div>
|
|
1305
|
+
<% end %>
|
|
1306
|
+
|
|
1246
1307
|
<%# Entry confirmed — the GENERIC web3 celebration (tx link + heading + drain
|
|
1247
1308
|
CTA). seedsEarned: 0 so no seeds bar even where leveling is on: this card
|
|
1248
1309
|
demos the clean success a web3-only app gets. The seeds variant lives in
|
|
@@ -1542,6 +1603,43 @@
|
|
|
1542
1603
|
<span class="block h-1.5 w-12 mx-auto rounded" style="background: var(--color-text); opacity: .3"></span>
|
|
1543
1604
|
</div>
|
|
1544
1605
|
<% end %>
|
|
1606
|
+
|
|
1607
|
+
<%# rail-row — the funding picker's option row. Exactly ONE primary. %>
|
|
1608
|
+
<%= render layout: "style/modal_specimen", locals: {
|
|
1609
|
+
label: "Rail row",
|
|
1610
|
+
reference: %(the funding rail row (studio/modals/blocks/_rail_row) — the option row a funding hub is built from, ported out of turf-monster where the SAME markup appeared TEN times across modals/_onramp_hub, _buy_entry_token and _wallet_topup. The specimen shows three: one :primary and two :neutral, which is the arrangement a real hub uses. The emphasis is a RANKING, not decoration — a hub of equally-weighted rails asks the person to compare payment processors, which is not a question they can answer. It reads louder in three places at once (doubled border, filled hover, coloured chevron) because one alone is invisible on a 56px row, which is why it is ONE `emphasis:` local rather than three classes a callsite could half-apply. Brand colour rides in as `icon_bg`, so a rail wears a processor's mark with no asset shipped; the emoji tile passes icon_class: "text-xl", because the default bold-white treatment renders an emoji as a fuzzy white blob. Open with $store.dsModals.open('ds-rail-row')),
|
|
1611
|
+
open_expr: "$store.dsModals.open('ds-rail-row')",
|
|
1612
|
+
glow_when: ds_glow.call("ds-rail-row") } do %>
|
|
1613
|
+
<div class="pointer-events-none w-40 rounded-lg bg-surface border border-subtle shadow p-4 space-y-2">
|
|
1614
|
+
<%# the primary rail, then two neutrals — the ranking IS the thumbnail %>
|
|
1615
|
+
<span class="flex items-center gap-1.5 rounded-md p-1.5" style="border: 2px solid var(--color-primary)">
|
|
1616
|
+
<span class="block h-4 w-4 rounded" style="background: var(--color-cta)"></span>
|
|
1617
|
+
<span class="block h-1.5 flex-1 rounded" style="background: var(--color-text); opacity: .3"></span>
|
|
1618
|
+
</span>
|
|
1619
|
+
<span class="flex items-center gap-1.5 rounded-md p-1.5 border border-subtle">
|
|
1620
|
+
<span class="block h-4 w-4 rounded" style="background: var(--color-text); opacity: .25"></span>
|
|
1621
|
+
<span class="block h-1.5 flex-1 rounded" style="background: var(--color-text); opacity: .18"></span>
|
|
1622
|
+
</span>
|
|
1623
|
+
<span class="flex items-center gap-1.5 rounded-md p-1.5 border border-subtle">
|
|
1624
|
+
<span class="block h-4 w-4 rounded" style="background: var(--color-text); opacity: .25"></span>
|
|
1625
|
+
<span class="block h-1.5 flex-1 rounded" style="background: var(--color-text); opacity: .18"></span>
|
|
1626
|
+
</span>
|
|
1627
|
+
</div>
|
|
1628
|
+
<% end %>
|
|
1629
|
+
|
|
1630
|
+
<%# close-x — the mark, and the one class it depends on. %>
|
|
1631
|
+
<%= render layout: "style/modal_specimen", locals: {
|
|
1632
|
+
label: "Close ×",
|
|
1633
|
+
reference: %(the centred-title card's close mark (studio/modals/blocks/_close_x) — ported out of turf-monster where this markup appeared BYTE-IDENTICAL in eight files (modals/_wallet_deposit, _wallet_topup, _cdp_ramp, _onramp_hub, _buy_entry_token, and three under modals/auth/). It exists ALONGSIDE blocks/_shell rather than inside it: the shell puts its title on the left with the close beside it, while this family centres the title and positions the mark above it, so retrofitting the shell would move eight titles — a visual change wearing a refactor's clothes. THE PARENT MUST BE `relative`: the button is absolute, so it anchors to the nearest positioned ancestor, and without that class it climbs to the modal host's backdrop and lands in the page corner. Nothing errors and nothing in the markup reads as wrong, which is why the specimen says so out loud. Open with $store.dsModals.open('ds-close-x')),
|
|
1634
|
+
open_expr: "$store.dsModals.open('ds-close-x')",
|
|
1635
|
+
glow_when: ds_glow.call("ds-close-x") } do %>
|
|
1636
|
+
<div class="pointer-events-none w-40 rounded-lg bg-surface border border-subtle shadow p-4 text-center space-y-2 relative">
|
|
1637
|
+
<span class="absolute top-1 right-2 text-secondary leading-none">×</span>
|
|
1638
|
+
<span class="block h-2 w-24 mx-auto rounded" style="background: var(--color-text); opacity: .18"></span>
|
|
1639
|
+
<span class="block h-1.5 w-28 mx-auto rounded" style="background: var(--color-text); opacity: .12"></span>
|
|
1640
|
+
<span class="block h-4 w-full rounded" style="background: var(--color-cta)"></span>
|
|
1641
|
+
</div>
|
|
1642
|
+
<% end %>
|
|
1545
1643
|
</div>
|
|
1546
1644
|
</section>
|
|
1547
1645
|
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<%#
|
|
2
|
+
Living style guide specimen — the centred-title card and its close ×.
|
|
3
|
+
|
|
4
|
+
The mark itself is one button, so what is worth showing is the RELATIONSHIP it
|
|
5
|
+
depends on: the × is absolutely positioned, and it anchors to the nearest
|
|
6
|
+
POSITIONED ancestor. This card wraps its content in `class="relative"`, which
|
|
7
|
+
is the contract. Drop that one class and the × does not disappear — it climbs
|
|
8
|
+
to whatever is positioned above, which inside a modal is the host's backdrop,
|
|
9
|
+
and lands in the corner of the page looking like a stray glyph. Nothing errors,
|
|
10
|
+
and nothing in the markup reads as wrong.
|
|
11
|
+
|
|
12
|
+
Shown next to a centred title because that pairing is the reason this exists
|
|
13
|
+
rather than blocks/_shell, whose title sits left with the close beside it.
|
|
14
|
+
|
|
15
|
+
Single root: the outer <div> is the host's required root.
|
|
16
|
+
%>
|
|
17
|
+
<div class="relative">
|
|
18
|
+
<%= render "studio/modals/blocks/close_x", modal_store: "dsModals" %>
|
|
19
|
+
|
|
20
|
+
<div class="text-center pt-1 mb-3">
|
|
21
|
+
<h3 class="text-heading font-bold text-lg leading-tight">Top Up Your Wallet</h3>
|
|
22
|
+
</div>
|
|
23
|
+
<p class="text-xs text-body mb-4 text-center">
|
|
24
|
+
The × above sits in this card’s own corner because the card is
|
|
25
|
+
<code class="font-mono text-2xs">relative</code>. That single class is the
|
|
26
|
+
whole contract.
|
|
27
|
+
</p>
|
|
28
|
+
<button type="button" @click="$store.dsModals.close()"
|
|
29
|
+
class="btn btn-primary btn-lg w-full">Done</button>
|
|
30
|
+
</div>
|
|
@@ -0,0 +1,71 @@
|
|
|
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>
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<%#
|
|
2
|
+
Living style guide specimen — the funding rail picker.
|
|
3
|
+
|
|
4
|
+
Three rows through the ENGINE's blocks/_rail_row, arranged the way a real hub
|
|
5
|
+
arranges them: exactly ONE primary, the rest neutral. That ranking is the thing
|
|
6
|
+
to look at. A hub of equally-weighted rails asks the person to compare payment
|
|
7
|
+
processors, which is not a question they can answer; the emphasis answers it
|
|
8
|
+
for them.
|
|
9
|
+
|
|
10
|
+
Watch the three signals move together on the top row — a doubled border, a
|
|
11
|
+
filled hover, a coloured chevron. Each alone is invisible on a 56px row, which
|
|
12
|
+
is why the primitive ships them as one `emphasis:` rather than three classes a
|
|
13
|
+
callsite could half-apply.
|
|
14
|
+
|
|
15
|
+
The brand tiles carry their colour as an inline `icon_bg`, which is how a rail
|
|
16
|
+
wears a processor's mark without the engine shipping an asset for it. The last
|
|
17
|
+
row is an EMOJI tile, and it passes icon_class: "text-xl" — the default
|
|
18
|
+
bold-white treatment renders an emoji as a fuzzy white blob.
|
|
19
|
+
|
|
20
|
+
Single root: the outer <div> is the host's required root.
|
|
21
|
+
%>
|
|
22
|
+
<div class="relative">
|
|
23
|
+
<%= render "studio/modals/blocks/close_x", modal_store: "dsModals" %>
|
|
24
|
+
|
|
25
|
+
<div class="text-center pt-1 mb-3">
|
|
26
|
+
<h3 class="text-heading font-bold text-lg leading-tight">Add funds</h3>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
<div class="space-y-3">
|
|
30
|
+
<%= render "studio/modals/blocks/rail_row",
|
|
31
|
+
emphasis: :primary,
|
|
32
|
+
on_click: "$store.dsModals.close()",
|
|
33
|
+
icon_label: "C",
|
|
34
|
+
icon_bg: "#0052FF",
|
|
35
|
+
title: "Coinbase",
|
|
36
|
+
subtitle: "Card or bank · funds your entry",
|
|
37
|
+
data: { ds_rail: "coinbase" } %>
|
|
38
|
+
|
|
39
|
+
<%= render "studio/modals/blocks/rail_row",
|
|
40
|
+
on_click: "$store.dsModals.close()",
|
|
41
|
+
icon_label: "CF",
|
|
42
|
+
icon_bg: "#14B8A6",
|
|
43
|
+
title: "Coinflow · $19",
|
|
44
|
+
subtitle: "Buy 1 entry token with a card",
|
|
45
|
+
badge: "New",
|
|
46
|
+
data: { ds_rail: "coinflow" } %>
|
|
47
|
+
|
|
48
|
+
<%= render "studio/modals/blocks/rail_row",
|
|
49
|
+
on_click: "$store.dsModals.close()",
|
|
50
|
+
icon_label: "🎟️",
|
|
51
|
+
icon_class: "text-xl",
|
|
52
|
+
title: "Entry tokens",
|
|
53
|
+
subtitle: "1 token = 1 contest entry",
|
|
54
|
+
data: { ds_rail: "tokens" } %>
|
|
55
|
+
|
|
56
|
+
<%# The THIRD shape — a rail announced before it is wired. Not a disabled
|
|
57
|
+
button: a <div>, so there is no focus stop and nothing for a keyboard
|
|
58
|
+
user to land on and wonder about, and the badge REPLACES the chevron
|
|
59
|
+
rather than dimming it, because a chevron says "this goes somewhere". %>
|
|
60
|
+
<%= render "studio/modals/blocks/rail_row",
|
|
61
|
+
state: :soon,
|
|
62
|
+
icon_label: "P",
|
|
63
|
+
icon_bg: "#003087",
|
|
64
|
+
title: "PayPal",
|
|
65
|
+
subtitle: "Pay with your PayPal balance",
|
|
66
|
+
data: { ds_rail: "paypal" } %>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
@@ -0,0 +1,69 @@
|
|
|
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>
|
data/lib/studio/version.rb
CHANGED
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.
|
|
4
|
+
version: 0.61.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alex McRitchie
|
|
@@ -450,6 +450,7 @@ files:
|
|
|
450
450
|
- app/views/studio/modals/blocks/_birthday.html.erb
|
|
451
451
|
- app/views/studio/modals/blocks/_card_header.html.erb
|
|
452
452
|
- app/views/studio/modals/blocks/_change_username.html.erb
|
|
453
|
+
- app/views/studio/modals/blocks/_close_x.html.erb
|
|
453
454
|
- app/views/studio/modals/blocks/_cta_redirect.html.erb
|
|
454
455
|
- app/views/studio/modals/blocks/_digit_reel.html.erb
|
|
455
456
|
- app/views/studio/modals/blocks/_entry_confirmed.html.erb
|
|
@@ -460,6 +461,7 @@ files:
|
|
|
460
461
|
- app/views/studio/modals/blocks/_processing_card.html.erb
|
|
461
462
|
- app/views/studio/modals/blocks/_progress_countdown.html.erb
|
|
462
463
|
- app/views/studio/modals/blocks/_progress_pill.html.erb
|
|
464
|
+
- app/views/studio/modals/blocks/_rail_row.html.erb
|
|
463
465
|
- app/views/studio/modals/blocks/_seeds_bar.html.erb
|
|
464
466
|
- app/views/studio/modals/blocks/_shell.html.erb
|
|
465
467
|
- app/views/studio/modals/blocks/_solana_tx_link.html.erb
|
|
@@ -507,6 +509,10 @@ files:
|
|
|
507
509
|
- app/views/style/modals/_auth.html.erb
|
|
508
510
|
- app/views/style/modals/_birthday.html.erb
|
|
509
511
|
- app/views/style/modals/_cosign_rejected.html.erb
|
|
512
|
+
- app/views/style/modals/_ds_close_x.html.erb
|
|
513
|
+
- app/views/style/modals/_ds_onramp_hub.html.erb
|
|
514
|
+
- app/views/style/modals/_ds_rail_row.html.erb
|
|
515
|
+
- app/views/style/modals/_ds_wallet_topup.html.erb
|
|
510
516
|
- app/views/style/modals/_email_change_pending.html.erb
|
|
511
517
|
- app/views/style/modals/_entry_tokens.html.erb
|
|
512
518
|
- app/views/style/modals/_it_begins.html.erb
|