studio-engine 0.122.0 → 0.124.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 +142 -0
- data/README.md +18 -3
- data/app/assets/tailwind/studio_engine/engine.css +210 -11
- data/app/controllers/concerns/studio/admin_models.rb +24 -16
- data/app/controllers/concerns/studio/error_handling.rb +13 -0
- data/app/controllers/studio/agent_chats_controller.rb +31 -4
- data/app/controllers/studio/marketing_kit_controller.rb +24 -0
- data/app/controllers/studio/voice_takes_controller.rb +11 -0
- data/app/controllers/style_controller.rb +2 -5
- data/app/controllers/theme_settings_controller.rb +8 -8
- data/app/helpers/studio/agent_chat_helper.rb +37 -0
- data/app/helpers/studio/site_footer_helper.rb +15 -2
- data/app/javascript/studio/agent_chat.js +42 -2
- data/app/javascript/studio/agent_chat_voice.js +318 -0
- data/app/javascript/studio/alpine_shims.js +1 -3
- data/app/javascript/studio/controllers/agent_chat_voice_controller.js +17 -0
- data/app/javascript/studio/controllers/copy_text_controller.js +63 -0
- data/app/javascript/studio/controllers/page_header_controller.js +60 -0
- data/app/javascript/studio/controllers/style_section_nav_controller.js +80 -0
- data/app/javascript/studio/microphone_chip.js +1 -0
- data/app/javascript/studio/page_header.js +24 -0
- data/app/javascript/studio/page_transitions.js +181 -0
- data/app/javascript/studio/pinned_stack.js +12 -1
- data/app/javascript/studio/stimulus.js +9 -1
- data/app/javascript/studio/style_guide.js +2 -0
- data/app/javascript/studio/style_section_nav.js +16 -0
- data/app/javascript/studio/theme_editor.js +6 -106
- data/app/javascript/studio/voice_recorder.js +23 -2
- data/app/models/studio/user_session.rb +76 -0
- data/app/models/theme_setting.rb +3 -0
- data/app/views/components/_link_sidebar.html.erb +5 -2
- data/app/views/components/_user_nav.html.erb +5 -4
- data/app/views/layouts/_navbar.html.erb +7 -4
- data/app/views/layouts/studio/_head.html.erb +6 -0
- data/app/views/layouts/studio/_smooth_load.html.erb +11 -2
- data/app/views/studio/_page_header.html.erb +65 -0
- data/app/views/studio/admin_models/_sessions_table.html.erb +28 -0
- data/app/views/studio/admin_models/show.html.erb +15 -12
- data/app/views/studio/admin_surveys/index.html.erb +2 -2
- data/app/views/studio/agent_chat/_chat.html.erb +17 -2
- data/app/views/studio/agent_chat/_form.html.erb +4 -3
- data/app/views/studio/agent_chat/_header.html.erb +1 -1
- data/app/views/studio/agent_chat/_voice.html.erb +54 -0
- data/app/views/studio/marketing_kit/_assets.html.erb +44 -0
- data/app/views/studio/marketing_kit/_kit.html.erb +84 -0
- data/app/views/studio/marketing_kit/show.html.erb +6 -0
- data/app/views/studio/site_footer/_assets.html.erb +1 -0
- data/app/views/studio/site_footer/_footer.html.erb +5 -0
- data/app/views/studio/voice/_microphone_help.html.erb +6 -3
- data/app/views/style/_theme.html.erb +75 -12
- data/app/views/style/_tricks.html.erb +35 -0
- data/app/views/style/index.html.erb +21 -34
- data/db/migrate/20261103120000_create_studio_user_sessions.rb +16 -0
- data/docs/SITE_FOOTER.md +146 -2
- data/lib/studio/agent_chat.rb +83 -5
- data/lib/studio/marketing_kit.rb +304 -0
- data/lib/studio/site_footer.rb +65 -6
- data/lib/studio/ui_primitives.rb +4 -2
- data/lib/studio/version.rb +1 -1
- data/lib/studio.rb +146 -6
- metadata +21 -4
- data/app/views/studio/admin_models/index.html.erb +0 -31
- data/app/views/theme_settings/edit.html.erb +0 -304
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.
|
|
4
|
+
version: 0.124.0
|
|
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-11-
|
|
11
|
+
date: 2026-11-04 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
@@ -466,6 +466,7 @@ files:
|
|
|
466
466
|
- app/controllers/studio/links_controller.rb
|
|
467
467
|
- app/controllers/studio/local_emails_controller.rb
|
|
468
468
|
- app/controllers/studio/local_reviews_controller.rb
|
|
469
|
+
- app/controllers/studio/marketing_kit_controller.rb
|
|
469
470
|
- app/controllers/studio/models_controller.rb
|
|
470
471
|
- app/controllers/studio/onboarding_controller.rb
|
|
471
472
|
- app/controllers/studio/profiles_controller.rb
|
|
@@ -477,6 +478,7 @@ files:
|
|
|
477
478
|
- app/controllers/style_controller.rb
|
|
478
479
|
- app/controllers/theme_settings_controller.rb
|
|
479
480
|
- app/helpers/studio/admin_models_table_helper.rb
|
|
481
|
+
- app/helpers/studio/agent_chat_helper.rb
|
|
480
482
|
- app/helpers/studio/at_time_helper.rb
|
|
481
483
|
- app/helpers/studio/fizz_helper.rb
|
|
482
484
|
- app/helpers/studio/geo_helper.rb
|
|
@@ -489,6 +491,7 @@ files:
|
|
|
489
491
|
- app/helpers/studio_sidebar_helper.rb
|
|
490
492
|
- app/helpers/studio_theme_helper.rb
|
|
491
493
|
- app/javascript/studio/agent_chat.js
|
|
494
|
+
- app/javascript/studio/agent_chat_voice.js
|
|
492
495
|
- app/javascript/studio/alpine_scopes.js
|
|
493
496
|
- app/javascript/studio/alpine_shims.js
|
|
494
497
|
- app/javascript/studio/alpine_stores.js
|
|
@@ -498,8 +501,10 @@ files:
|
|
|
498
501
|
- app/javascript/studio/booking.js
|
|
499
502
|
- app/javascript/studio/confirm_interstitial.js
|
|
500
503
|
- app/javascript/studio/controllers/agent_chat_controller.js
|
|
504
|
+
- app/javascript/studio/controllers/agent_chat_voice_controller.js
|
|
501
505
|
- app/javascript/studio/controllers/board_controller.js
|
|
502
506
|
- app/javascript/studio/controllers/booking_controller.js
|
|
507
|
+
- app/javascript/studio/controllers/copy_text_controller.js
|
|
503
508
|
- app/javascript/studio/controllers/email_banner_scale_controller.js
|
|
504
509
|
- app/javascript/studio/controllers/footer_map_controller.js
|
|
505
510
|
- app/javascript/studio/controllers/geo_settings_controller.js
|
|
@@ -511,7 +516,9 @@ files:
|
|
|
511
516
|
- app/javascript/studio/controllers/microphone_chip_controller.js
|
|
512
517
|
- app/javascript/studio/controllers/modal_host_controller.js
|
|
513
518
|
- app/javascript/studio/controllers/nav_collapse_controller.js
|
|
519
|
+
- app/javascript/studio/controllers/page_header_controller.js
|
|
514
520
|
- app/javascript/studio/controllers/style_modals_controller.js
|
|
521
|
+
- app/javascript/studio/controllers/style_section_nav_controller.js
|
|
515
522
|
- app/javascript/studio/controllers/survey_controller.js
|
|
516
523
|
- app/javascript/studio/controllers/toast_controller.js
|
|
517
524
|
- app/javascript/studio/controllers/voice_profile_controller.js
|
|
@@ -541,6 +548,8 @@ files:
|
|
|
541
548
|
- app/javascript/studio/modal_host.js
|
|
542
549
|
- app/javascript/studio/nav_collapse.js
|
|
543
550
|
- app/javascript/studio/newsletter_modal.js
|
|
551
|
+
- app/javascript/studio/page_header.js
|
|
552
|
+
- app/javascript/studio/page_transitions.js
|
|
544
553
|
- app/javascript/studio/pinned_stack.js
|
|
545
554
|
- app/javascript/studio/profile_form.js
|
|
546
555
|
- app/javascript/studio/sticky_table_header.js
|
|
@@ -548,6 +557,7 @@ files:
|
|
|
548
557
|
- app/javascript/studio/studio_confetti.js
|
|
549
558
|
- app/javascript/studio/style_guide.js
|
|
550
559
|
- app/javascript/studio/style_modals.js
|
|
560
|
+
- app/javascript/studio/style_section_nav.js
|
|
551
561
|
- app/javascript/studio/survey.js
|
|
552
562
|
- app/javascript/studio/theme_editor.js
|
|
553
563
|
- app/javascript/studio/toast.js
|
|
@@ -581,6 +591,7 @@ files:
|
|
|
581
591
|
- app/models/studio/model_page.rb
|
|
582
592
|
- app/models/studio/site_identity.rb
|
|
583
593
|
- app/models/studio/survey_response.rb
|
|
594
|
+
- app/models/studio/user_session.rb
|
|
584
595
|
- app/models/theme_setting.rb
|
|
585
596
|
- app/services/google_oauth_validator.rb
|
|
586
597
|
- app/services/studio/banner.rb
|
|
@@ -629,10 +640,11 @@ files:
|
|
|
629
640
|
- app/views/studio/_hold_button.html.erb
|
|
630
641
|
- app/views/studio/_hold_button_guard.html.erb
|
|
631
642
|
- app/views/studio/_leveling_activity_assets.html.erb
|
|
643
|
+
- app/views/studio/_page_header.html.erb
|
|
632
644
|
- app/views/studio/_session_stamp.html.erb
|
|
633
645
|
- app/views/studio/admin_models/_arenas_table.html.erb
|
|
646
|
+
- app/views/studio/admin_models/_sessions_table.html.erb
|
|
634
647
|
- app/views/studio/admin_models/_teams_table.html.erb
|
|
635
|
-
- app/views/studio/admin_models/index.html.erb
|
|
636
648
|
- app/views/studio/admin_models/show.html.erb
|
|
637
649
|
- app/views/studio/admin_surveys/index.html.erb
|
|
638
650
|
- app/views/studio/admin_surveys/show.html.erb
|
|
@@ -641,6 +653,7 @@ files:
|
|
|
641
653
|
- app/views/studio/agent_chat/_header.html.erb
|
|
642
654
|
- app/views/studio/agent_chat/_turn.html.erb
|
|
643
655
|
- app/views/studio/agent_chat/_typing.html.erb
|
|
656
|
+
- app/views/studio/agent_chat/_voice.html.erb
|
|
644
657
|
- app/views/studio/banners/_app_banner.html.erb
|
|
645
658
|
- app/views/studio/banners/_button.html.erb
|
|
646
659
|
- app/views/studio/banners/_dev_mode_button.html.erb
|
|
@@ -692,6 +705,9 @@ files:
|
|
|
692
705
|
- app/views/studio/loader/_overlay.html.erb
|
|
693
706
|
- app/views/studio/local_emails/index.html.erb
|
|
694
707
|
- app/views/studio/mailers/_layered_banner.html.erb
|
|
708
|
+
- app/views/studio/marketing_kit/_assets.html.erb
|
|
709
|
+
- app/views/studio/marketing_kit/_kit.html.erb
|
|
710
|
+
- app/views/studio/marketing_kit/show.html.erb
|
|
695
711
|
- app/views/studio/modals/_crop_photo.html.erb
|
|
696
712
|
- app/views/studio/modals/_host.html.erb
|
|
697
713
|
- app/views/studio/modals/_image_upload.html.erb
|
|
@@ -796,7 +812,6 @@ files:
|
|
|
796
812
|
- app/views/style/modals/_unsubscribe_confirm.html.erb
|
|
797
813
|
- app/views/style/modals/_wallet_connect.html.erb
|
|
798
814
|
- app/views/style/modals/_wallet_connect_slot.html.erb
|
|
799
|
-
- app/views/theme_settings/edit.html.erb
|
|
800
815
|
- app/views/user_mailer/magic_link.html.erb
|
|
801
816
|
- app/views/user_mailer/magic_link.text.erb
|
|
802
817
|
- config/importmap.rb
|
|
@@ -821,6 +836,7 @@ files:
|
|
|
821
836
|
- db/migrate/20261008120000_add_recording_to_studio_knowledge_docs.rb
|
|
822
837
|
- db/migrate/20261010120000_add_stored_in_to_image_caches.rb
|
|
823
838
|
- db/migrate/20261029120000_add_voice_profile_to_users.rb
|
|
839
|
+
- db/migrate/20261103120000_create_studio_user_sessions.rb
|
|
824
840
|
- docs/BOOKING.md
|
|
825
841
|
- docs/SITE_FOOTER.md
|
|
826
842
|
- lib/active_storage/service/studio_trash_s3_service.rb
|
|
@@ -864,6 +880,7 @@ files:
|
|
|
864
880
|
- lib/studio/log_rotation.rb
|
|
865
881
|
- lib/studio/mail_sender.rb
|
|
866
882
|
- lib/studio/mail_transport.rb
|
|
883
|
+
- lib/studio/marketing_kit.rb
|
|
867
884
|
- lib/studio/name_parts.rb
|
|
868
885
|
- lib/studio/navbar_account_sidebar.rb
|
|
869
886
|
- lib/studio/navbar_brand.rb
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
<% content_for(:title, "Models - Admin") %>
|
|
2
|
-
|
|
3
|
-
<div class="max-w-7xl mx-auto px-4 py-8 space-y-6">
|
|
4
|
-
<header class="flex flex-col gap-3 md:flex-row md:items-end md:justify-between">
|
|
5
|
-
<div>
|
|
6
|
-
<p class="text-xs text-muted uppercase tracking-wide font-semibold">Admin QA</p>
|
|
7
|
-
<h1 class="text-heading text-2xl font-bold mt-1">Models</h1>
|
|
8
|
-
<p class="text-muted text-sm mt-1">Ten-row snapshots for records that need quick inspection.</p>
|
|
9
|
-
</div>
|
|
10
|
-
<%= link_to "Back to dashboard", admin_dashboard_path, class: "btn btn-outline" %>
|
|
11
|
-
</header>
|
|
12
|
-
|
|
13
|
-
<div class="space-y-5">
|
|
14
|
-
<% @sections.each do |section| %>
|
|
15
|
-
<section id="model-<%= section.fetch(:key) %>" class="card overflow-hidden">
|
|
16
|
-
<div class="px-4 py-4 border-b border-subtle flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
|
17
|
-
<div>
|
|
18
|
-
<h2 class="text-heading text-lg font-semibold"><%= section.fetch(:label) %></h2>
|
|
19
|
-
<p class="text-xs text-muted"><%= section.fetch(:description) %></p>
|
|
20
|
-
</div>
|
|
21
|
-
<div class="flex items-center gap-3">
|
|
22
|
-
<span class="text-xs text-muted">Showing <%= section.fetch(:records).size %> of <%= section.fetch(:count) %></span>
|
|
23
|
-
<%= link_to "View all", admin_model_path(section.fetch(:key)), class: "text-xs text-primary hover:underline" %>
|
|
24
|
-
</div>
|
|
25
|
-
</div>
|
|
26
|
-
|
|
27
|
-
<%= render admin_models_table_partial(section.fetch(:key)), records: section.fetch(:records) %>
|
|
28
|
-
</section>
|
|
29
|
-
<% end %>
|
|
30
|
-
</div>
|
|
31
|
-
</div>
|
|
@@ -1,304 +0,0 @@
|
|
|
1
|
-
<%# The editor is studio/theme_editor's themeEditor factory, seeded with the
|
|
2
|
-
server-resolved role colours. studio/alpine_shims publishes it. %>
|
|
3
|
-
<div class="max-w-5xl mx-auto px-4 py-8" x-data="themeEditor(<%= @theme_setting.resolved_colors.to_json %>)">
|
|
4
|
-
<div class="flex items-center justify-between mb-8">
|
|
5
|
-
<h1 class="text-2xl font-bold text-heading">Theme</h1>
|
|
6
|
-
<div class="flex gap-3">
|
|
7
|
-
<%= form_tag("/admin/theme/regenerate", method: :post) do %>
|
|
8
|
-
<button type="submit" class="btn btn-outline btn-sm">Regenerate Cache</button>
|
|
9
|
-
<% end %>
|
|
10
|
-
</div>
|
|
11
|
-
</div>
|
|
12
|
-
|
|
13
|
-
<%= form_tag("/admin/theme", method: :patch) do %>
|
|
14
|
-
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
|
15
|
-
<!-- Color Inputs -->
|
|
16
|
-
<div class="card p-6">
|
|
17
|
-
<h2 class="text-lg font-bold text-heading mb-6">Role Colors</h2>
|
|
18
|
-
|
|
19
|
-
<% ThemeSetting::ROLES.each do |role| %>
|
|
20
|
-
<% db_col = ThemeSetting.db_column_for(role) %>
|
|
21
|
-
<% db_val = @theme_setting.read_attribute(db_col) %>
|
|
22
|
-
<% default_val = @defaults[role] %>
|
|
23
|
-
<% current_val = db_val.presence || default_val %>
|
|
24
|
-
<div class="flex items-center gap-4 mb-4">
|
|
25
|
-
<input type="color"
|
|
26
|
-
:value="colors.<%= role %>"
|
|
27
|
-
@input="colors.<%= role %> = $event.target.value; updatePreview()"
|
|
28
|
-
class="w-10 h-10 rounded cursor-pointer border border-subtle"
|
|
29
|
-
style="padding: 1px;">
|
|
30
|
-
<div class="flex-1">
|
|
31
|
-
<div class="flex items-center gap-2">
|
|
32
|
-
<span class="text-heading font-medium text-sm"><%= role.to_s.titleize %></span>
|
|
33
|
-
<% if db_val.present? %>
|
|
34
|
-
<span class="text-xs text-muted">(custom)</span>
|
|
35
|
-
<% end %>
|
|
36
|
-
</div>
|
|
37
|
-
<input type="text"
|
|
38
|
-
name="theme_setting[<%= db_col %>]"
|
|
39
|
-
x-model="colors.<%= role %>"
|
|
40
|
-
@input="updatePreview()"
|
|
41
|
-
@blur="normalizeHex('<%= role %>')"
|
|
42
|
-
class="text-xs text-secondary font-mono"
|
|
43
|
-
style="background: transparent; border: none; border-bottom: 1px dashed currentColor; padding: 0; width: 5.5rem; outline: none;"
|
|
44
|
-
spellcheck="false">
|
|
45
|
-
</div>
|
|
46
|
-
<% if default_val %>
|
|
47
|
-
<button type="button"
|
|
48
|
-
@click="resetColor('<%= role %>', '<%= default_val %>')"
|
|
49
|
-
class="text-xs text-muted hover:text-heading transition"
|
|
50
|
-
title="Reset to default (<%= default_val %>)">
|
|
51
|
-
Reset
|
|
52
|
-
</button>
|
|
53
|
-
<% end %>
|
|
54
|
-
</div>
|
|
55
|
-
<% end %>
|
|
56
|
-
|
|
57
|
-
<div class="flex gap-3 mt-6 pt-6 border-t border-subtle">
|
|
58
|
-
<button type="submit" class="btn btn-primary">Save Theme</button>
|
|
59
|
-
</div>
|
|
60
|
-
</div>
|
|
61
|
-
|
|
62
|
-
<!-- Live Preview -->
|
|
63
|
-
<div class="space-y-6">
|
|
64
|
-
<!-- Dark Preview -->
|
|
65
|
-
<div class="rounded-xl border border-subtle overflow-hidden">
|
|
66
|
-
<div class="px-4 py-2 bg-surface-alt">
|
|
67
|
-
<span class="text-xs font-bold text-secondary uppercase tracking-wider">Dark Mode Preview</span>
|
|
68
|
-
</div>
|
|
69
|
-
<div class="p-6" :style="darkPreviewStyle()">
|
|
70
|
-
<h3 class="font-bold mb-1" :style="{ color: '#ffffff' }">Page Heading</h3>
|
|
71
|
-
<p class="text-sm mb-4" :style="{ color: '#e2e8f0' }">Body text on the page surface.</p>
|
|
72
|
-
<div class="rounded-lg p-4 mb-4" :style="darkSurfaceStyle()">
|
|
73
|
-
<p class="text-sm mb-3" :style="{ color: '#94a3b8' }">Card on surface with secondary text.</p>
|
|
74
|
-
<div class="flex gap-2">
|
|
75
|
-
<button class="btn btn-sm text-white rounded-lg px-3 py-1.5 text-xs font-bold" :style="{ backgroundColor: colors.primary }">Primary</button>
|
|
76
|
-
<button class="btn btn-sm text-white rounded-lg px-3 py-1.5 text-xs font-bold" :style="{ backgroundColor: colors.success || '#367E3A' }">Accent</button>
|
|
77
|
-
<button class="btn btn-sm text-white rounded-lg px-3 py-1.5 text-xs font-bold" :style="{ backgroundColor: colors.danger || '#EF4444' }">Danger</button>
|
|
78
|
-
</div>
|
|
79
|
-
</div>
|
|
80
|
-
<div class="flex gap-2">
|
|
81
|
-
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium" :style="{ backgroundColor: colors.primary + '33', color: colors.primary, border: '1px solid ' + colors.primary + '55' }">Badge</span>
|
|
82
|
-
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium" :style="{ backgroundColor: (colors.success || '#367E3A') + '33', color: colors.success || '#367E3A', border: '1px solid ' + (colors.success || '#367E3A') + '55' }">Success</span>
|
|
83
|
-
</div>
|
|
84
|
-
</div>
|
|
85
|
-
</div>
|
|
86
|
-
|
|
87
|
-
<!-- Light Preview -->
|
|
88
|
-
<div class="rounded-xl border border-subtle overflow-hidden">
|
|
89
|
-
<div class="px-4 py-2 bg-surface-alt">
|
|
90
|
-
<span class="text-xs font-bold text-secondary uppercase tracking-wider">Light Mode Preview</span>
|
|
91
|
-
</div>
|
|
92
|
-
<div class="p-6" :style="lightPreviewStyle()">
|
|
93
|
-
<h3 class="font-bold mb-1" :style="{ color: '#0f172a' }">Page Heading</h3>
|
|
94
|
-
<p class="text-sm mb-4" :style="{ color: '#334155' }">Body text on the page surface.</p>
|
|
95
|
-
<div class="rounded-lg p-4 mb-4" :style="lightSurfaceStyle()">
|
|
96
|
-
<p class="text-sm mb-3" :style="{ color: '#64748b' }">Card on surface with secondary text.</p>
|
|
97
|
-
<div class="flex gap-2">
|
|
98
|
-
<button class="btn btn-sm text-white rounded-lg px-3 py-1.5 text-xs font-bold" :style="{ backgroundColor: colors.primary }">Primary</button>
|
|
99
|
-
<button class="btn btn-sm text-white rounded-lg px-3 py-1.5 text-xs font-bold" :style="{ backgroundColor: colors.success || '#367E3A' }">Accent</button>
|
|
100
|
-
<button class="btn btn-sm text-white rounded-lg px-3 py-1.5 text-xs font-bold" :style="{ backgroundColor: colors.danger || '#EF4444' }">Danger</button>
|
|
101
|
-
</div>
|
|
102
|
-
</div>
|
|
103
|
-
<div class="flex gap-2">
|
|
104
|
-
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium" :style="{ backgroundColor: colors.primary + '33', color: colors.primary, border: '1px solid ' + colors.primary + '55' }">Badge</span>
|
|
105
|
-
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium" :style="{ backgroundColor: (colors.success || '#367E3A') + '33', color: colors.success || '#367E3A', border: '1px solid ' + (colors.success || '#367E3A') + '55' }">Success</span>
|
|
106
|
-
</div>
|
|
107
|
-
</div>
|
|
108
|
-
</div>
|
|
109
|
-
</div>
|
|
110
|
-
</div>
|
|
111
|
-
<% end %>
|
|
112
|
-
|
|
113
|
-
<%# ── Styleguide ── %>
|
|
114
|
-
<div class="border-t border-subtle mt-12 pt-12 space-y-12">
|
|
115
|
-
|
|
116
|
-
<% if Studio.theme_logos.any? %>
|
|
117
|
-
<%# ── Logos ── %>
|
|
118
|
-
<section>
|
|
119
|
-
<h2 class="text-xl font-bold text-heading mb-4">Logos</h2>
|
|
120
|
-
<div class="grid grid-cols-2 md:grid-cols-5 gap-4">
|
|
121
|
-
<% Studio.theme_logos.each do |logo| %>
|
|
122
|
-
<% file = logo.is_a?(Hash) ? logo[:file] : logo %>
|
|
123
|
-
<% title = logo.is_a?(Hash) ? logo[:title] : file %>
|
|
124
|
-
<div class="card p-4 space-y-3">
|
|
125
|
-
<p class="label-upper"><%= title %></p>
|
|
126
|
-
<div class="flex items-center justify-center w-20 h-20 rounded-lg" style="background-color: #ddd; background-image: linear-gradient(45deg, #777 25%, transparent 25%, transparent 75%, #777 75%), linear-gradient(45deg, #777 25%, transparent 25%, transparent 75%, #777 75%); background-size: 12px 12px; background-position: 0 0, 6px 6px;">
|
|
127
|
-
<img src="/<%= file %>" alt="<%= title %>" class="max-w-16 max-h-16 rounded">
|
|
128
|
-
</div>
|
|
129
|
-
<p class="text-muted text-xs font-mono"><%= file %></p>
|
|
130
|
-
</div>
|
|
131
|
-
<% end %>
|
|
132
|
-
</div>
|
|
133
|
-
</section>
|
|
134
|
-
<% end %>
|
|
135
|
-
|
|
136
|
-
<%# ── Semantic Tokens ── %>
|
|
137
|
-
<section>
|
|
138
|
-
<h2 class="text-xl font-bold text-heading mb-4">Semantic Tokens</h2>
|
|
139
|
-
<div class="grid grid-cols-2 md:grid-cols-5 gap-3">
|
|
140
|
-
<%
|
|
141
|
-
semantic_colors = [
|
|
142
|
-
{ name: "Page", utility: "bg-page", type: :bg },
|
|
143
|
-
{ name: "Surface", utility: "bg-surface", type: :bg },
|
|
144
|
-
{ name: "Surface Alt", utility: "bg-surface-alt", type: :bg },
|
|
145
|
-
{ name: "Inset", utility: "bg-inset", type: :bg },
|
|
146
|
-
{ name: "Heading", utility: "text-heading", type: :text },
|
|
147
|
-
{ name: "Body", utility: "text-body", type: :text },
|
|
148
|
-
{ name: "Secondary", utility: "text-secondary", type: :text },
|
|
149
|
-
{ name: "Muted", utility: "text-muted", type: :text },
|
|
150
|
-
{ name: "Border", utility: "border-subtle", type: :border },
|
|
151
|
-
{ name: "Border Strong", utility: "border-strong", type: :border },
|
|
152
|
-
]
|
|
153
|
-
%>
|
|
154
|
-
<% semantic_colors.each do |c| %>
|
|
155
|
-
<div class="card p-3 flex items-center gap-3">
|
|
156
|
-
<% if c[:type] == :bg %>
|
|
157
|
-
<div class="w-8 h-8 rounded-full border border-subtle shrink-0 <%= c[:utility] %>"></div>
|
|
158
|
-
<% elsif c[:type] == :text %>
|
|
159
|
-
<div class="w-8 h-8 rounded-full border border-subtle shrink-0 bg-surface flex items-center justify-center">
|
|
160
|
-
<span class="text-sm font-bold <%= c[:utility] %>">A</span>
|
|
161
|
-
</div>
|
|
162
|
-
<% else %>
|
|
163
|
-
<div class="w-8 h-8 rounded-full shrink-0 border-2 <%= c[:utility] %> bg-transparent"></div>
|
|
164
|
-
<% end %>
|
|
165
|
-
<div class="min-w-0">
|
|
166
|
-
<p class="text-heading text-sm font-semibold truncate"><%= c[:name] %></p>
|
|
167
|
-
<p class="text-muted text-xs font-mono truncate"><%= c[:utility] %></p>
|
|
168
|
-
</div>
|
|
169
|
-
</div>
|
|
170
|
-
<% end %>
|
|
171
|
-
</div>
|
|
172
|
-
</section>
|
|
173
|
-
|
|
174
|
-
<%# ── Typography ── %>
|
|
175
|
-
<section>
|
|
176
|
-
<h2 class="text-xl font-bold text-heading mb-4">Typography</h2>
|
|
177
|
-
<div class="card p-6 space-y-4">
|
|
178
|
-
<p class="text-heading text-3xl font-extrabold">Heading — Montserrat 800</p>
|
|
179
|
-
<p class="text-heading text-xl font-bold">Subheading — Montserrat 700</p>
|
|
180
|
-
<p class="text-body text-base">Body text — The quick brown fox jumps over the lazy dog. Montserrat 400</p>
|
|
181
|
-
<p class="text-secondary text-sm">Secondary text — Additional context and metadata. Montserrat 400</p>
|
|
182
|
-
<p class="text-muted text-xs">Muted text — Timestamps, hints, and fine print. Montserrat 400</p>
|
|
183
|
-
<hr class="border-subtle">
|
|
184
|
-
<div class="flex flex-wrap gap-4">
|
|
185
|
-
<% [400, 500, 600, 700, 800, 900].each do |w| %>
|
|
186
|
-
<span class="text-heading text-lg" style="font-weight: <%= w %>"><%= w %></span>
|
|
187
|
-
<% end %>
|
|
188
|
-
</div>
|
|
189
|
-
</div>
|
|
190
|
-
</section>
|
|
191
|
-
|
|
192
|
-
<%# ── Buttons ── %>
|
|
193
|
-
<section>
|
|
194
|
-
<h2 class="text-xl font-bold text-heading mb-4">Buttons</h2>
|
|
195
|
-
<div class="card p-6 space-y-6">
|
|
196
|
-
<div>
|
|
197
|
-
<p class="label-upper mb-3">Primary</p>
|
|
198
|
-
<div class="flex flex-wrap items-center gap-3">
|
|
199
|
-
<button type="button" class="btn btn-primary btn-sm">Small</button>
|
|
200
|
-
<button type="button" class="btn btn-primary">Medium</button>
|
|
201
|
-
<button type="button" class="btn btn-primary btn-lg">Large</button>
|
|
202
|
-
</div>
|
|
203
|
-
</div>
|
|
204
|
-
<div>
|
|
205
|
-
<p class="label-upper mb-3">Secondary</p>
|
|
206
|
-
<div class="flex flex-wrap items-center gap-3">
|
|
207
|
-
<button type="button" class="btn btn-secondary btn-sm">Small</button>
|
|
208
|
-
<button type="button" class="btn btn-secondary">Medium</button>
|
|
209
|
-
<button type="button" class="btn btn-secondary btn-lg">Large</button>
|
|
210
|
-
</div>
|
|
211
|
-
</div>
|
|
212
|
-
<div>
|
|
213
|
-
<p class="label-upper mb-3">Outline</p>
|
|
214
|
-
<div class="flex flex-wrap items-center gap-3">
|
|
215
|
-
<button type="button" class="btn btn-outline btn-sm">Small</button>
|
|
216
|
-
<button type="button" class="btn btn-outline">Medium</button>
|
|
217
|
-
<button type="button" class="btn btn-outline btn-lg">Large</button>
|
|
218
|
-
</div>
|
|
219
|
-
</div>
|
|
220
|
-
<div>
|
|
221
|
-
<p class="label-upper mb-3">Danger</p>
|
|
222
|
-
<div class="flex flex-wrap items-center gap-3">
|
|
223
|
-
<button type="button" class="btn btn-danger btn-sm">Small</button>
|
|
224
|
-
<button type="button" class="btn btn-danger">Medium</button>
|
|
225
|
-
<button type="button" class="btn btn-danger btn-lg">Large</button>
|
|
226
|
-
</div>
|
|
227
|
-
</div>
|
|
228
|
-
<div>
|
|
229
|
-
<p class="label-upper mb-3">Google</p>
|
|
230
|
-
<div class="flex flex-wrap items-center gap-3">
|
|
231
|
-
<button type="button" class="btn btn-google">Sign in with Google</button>
|
|
232
|
-
</div>
|
|
233
|
-
</div>
|
|
234
|
-
<div>
|
|
235
|
-
<p class="label-upper mb-3">Disabled</p>
|
|
236
|
-
<div class="flex flex-wrap items-center gap-3">
|
|
237
|
-
<button type="button" class="btn btn-primary" disabled>Primary</button>
|
|
238
|
-
<button type="button" class="btn btn-outline" disabled>Outline</button>
|
|
239
|
-
<button type="button" class="btn btn-danger" disabled>Danger</button>
|
|
240
|
-
</div>
|
|
241
|
-
</div>
|
|
242
|
-
</div>
|
|
243
|
-
</section>
|
|
244
|
-
|
|
245
|
-
<%# ── Components ── %>
|
|
246
|
-
<section>
|
|
247
|
-
<h2 class="text-xl font-bold text-heading mb-4">Components</h2>
|
|
248
|
-
<div class="space-y-6">
|
|
249
|
-
<div>
|
|
250
|
-
<p class="label-upper mb-3">Cards</p>
|
|
251
|
-
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
252
|
-
<div class="card p-6">
|
|
253
|
-
<p class="text-heading font-semibold mb-1">.card</p>
|
|
254
|
-
<p class="text-secondary text-sm">Static card with surface background and subtle border.</p>
|
|
255
|
-
</div>
|
|
256
|
-
<div class="card-hover p-6">
|
|
257
|
-
<p class="text-heading font-semibold mb-1">.card-hover</p>
|
|
258
|
-
<p class="text-secondary text-sm">Interactive card — hover to see the border glow.</p>
|
|
259
|
-
</div>
|
|
260
|
-
</div>
|
|
261
|
-
</div>
|
|
262
|
-
|
|
263
|
-
<div>
|
|
264
|
-
<p class="label-upper mb-3">Badges</p>
|
|
265
|
-
<div class="flex flex-wrap gap-2">
|
|
266
|
-
<span class="badge bg-mint/10 text-mint border-mint/30">Mint</span>
|
|
267
|
-
<span class="badge bg-violet/10 text-violet border-violet/30">Violet</span>
|
|
268
|
-
<span class="badge bg-red-600/10 text-red-400 border-red-600/30">Red</span>
|
|
269
|
-
<span class="badge bg-yellow-500/10 text-yellow-400 border-yellow-500/30">Yellow</span>
|
|
270
|
-
<span class="badge bg-surface-alt text-secondary border-subtle">Gray</span>
|
|
271
|
-
</div>
|
|
272
|
-
</div>
|
|
273
|
-
|
|
274
|
-
<div>
|
|
275
|
-
<p class="label-upper mb-3">Input Field</p>
|
|
276
|
-
<div class="max-w-md">
|
|
277
|
-
<input type="text" class="input-field" placeholder="Placeholder text...">
|
|
278
|
-
</div>
|
|
279
|
-
</div>
|
|
280
|
-
|
|
281
|
-
<div>
|
|
282
|
-
<p class="label-upper mb-3">Empty State</p>
|
|
283
|
-
<div class="empty-state">
|
|
284
|
-
<p class="text-secondary">No items found.</p>
|
|
285
|
-
<p class="text-muted text-sm mt-1">Try adjusting your search or filters.</p>
|
|
286
|
-
</div>
|
|
287
|
-
</div>
|
|
288
|
-
|
|
289
|
-
<div>
|
|
290
|
-
<p class="label-upper mb-3">Label Upper</p>
|
|
291
|
-
<span class="label-upper">This is a .label-upper element</span>
|
|
292
|
-
</div>
|
|
293
|
-
|
|
294
|
-
<div>
|
|
295
|
-
<p class="label-upper mb-3">JSON Debug</p>
|
|
296
|
-
<div class="json-debug">
|
|
297
|
-
<pre class="text-mint text-sm font-mono"><%= JSON.pretty_generate({ id: 1, name: "Example", status: "active", created_at: Time.current.iso8601 }) %></pre>
|
|
298
|
-
</div>
|
|
299
|
-
</div>
|
|
300
|
-
</div>
|
|
301
|
-
</section>
|
|
302
|
-
|
|
303
|
-
</div>
|
|
304
|
-
</div>
|