studio-engine 0.123.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.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +64 -0
  3. data/README.md +16 -1
  4. data/app/assets/tailwind/studio_engine/engine.css +210 -11
  5. data/app/controllers/studio/marketing_kit_controller.rb +24 -0
  6. data/app/helpers/studio/site_footer_helper.rb +15 -2
  7. data/app/javascript/studio/controllers/copy_text_controller.js +63 -0
  8. data/app/javascript/studio/controllers/page_header_controller.js +60 -0
  9. data/app/javascript/studio/page_header.js +24 -0
  10. data/app/javascript/studio/page_transitions.js +181 -0
  11. data/app/javascript/studio/pinned_stack.js +12 -1
  12. data/app/javascript/studio/stimulus.js +6 -1
  13. data/app/views/components/_link_sidebar.html.erb +5 -2
  14. data/app/views/components/_user_nav.html.erb +5 -4
  15. data/app/views/layouts/_navbar.html.erb +7 -4
  16. data/app/views/layouts/studio/_head.html.erb +6 -0
  17. data/app/views/layouts/studio/_smooth_load.html.erb +11 -2
  18. data/app/views/studio/_page_header.html.erb +65 -0
  19. data/app/views/studio/admin_models/show.html.erb +10 -18
  20. data/app/views/studio/admin_surveys/index.html.erb +2 -2
  21. data/app/views/studio/agent_chat/_form.html.erb +1 -1
  22. data/app/views/studio/agent_chat/_header.html.erb +1 -1
  23. data/app/views/studio/marketing_kit/_assets.html.erb +44 -0
  24. data/app/views/studio/marketing_kit/_kit.html.erb +84 -0
  25. data/app/views/studio/marketing_kit/show.html.erb +6 -0
  26. data/app/views/studio/site_footer/_assets.html.erb +1 -0
  27. data/app/views/studio/site_footer/_footer.html.erb +5 -0
  28. data/app/views/style/_tricks.html.erb +35 -0
  29. data/app/views/style/index.html.erb +17 -28
  30. data/docs/SITE_FOOTER.md +113 -2
  31. data/lib/studio/marketing_kit.rb +304 -0
  32. data/lib/studio/site_footer.rb +22 -6
  33. data/lib/studio/version.rb +1 -1
  34. data/lib/studio.rb +83 -1
  35. metadata +11 -1
data/lib/studio.rb CHANGED
@@ -34,6 +34,7 @@ require "studio/hold_button"
34
34
  require "studio/partial_block"
35
35
  require "studio/sidebar_sections"
36
36
  require "studio/site_footer"
37
+ require "studio/marketing_kit"
37
38
  require "studio/booking"
38
39
  require "studio/navbar_links"
39
40
  require "studio/navbar_signed_out_cta"
@@ -159,6 +160,23 @@ module Studio
159
160
  # no-preview holds the old page until the fresh response arrives.
160
161
  mattr_accessor :smooth_load, default: false
161
162
 
163
+ # ---- App-to-app page transitions -----------------------------------------
164
+ # One of :left, :right, :top, :bottom, or nil (the default: nothing changes).
165
+ # The way this app's pages move on every page change (docs/PAGE_TRANSITIONS.md).
166
+ # It is THE one switch: a set direction also turns smooth-load on, whatever
167
+ # Studio.smooth_load says, because the view transition is what it styles.
168
+ PAGE_TRANSITION_DIRECTIONS = %i[left right top bottom].freeze
169
+ mattr_reader :page_transition_direction, default: nil
170
+
171
+ def self.page_transition_direction=(value)
172
+ direction = value.presence&.to_sym
173
+ unless direction.nil? || PAGE_TRANSITION_DIRECTIONS.include?(direction)
174
+ raise ArgumentError, "Studio.page_transition_direction must be one of " \
175
+ "#{PAGE_TRANSITION_DIRECTIONS.join(', ')} or nil (got #{value.inspect})"
176
+ end
177
+ @@page_transition_direction = direction
178
+ end
179
+
162
180
  # Minimum ms the nav spinner stays visible once shown (_head.html.erb).
163
181
  # Apps wrapping multi-second operations in the spinner (e.g. Solana RPC)
