studio-engine 0.21.0 → 0.23.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/CHANGELOG.md +147 -0
- data/app/assets/javascripts/studio/canvas_confetti.js +17 -0
- data/app/assets/javascripts/studio/sortable.js +11 -0
- data/app/assets/javascripts/studio/studio_confetti.js +93 -0
- data/app/assets/tailwind/studio_engine/engine-motion.css +47 -0
- data/app/controllers/concerns/studio/board/reorderable.rb +97 -0
- data/app/models/concerns/studio/board/rankable.rb +84 -0
- data/app/views/components/_badge.html.erb +4 -2
- data/app/views/layouts/studio/_head.html.erb +13 -1
- data/app/views/studio/_board_assets.html.erb +341 -0
- data/app/views/studio/_leveling_activity_assets.html.erb +174 -0
- data/app/views/studio/board/_board.html.erb +151 -0
- data/app/views/studio/board/_card_shell.html.erb +47 -0
- data/app/views/studio/board/_column.html.erb +80 -0
- data/app/views/studio/modals/blocks/_change_username.html.erb +46 -0
- data/app/views/studio/modals/blocks/_leveling_activity.html.erb +159 -0
- data/app/views/style/_modals.html.erb +141 -0
- data/app/views/style/_tasks.html.erb +82 -11
- data/app/views/style/_tricks.html.erb +46 -0
- data/app/views/style/board/_demo_card.html.erb +22 -0
- data/lib/studio/engine.rb +3 -0
- data/lib/studio/version.rb +1 -1
- metadata +14 -1
|
@@ -1,13 +1,52 @@
|
|
|
1
1
|
<%# Tasks section of the living style guide (admin/style).
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
/
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
The shared board primitive, LIVE. Phase D lifted the columns / cards / drag +
|
|
4
|
+
optimistic move / reorder that the three near-identical McRitchie Studio boards
|
|
5
|
+
(tasks / news / content) each hand-rolled into one engine primitive
|
|
6
|
+
(studio/board/_board + the window.studioBoard factory + vendored SortableJS).
|
|
7
|
+
The first block below renders that real primitive with `demo: true` — you can
|
|
8
|
+
DRAG a card between columns and the move animates + toasts, but nothing POSTs.
|
|
9
|
+
The blocks under it stay a static reference: the stage-* badge palette
|
|
10
|
+
(components/_badge) that is the pipeline spine, and the standard-vs-custom
|
|
11
|
+
split of what a board inherits vs sets. %>
|
|
9
12
|
<%
|
|
10
|
-
#
|
|
13
|
+
# LIVE specimen — the real studio/board/_board primitive, demo mode. Plain Hash
|
|
14
|
+
# records (the style guide has no models); each card id becomes id="card-<id>".
|
|
15
|
+
# Each demo card carries its current `zone` (the column it sits in) — in a real
|
|
16
|
+
# board the record knows its own stage; here the Hash does.
|
|
17
|
+
live_board_columns = [
|
|
18
|
+
{ key: "designed", label: "Designed", badge_class: "stage-fresh",
|
|
19
|
+
cards: [
|
|
20
|
+
{ id: "engine-board-primitive", zone: "designed", title: "Engine board primitive", repo: "studio-engine", who: "SH" },
|
|
21
|
+
{ id: "coinflow-buy-rail", zone: "designed", title: "Coinflow buy rail", repo: "turf-monster", who: "JA" }
|
|
22
|
+
] },
|
|
23
|
+
{ key: "building", label: "Building", badge_class: "stage-shaping",
|
|
24
|
+
cards: [{ id: "navbar-rpc-preload", zone: "building", title: "Navbar RPC preload", repo: "turf-monster", who: "CA" }] },
|
|
25
|
+
{ key: "submitted", label: "Submitted", badge_class: "stage-structured",
|
|
26
|
+
cards: [{ id: "magic-link-ttl-bump", zone: "submitted", title: "Magic-link TTL bump", repo: "studio-engine", who: "SH" }] },
|
|
27
|
+
{ key: "shipped", label: "Shipped", badge_class: "stage-shipped",
|
|
28
|
+
cards: [{ id: "ses-email-backend", zone: "shipped", title: "SES email backend", repo: "mcritchie", who: "ST" }] }
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
# Copy-paste-for-an-agent usage. Built by array-join, NOT a heredoc: a heredoc as
|
|
32
|
+
# the last expression of an ERB scriptlet trips Erubi, and literal ERB tags in the
|
|
33
|
+
# body would close the tag. Plain render() calls read clearly for an agent.
|
|
34
|
+
board_usage_snippet = [
|
|
35
|
+
"# once at layout level (a <script> in the board template never runs):",
|
|
36
|
+
'render "studio/board_assets"',
|
|
37
|
+
"",
|
|
38
|
+
"# then the board itself:",
|
|
39
|
+
'render "studio/board/board",',
|
|
40
|
+
" columns: @columns, # [{ key:, label:, cards:, badge_class: }]",
|
|
41
|
+
' card_partial: "tasks/task_card",',
|
|
42
|
+
" reorder_url: tasks_reorder_path, # POST { slugs: [...], zone: }",
|
|
43
|
+
' move_url: "/tasks/:id.json", # PATCH { task: { stage: } }',
|
|
44
|
+
' move_param: { resource: "task", attr: "stage" },',
|
|
45
|
+
' live_channel: "deployments"'
|
|
46
|
+
].join("\n")
|
|
47
|
+
|
|
48
|
+
# The static reference palette below (unchanged): each column maps to a stage-*
|
|
49
|
+
# badge scheme.
|
|
11
50
|
board_columns = [
|
|
12
51
|
{ key: "stage-fresh", label: "Fresh", count: 2 },
|
|
13
52
|
{ key: "stage-shaping", label: "Shaping", count: 1 },
|
|
@@ -32,13 +71,45 @@
|
|
|
32
71
|
<h2 class="text-2xl font-bold text-heading">Tasks</h2>
|
|
33
72
|
<p class="text-muted text-sm max-w-2xl">
|
|
34
73
|
The shared board primitive that every board builds from — columns, cards, the
|
|
35
|
-
<code class="font-mono text-2xs">stage-*</code> badge palette, and the drag /
|
|
36
|
-
McRitchie Studio's <code class="font-mono text-2xs">/deployments</code> board is
|
|
37
|
-
|
|
74
|
+
<code class="font-mono text-2xs">stage-*</code> badge palette, and the drag / optimistic
|
|
75
|
+
move + reorder. McRitchie Studio's <code class="font-mono text-2xs">/deployments</code> board is
|
|
76
|
+
the top-of-line; the specimen below is the <strong>real</strong>
|
|
77
|
+
<code class="font-mono text-2xs">studio/board/board</code> primitive in
|
|
78
|
+
<code class="font-mono text-2xs">demo: true</code> mode — drag a card, no save.
|
|
38
79
|
</p>
|
|
39
80
|
</div>
|
|
40
81
|
|
|
41
|
-
<%# ---- The
|
|
82
|
+
<%# ---- The LIVE primitive (demo mode) --------------------------------- %>
|
|
83
|
+
<%# Render the factory once (a <script> in the board template would never run), then
|
|
84
|
+
the board. demo: true → drag animates + toasts locally, nothing POSTs. %>
|
|
85
|
+
<%= render "studio/board_assets" %>
|
|
86
|
+
<div class="space-y-3">
|
|
87
|
+
<div class="flex items-center gap-2">
|
|
88
|
+
<span class="badge" style="color: var(--color-success); border-color: var(--color-success)">Live</span>
|
|
89
|
+
<p class="label-upper"><code class="font-mono text-2xs">studio/board/board</code> · demo — drag a card between columns</p>
|
|
90
|
+
</div>
|
|
91
|
+
<%= render "studio/board/board",
|
|
92
|
+
demo: true,
|
|
93
|
+
columns: live_board_columns,
|
|
94
|
+
card_partial: "style/board/demo_card",
|
|
95
|
+
card_as: :card,
|
|
96
|
+
reorder_url: "#",
|
|
97
|
+
move_url: "#",
|
|
98
|
+
move_param: { resource: "task", attr: "stage" },
|
|
99
|
+
group: "studio-board-demo",
|
|
100
|
+
empty_label: "Drop tasks here" %>
|
|
101
|
+
<div class="relative" x-data="{ copied: false }">
|
|
102
|
+
<pre class="bg-inset text-body text-2xs rounded-lg px-3 py-2 pr-16 overflow-x-auto"><code x-ref="boardUsage"><%= board_usage_snippet %></code></pre>
|
|
103
|
+
<button type="button"
|
|
104
|
+
class="btn btn-neutral btn-sm absolute top-2 right-2"
|
|
105
|
+
aria-label="Copy usage snippet"
|
|
106
|
+
@click="navigator.clipboard?.writeText($refs.boardUsage.innerText); copied = true; setTimeout(() => copied = false, 1200)">
|
|
107
|
+
<span x-text="copied ? 'Copied' : 'Copy'">Copy</span>
|
|
108
|
+
</button>
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
|
|
112
|
+
<%# ---- The static reference sketch ------------------------------------- %>
|
|
42
113
|
<div class="fade-edge-x overflow-x-auto pb-2">
|
|
43
114
|
<div class="flex gap-4 min-w-max">
|
|
44
115
|
<% board_columns.each do |col| %>
|
|
@@ -259,6 +259,52 @@
|
|
|
259
259
|
</div>
|
|
260
260
|
</section>
|
|
261
261
|
|
|
262
|
+
<!-- Confetti & pulse -->
|
|
263
|
+
<section class="space-y-5">
|
|
264
|
+
<div class="space-y-1">
|
|
265
|
+
<h3 class="text-xl font-bold text-heading">Confetti & pulse</h3>
|
|
266
|
+
<p class="text-muted text-sm max-w-2xl">
|
|
267
|
+
Celebration effects lifted from Turf Monster into the engine. Confetti is
|
|
268
|
+
<code class="font-mono text-2xs">window.studioConfetti</code> - a zero-dependency,
|
|
269
|
+
no-CDN effect (canvas-confetti is vendored into the engine and shipped through the
|
|
270
|
+
asset pipeline). Two callable variants, both honoring
|
|
271
|
+
<code class="font-mono text-2xs">prefers-reduced-motion</code>. The pulse is the
|
|
272
|
+
<code class="font-mono text-2xs">.pulse-cta</code> attention beat. Fire the confetti
|
|
273
|
+
with the buttons below.
|
|
274
|
+
</p>
|
|
275
|
+
</div>
|
|
276
|
+
<div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
|
277
|
+
<%= render layout: "style/specimen",
|
|
278
|
+
locals: { klass: "window.studioConfetti.burst(el)",
|
|
279
|
+
usage: %(window.studioConfetti.burst(cardEl)\n// radial burst from behind a card/modal, from its center) } do %>
|
|
280
|
+
<div x-data="{}" class="flex flex-col items-center gap-3 py-2">
|
|
281
|
+
<div x-ref="burstCard" class="card px-5 py-4 text-sm font-semibold text-heading text-center">Success!</div>
|
|
282
|
+
<button type="button" class="btn btn-primary btn-sm"
|
|
283
|
+
@click="window.studioConfetti && window.studioConfetti.burst($refs.burstCard)">Fire burst</button>
|
|
284
|
+
</div>
|
|
285
|
+
<% end %>
|
|
286
|
+
|
|
287
|
+
<%= render layout: "style/specimen",
|
|
288
|
+
locals: { klass: "window.studioConfetti.cannons()",
|
|
289
|
+
usage: %(window.studioConfetti.cannons()\n// left + right side-cannons, full-screen celebration) } do %>
|
|
290
|
+
<div x-data="{}" class="flex flex-col items-center gap-3 py-2">
|
|
291
|
+
<p class="text-sm font-semibold text-heading text-center">You joined a contest!</p>
|
|
292
|
+
<button type="button" class="btn btn-success btn-sm"
|
|
293
|
+
@click="window.studioConfetti && window.studioConfetti.cannons()">Fire cannons</button>
|
|
294
|
+
</div>
|
|
295
|
+
<% end %>
|
|
296
|
+
|
|
297
|
+
<%= render layout: "style/specimen",
|
|
298
|
+
locals: { klass: ".pulse-cta (knobs: --pulse-cta-color / -speed / -scale)",
|
|
299
|
+
usage: %(<button class="btn btn-primary pulse-cta">Change Username</button>\n<button class="btn btn-success pulse-cta" style="--pulse-cta-color: var(--color-success)">Go</button>) } do %>
|
|
300
|
+
<div class="flex flex-wrap items-center justify-center gap-4">
|
|
301
|
+
<button type="button" class="btn btn-primary pulse-cta">Change Username</button>
|
|
302
|
+
<button type="button" class="btn btn-success pulse-cta" style="--pulse-cta-color: var(--color-success)">Go</button>
|
|
303
|
+
</div>
|
|
304
|
+
<% end %>
|
|
305
|
+
</div>
|
|
306
|
+
</section>
|
|
307
|
+
|
|
262
308
|
<!-- Leveling (capability-gated: Studio.feature?(:leveling)) -->
|
|
263
309
|
<section class="space-y-5">
|
|
264
310
|
<div class="space-y-1">
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<%# locals: (card:, id_attr: "slug", zone_attr: "stage") %>
|
|
2
|
+
<%#
|
|
3
|
+
A demo board card for the /admin/style Board specimen. Renders THROUGH the engine
|
|
4
|
+
card-shell chrome (studio/board/_card_shell) so the specimen exercises the real
|
|
5
|
+
identity contract (id="card-<id>", class .kanban-card, data-<id_attr>/<zone_attr>),
|
|
6
|
+
not a bespoke stand-in. `card` is a plain Hash — the specimen has no models. The
|
|
7
|
+
id_attr / zone_attr flow through from the board so the same partial demonstrates
|
|
8
|
+
the primitive under both the default and a custom attribute naming.
|
|
9
|
+
%>
|
|
10
|
+
<%= render layout: "studio/board/card_shell",
|
|
11
|
+
locals: { id: card[:id], zone: card[:zone], id_attr: id_attr, zone_attr: zone_attr,
|
|
12
|
+
class: "card p-3 space-y-2 cursor-grab active:cursor-grabbing" } do %>
|
|
13
|
+
<div class="flex items-start gap-2">
|
|
14
|
+
<span class="text-muted select-none leading-none" aria-hidden="true">⠿</span>
|
|
15
|
+
<p class="text-sm font-semibold text-heading leading-snug flex-1"><%= card[:title] %></p>
|
|
16
|
+
</div>
|
|
17
|
+
<div class="flex items-center justify-between gap-2">
|
|
18
|
+
<%= render "components/badge", text: card[:repo], scheme: "neutral" %>
|
|
19
|
+
<span class="inline-flex h-6 w-6 items-center justify-center rounded-full text-2xs font-bold text-white shrink-0"
|
|
20
|
+
style="background: var(--color-cta)"><%= card[:who] %></span>
|
|
21
|
+
</div>
|
|
22
|
+
<% end %>
|
data/lib/studio/engine.rb
CHANGED
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.23.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alex McRitchie
|
|
@@ -170,12 +170,16 @@ files:
|
|
|
170
170
|
- README.md
|
|
171
171
|
- app/assets/images/resend-favicon.png
|
|
172
172
|
- app/assets/images/ses-favicon.png
|
|
173
|
+
- app/assets/javascripts/studio/canvas_confetti.js
|
|
174
|
+
- app/assets/javascripts/studio/sortable.js
|
|
173
175
|
- app/assets/javascripts/studio/sticky_table_header.js
|
|
176
|
+
- app/assets/javascripts/studio/studio_confetti.js
|
|
174
177
|
- app/assets/stylesheets/studio/sticky_table_header.css
|
|
175
178
|
- app/assets/tailwind/studio_engine/engine-motion.css
|
|
176
179
|
- app/assets/tailwind/studio_engine/engine.css
|
|
177
180
|
- app/controllers/concerns/solana/session_auth.rb
|
|
178
181
|
- app/controllers/concerns/studio/admin_models.rb
|
|
182
|
+
- app/controllers/concerns/studio/board/reorderable.rb
|
|
179
183
|
- app/controllers/concerns/studio/error_handling.rb
|
|
180
184
|
- app/controllers/concerns/studio/impersonation.rb
|
|
181
185
|
- app/controllers/concerns/studio/link_consumption.rb
|
|
@@ -203,6 +207,7 @@ files:
|
|
|
203
207
|
- app/mailers/application_mailer.rb
|
|
204
208
|
- app/mailers/user_mailer.rb
|
|
205
209
|
- app/models/concerns/sluggable.rb
|
|
210
|
+
- app/models/concerns/studio/board/rankable.rb
|
|
206
211
|
- app/models/concerns/studio/broadcastable.rb
|
|
207
212
|
- app/models/current.rb
|
|
208
213
|
- app/models/error_log.rb
|
|
@@ -244,8 +249,10 @@ files:
|
|
|
244
249
|
- app/views/sessions/_sso_continue.html.erb
|
|
245
250
|
- app/views/sessions/new.html.erb
|
|
246
251
|
- app/views/studio/_age_verify_assets.html.erb
|
|
252
|
+
- app/views/studio/_board_assets.html.erb
|
|
247
253
|
- app/views/studio/_confirm_interstitial.html.erb
|
|
248
254
|
- app/views/studio/_cropper_assets.html.erb
|
|
255
|
+
- app/views/studio/_leveling_activity_assets.html.erb
|
|
249
256
|
- app/views/studio/admin_models/_arenas_table.html.erb
|
|
250
257
|
- app/views/studio/admin_models/_teams_table.html.erb
|
|
251
258
|
- app/views/studio/admin_models/index.html.erb
|
|
@@ -256,6 +263,9 @@ files:
|
|
|
256
263
|
- app/views/studio/banners/_email_status_button.html.erb
|
|
257
264
|
- app/views/studio/banners/_environment.html.erb
|
|
258
265
|
- app/views/studio/banners/_impersonation.html.erb
|
|
266
|
+
- app/views/studio/board/_board.html.erb
|
|
267
|
+
- app/views/studio/board/_card_shell.html.erb
|
|
268
|
+
- app/views/studio/board/_column.html.erb
|
|
259
269
|
- app/views/studio/email_images/index.html.erb
|
|
260
270
|
- app/views/studio/links/confirm.html.erb
|
|
261
271
|
- app/views/studio/local_emails/index.html.erb
|
|
@@ -266,11 +276,13 @@ files:
|
|
|
266
276
|
- app/views/studio/modals/auth/_resend_footer.html.erb
|
|
267
277
|
- app/views/studio/modals/blocks/_age_verify.html.erb
|
|
268
278
|
- app/views/studio/modals/blocks/_card_header.html.erb
|
|
279
|
+
- app/views/studio/modals/blocks/_change_username.html.erb
|
|
269
280
|
- app/views/studio/modals/blocks/_cta_redirect.html.erb
|
|
270
281
|
- app/views/studio/modals/blocks/_digit_reel.html.erb
|
|
271
282
|
- app/views/studio/modals/blocks/_entry_confirmed.html.erb
|
|
272
283
|
- app/views/studio/modals/blocks/_error_card.html.erb
|
|
273
284
|
- app/views/studio/modals/blocks/_free_entry_earned.html.erb
|
|
285
|
+
- app/views/studio/modals/blocks/_leveling_activity.html.erb
|
|
274
286
|
- app/views/studio/modals/blocks/_onchain_success.html.erb
|
|
275
287
|
- app/views/studio/modals/blocks/_processing_card.html.erb
|
|
276
288
|
- app/views/studio/modals/blocks/_progress_countdown.html.erb
|
|
@@ -294,6 +306,7 @@ files:
|
|
|
294
306
|
- app/views/style/_tasks.html.erb
|
|
295
307
|
- app/views/style/_theme.html.erb
|
|
296
308
|
- app/views/style/_tricks.html.erb
|
|
309
|
+
- app/views/style/board/_demo_card.html.erb
|
|
297
310
|
- app/views/style/index.html.erb
|
|
298
311
|
- app/views/style/modals/_age_verify.html.erb
|
|
299
312
|
- app/views/style/modals/_auth.html.erb
|