164
182
  # keep the high default to avoid flicker; smooth-load apps typically drop
@@ -1805,7 +1823,8 @@ module Studio
1805
1823
  booking_path: booking_path_for(view), address: site_footer_address,
1806
1824
  chat: SiteFooter.chat_row(view, path: site_footer_chat_path,
1807
1825
  label: site_footer_chat_label,
1808
- allowed: site_footer_chat_allowed.nil? ? agent_chat_allowed : site_footer_chat_allowed))
1826
+ allowed: site_footer_chat_allowed.nil? ? agent_chat_allowed : site_footer_chat_allowed),
1827
+ marketing_kit: MarketingKit.page_path(view, host_route_set))
1809
1828
  end
1810
1829
 
1811
1830
  # The host's route set, for the default footer's legal links. nil outside a
@@ -1816,6 +1835,65 @@ module Studio
1816
1835
  ::Rails.application.routes
1817
1836
  end
1818
1837
 
1838
+ # The marketing kit: the public page at /marketing-kit (lib/studio/marketing_kit.rb,
1839
+ # docs/SITE_FOOTER.md). A Hash, or a callable receiving the view. Unset, the logos
1840
+ # and colours derive from the app's own brand artwork and the colours it paints,
1841
+ # so a new app has a working page with no setup.
1842
+ mattr_reader :marketing_kit, default: nil
1843
+
1844
+ def self.marketing_kit=(declared)
1845
+ MarketingKit.validate!(declared)
1846
+ @@marketing_kit = declared
1847
+ end
1848
+
1849
+ # Whether Studio.routes draws /marketing-kit (Studio::MarketingKitController).
1850
+ #
1851
+ # ON BY DEFAULT: every app should have a kit. The helper is
1852
+ # studio_marketing_kit_path, not marketing_kit_path, because the hub already
1853
+ # owns that name, and a second claim on it raises `Invalid route name, already
1854
+ # in use` and takes down the host's route set (see draw_admin_emails_routes).
1855
+ # The PATH can be shared: a host's own /marketing-kit wins, whichever side of
1856
+ # Studio.routes it is drawn on (Studio.marketing_kit_routes).
1857
+ mattr_accessor :draw_marketing_kit_routes, default: true
1858
+
1859
+ # The kit for a view. `declared` lets a page render a kit other than the app's.
1860
+ def self.marketing_kit_for(view, declared: marketing_kit)
1861
+ colors = marketing_kit_colors
1862
+ MarketingKit.resolve(declared, view, logos: theme_logos, theme: colors,
1863
+ artwork: [["Navbar logo", navbar_wordmark], ["Footer logo", marketing_kit_lockup(view)]],
1864
+ name: site_identity[:title], dark_ground: colors[:dark])
1865
+ end
1866
+
1867
+ # What the app paints: an /admin/theme edit included, as studio_theme_css_tag
1868
+ # reads it. An app with no database, or no table yet, paints its config.
1869
+ def self.marketing_kit_colors
1870
+ return theme_config unless active_record? && defined?(::ThemeSetting)
1871
+
1872
+ ::ThemeSetting.current.resolved_colors
1873
+ rescue StandardError
1874
+ theme_config
1875
+ end
1876
+
1877
+ # The footer's lockup, already resolved for this request where the view is one.
1878
+ def self.marketing_kit_lockup(view)
1879
+ view.studio_site_footer_facts&.dig(:lockup) if view.respond_to?(:studio_site_footer_facts)
1880
+ end
1881
+
1882
+ # Draws the page into `router`, unless the host's own /marketing-kit got there
1883
+ # first: then this draws nothing, and the host's page is the only route. A host
1884
+ # route drawn later is handled at request time, by the route's constraint.
1885
+ #
1886
+ # Studio.routes calls this. An app with no database cannot call Studio.routes
1887
+ # (docs/SITE_FOOTER.md, "An app with no database") and calls this alone.
1888
+ def self.marketing_kit_routes(router)
1889
+ router.instance_exec do
1890
+ next if MarketingKit.host_route?(@set)
1891
+
1892
+ get MarketingKit::PATH.delete_prefix("/"), to: "#{MarketingKit::CONTROLLER}#show", as: MarketingKit::ROUTE_NAME,
1893
+ format: false, constraints: MarketingKit::YieldToHostRoute.new(@set)
1894
+ end
1895
+ end
1896
+
1819
1897
  # Navbar links resolved for a view context (lib/studio/navbar_links.rb).
1820
1898
  def self.navbar_links_for(view)
1821
1899
  NavbarLinks.resolve(navbar_links, view)
@@ -2112,6 +2190,10 @@ module Studio
2112
2190
  get "schedule", to: "studio/bookings#show", as: :studio_booking
2113
2191
  end
2114
2192
 
2193
+ # The marketing kit (/marketing-kit): public, ON by default. A host's own
2194
+ # page of the same path wins. See Studio.marketing_kit_routes.
2195
+ Studio.marketing_kit_routes(self) if Studio.draw_marketing_kit_routes
2196
+
2115
2197
  # The living style guide (StyleController#index).
2116
2198
  get "admin/style", to: "style#index", as: :admin_style
2117
2199
 
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.123.0
4
+ version: 0.124.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex McRitchie
@@ -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
@@ -503,6 +504,7 @@ files:
503
504
  - app/javascript/studio/controllers/agent_chat_voice_controller.js
504
505
  - app/javascript/studio/controllers/board_controller.js
505
506
  - app/javascript/studio/controllers/booking_controller.js
507
+ - app/javascript/studio/controllers/copy_text_controller.js
506
508
  - app/javascript/studio/controllers/email_banner_scale_controller.js
507
509
  - app/javascript/studio/controllers/footer_map_controller.js
508
510
  - app/javascript/studio/controllers/geo_settings_controller.js
@@ -514,6 +516,7 @@ files:
514
516
  - app/javascript/studio/controllers/microphone_chip_controller.js
515
517
  - app/javascript/studio/controllers/modal_host_controller.js
516
518
  - app/javascript/studio/controllers/nav_collapse_controller.js
519
+ - app/javascript/studio/controllers/page_header_controller.js
517
520
  - app/javascript/studio/controllers/style_modals_controller.js
518
521
  - app/javascript/studio/controllers/style_section_nav_controller.js
519
522
  - app/javascript/studio/controllers/survey_controller.js
@@ -545,6 +548,8 @@ files:
545
548
  - app/javascript/studio/modal_host.js
546
549
  - app/javascript/studio/nav_collapse.js
547
550
  - app/javascript/studio/newsletter_modal.js
551
+ - app/javascript/studio/page_header.js
552
+ - app/javascript/studio/page_transitions.js
548
553
  - app/javascript/studio/pinned_stack.js
549
554
  - app/javascript/studio/profile_form.js
550
555
  - app/javascript/studio/sticky_table_header.js
@@ -635,6 +640,7 @@ files:
635
640
  - app/views/studio/_hold_button.html.erb
636
641
  - app/views/studio/_hold_button_guard.html.erb
637
642
  - app/views/studio/_leveling_activity_assets.html.erb
643
+ - app/views/studio/_page_header.html.erb
638
644
  - app/views/studio/_session_stamp.html.erb
639
645
  - app/views/studio/admin_models/_arenas_table.html.erb
640
646
  - app/views/studio/admin_models/_sessions_table.html.erb
@@ -699,6 +705,9 @@ files:
699
705
  - app/views/studio/loader/_overlay.html.erb
700
706
  - app/views/studio/local_emails/index.html.erb
701
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
702
711
  - app/views/studio/modals/_crop_photo.html.erb
703
712
  - app/views/studio/modals/_host.html.erb
704
713
  - app/views/studio/modals/_image_upload.html.erb
@@ -871,6 +880,7 @@ files:
871
880
  - lib/studio/log_rotation.rb
872
881
  - lib/studio/mail_sender.rb
873
882
  - lib/studio/mail_transport.rb
883
+ - lib/studio/marketing_kit.rb
874
884
  - lib/studio/name_parts.rb
875
885
  - lib/studio/navbar_account_sidebar.rb
876
886
  - lib/studio/navbar_brand.rb