lookbook 2.0.0.beta.3 → 2.0.0.beta.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/lookbook/css/lookbook.css +6 -0
  3. data/app/assets/lookbook/css/themes/blue.css +4 -1
  4. data/app/assets/lookbook/css/themes/green.css +4 -1
  5. data/app/assets/lookbook/css/themes/indigo.css +4 -1
  6. data/app/assets/lookbook/css/themes/rose.css +4 -1
  7. data/app/assets/lookbook/css/themes/zinc.css +4 -1
  8. data/app/assets/lookbook/img/lucide-sprite.svg +869 -869
  9. data/app/components/lookbook/code/highlight_github.css +16 -17
  10. data/app/components/lookbook/dimensions_display/component.js +4 -7
  11. data/app/components/lookbook/file_source/component.html.erb +9 -0
  12. data/app/components/lookbook/file_source/component.rb +73 -0
  13. data/app/components/lookbook/header/component.html.erb +11 -8
  14. data/app/components/lookbook/icon/component.css +1 -1
  15. data/app/components/lookbook/icon/component.html.erb +1 -1
  16. data/app/components/lookbook/icon/component.rb +4 -1
  17. data/app/components/lookbook/logo/component.html.erb +6 -0
  18. data/app/components/lookbook/logo/component.rb +15 -0
  19. data/app/components/lookbook/message/component.css +33 -0
  20. data/app/components/lookbook/message/component.html.erb +26 -0
  21. data/app/components/lookbook/message/component.rb +13 -0
  22. data/app/components/lookbook/nav/entity/component.html.erb +1 -1
  23. data/app/components/lookbook/nav/entity/component.rb +1 -1
  24. data/app/components/lookbook/params/field/component.css +3 -3
  25. data/app/components/lookbook/prose/component.css +8 -1
  26. data/app/components/lookbook/prose/component.html.erb +6 -1
  27. data/app/components/lookbook/prose/component.rb +2 -2
  28. data/app/controllers/concerns/lookbook/targetable_concern.rb +2 -16
  29. data/app/controllers/lookbook/application_controller.rb +38 -14
  30. data/app/controllers/lookbook/embeds_controller.rb +3 -4
  31. data/app/controllers/lookbook/inspector_controller.rb +4 -12
  32. data/app/controllers/lookbook/pages_controller.rb +15 -27
  33. data/app/controllers/lookbook/preview_controller.rb +30 -2
  34. data/app/controllers/lookbook/previews_controller.rb +13 -15
  35. data/app/views/layouts/lookbook/application.html.erb +1 -0
  36. data/app/views/layouts/lookbook/skeleton.html.erb +2 -2
  37. data/app/views/lookbook/errors/default.html.erb +40 -0
  38. data/app/views/lookbook/errors/not_found.html.erb +10 -0
  39. data/app/views/lookbook/index.html.erb +29 -24
  40. data/app/views/lookbook/pages/show.html.erb +6 -5
  41. data/app/views/lookbook/partials/_blank_slate.html.erb +7 -0
  42. data/config/app.yml +8 -0
  43. data/config/routes.rb +2 -0
  44. data/lib/lookbook/engine.rb +6 -3
  45. data/lib/lookbook/entities/concerns/annotatable_entity.rb +26 -1
  46. data/lib/lookbook/entities/concerns/inspectable_entity.rb +17 -2
  47. data/lib/lookbook/entities/concerns/locatable_entity.rb +51 -7
  48. data/lib/lookbook/entities/concerns/navigable_entity.rb +14 -1
  49. data/lib/lookbook/entities/entity.rb +34 -12
  50. data/lib/lookbook/entities/page_entity.rb +68 -10
  51. data/lib/lookbook/entities/page_section_entity.rb +4 -0
  52. data/lib/lookbook/entities/preview_entity.rb +107 -17
  53. data/lib/lookbook/entities/renderable_entity.rb +47 -9
  54. data/lib/lookbook/entities/rendered_scenario_entity.rb +17 -6
  55. data/lib/lookbook/entities/scenario_entity.rb +77 -16
  56. data/lib/lookbook/entities/scenario_group_entity.rb +82 -9
  57. data/lib/lookbook/helpers/page_helper.rb +26 -1
  58. data/lib/lookbook/helpers/ui_elements_helper.rb +0 -24
  59. data/lib/lookbook/param.rb +1 -1
  60. data/lib/lookbook/stores/config_store.rb +0 -12
  61. data/lib/lookbook/support/errors/config_error.rb +1 -1
  62. data/lib/lookbook/support/errors/error.rb +64 -0
  63. data/lib/lookbook/support/errors/parser_error.rb +1 -1
  64. data/lib/lookbook/support/errors/preview_template_error.rb +1 -1
  65. data/lib/lookbook/support/errors/routing_error.rb +7 -0
  66. data/lib/lookbook/support/errors/template_error.rb +7 -0
  67. data/lib/lookbook/version.rb +1 -1
  68. data/public/lookbook-assets/css/lookbook.css +374 -53
  69. data/public/lookbook-assets/css/lookbook.css.map +1 -1
  70. data/public/lookbook-assets/css/themes/blue.css +4 -1
  71. data/public/lookbook-assets/css/themes/blue.css.map +1 -1
  72. data/public/lookbook-assets/css/themes/green.css +4 -1
  73. data/public/lookbook-assets/css/themes/green.css.map +1 -1
  74. data/public/lookbook-assets/css/themes/indigo.css +4 -1
  75. data/public/lookbook-assets/css/themes/indigo.css.map +1 -1
  76. data/public/lookbook-assets/css/themes/rose.css +4 -1
  77. data/public/lookbook-assets/css/themes/rose.css.map +1 -1
  78. data/public/lookbook-assets/css/themes/zinc.css +4 -1
  79. data/public/lookbook-assets/css/themes/zinc.css.map +1 -1
  80. data/public/lookbook-assets/img/lucide-sprite.svg +869 -869
  81. data/public/lookbook-assets/js/index.js +125 -125
  82. data/public/lookbook-assets/js/index.js.map +1 -1
  83. metadata +15 -7
  84. data/app/views/layouts/lookbook/shell.html.erb +0 -25
  85. data/app/views/lookbook/404.html.erb +0 -15
  86. data/app/views/lookbook/error.html.erb +0 -46
  87. data/lib/lookbook/error.rb +0 -120
  88. data/lib/lookbook/support/errors/lookbook_error.rb +0 -21
@@ -1,6 +1,5 @@
1
1
  module Lookbook
2
2
  class PagesController < ApplicationController
3
- layout "lookbook/application"
4
3
  helper_method :page_controller
5
4
 
6
5
  def self.controller_path
@@ -9,40 +8,29 @@ module Lookbook
9
8
 
10
9
  def index
11
10
  landing = Engine.pages.find(&:landing?) || Engine.pages.first
12
- if landing.present?
13
- redirect_to lookbook_page_path(landing.path)
14
- else
15
- show_404
16
- end
11
+ raise_not_found("Page not found") unless landing.present?
12
+
13
+ redirect_to lookbook_page_path(landing.path)
17
14
  end
18
15
 
19
16
  def show
20
17
  @page = @pages.find_by_path(params[:path])
21
- if @page
22
- @next_page = @pages.next(@page)
23
- @previous_page = @pages.previous(@page)
24
- begin
25
- @page_content = page_controller.render_page(@page)
26
- @title = @page.title
27
- rescue => exception
28
- render_in_layout "lookbook/error",
29
- layout: "lookbook/application",
30
- error: Lookbook::Error.new(exception, file_path: @page.file_path, source_code: @page.content)
31
- end
32
- else
33
- show_404
34
- end
18
+ raise_not_found("Page not found") unless @page
19
+
20
+ @page_content = page_controller.render_page(@page)
21
+ @title = @page.title
22
+ @next_page = @pages.next(@page)
23
+ @previous_page = @pages.previous(@page)
24
+ rescue ActionView::Template::Error => err
25
+ raise Lookbook::TemplateError.new(
26
+ original: err,
27
+ file_path: @page.file_path,
28
+ source: @page.content
29
+ )
35
30
  end
36
31
 
37
32
  protected
38
33
 
39
- def show_404
40
- render "lookbook/404", locals: {
41
- message: "Page not found",
42
- description: "The page may have been removed or renamed."
43
- }
44
- end
45
-
46
34
  def page_controller
47
35
  controller_class = Lookbook.config.page_controller.constantize
48
36
  controller = controller_class.new
@@ -6,12 +6,40 @@ module Lookbook
6
6
 
7
7
  private
8
8
 
9
- [:determine_layout, :prepend_application_view_paths, :prepend_preview_examples_view_path].each do |method_name|
10
- define_method method_name, ViewComponentsController.instance_method(method_name)
9
+ def set_locale(&block)
10
+ I18n.with_locale(params[:locale] || I18n.default_locale, &block)
11
+ end
12
+
13
+ # Returns either {} or {layout: value} depending on configuration
14
+ def determine_layout(layout_override = nil, prepend_views: true)
15
+ return {} unless defined?(Rails.root)
16
+
17
+ layout_declaration = {}
18
+
19
+ if !layout_override.nil?
20
+ # Allow component-level override, even if false (thus no layout rendered)
21
+ layout_declaration[:layout] = layout_override
22
+ elsif default_preview_layout.present?
23
+ layout_declaration[:layout] = default_preview_layout
24
+ end
25
+
26
+ prepend_application_view_paths if layout_declaration[:layout].present? && prepend_views
27
+
28
+ layout_declaration
11
29
  end
12
30
 
13
31
  def default_preview_layout
14
32
  Lookbook.config.preview_layout
15
33
  end
34
+
35
+ def prepend_application_view_paths
36
+ prepend_view_path Rails.root.join("app/views") if defined?(Rails.root)
37
+ end
38
+
39
+ def prepend_preview_scenarios_view_path
40
+ prepend_view_path(Engine.preview_paths)
41
+ end
42
+
43
+ alias_method :prepend_preview_examples_view_path, :prepend_preview_scenarios_view_path
16
44
  end
17
45
  end
@@ -37,21 +37,15 @@ module Lookbook
37
37
  end
38
38
 
39
39
  def show
40
- if @target
41
- begin
42
- opts = {layout: @preview.layout}
43
- if embedded?
44
- opts[:append_html] = render_to_string("lookbook/partials/_iframe_content_scripts", layout: nil)
45
- end
46
- @preview_html = preview_controller.process(:render_in_layout_to_string, "lookbook/previews/group", inspector_data, **opts)
47
- rescue => exception
48
- render_in_layout "lookbook/error",
49
- layout: "lookbook/skeleton",
50
- error: prettify_error(exception)
51
- end
52
- else
53
- show_404
54
- end
40
+ raise_not_found("Preview not found") unless @target
41
+
42
+ @preview_html = preview_controller.process(
43
+ :render_in_layout_to_string,
44
+ "lookbook/previews/group",
45
+ inspector_data,
46
+ layout: @preview.layout,
47
+ append_html: (iframe_content_scripts if embedded?)
48
+ )
55
49
  end
56
50
 
57
51
  private
@@ -60,6 +54,10 @@ module Lookbook
60
54
  params[:lookbook_embed] == "true"
61
55
  end
62
56
 
57
+ def iframe_content_scripts
58
+ render_to_string("lookbook/partials/_iframe_content_scripts", layout: nil)
59
+ end
60
+
63
61
  def scenario_json(scenario)
64
62
  {
65
63
  name: scenario.name,
@@ -6,6 +6,7 @@
6
6
  @popstate.window="handleNavigation"
7
7
  @click.document="hijax"
8
8
  @navigation:start="closeMobileSidebar"
9
+ @dom:update-complete.window="Lookbook.initEmbeds()"
9
10
  class="w-screen h-screen grid grid-rows-[40px_1fr] relative">
10
11
 
11
12
  <%= render "lookbook/partials/user_styles" %>
@@ -17,11 +17,11 @@
17
17
  <% if @config.ui_favicon == true %>
18
18
  <link
19
19
  rel="icon"
20
- href="data:image/svg+xml,%3Csvg width='96' height='84' viewBox='0 0 96 84' xmlns='http://www.w3.org/2000/svg'%3E%3Cdefs%3E%3CclipPath id='a'%3E%3Cpath d='M96 0v84H0V0h96Z'/%3E%3C/clipPath%3E%3CclipPath id='b'%3E%3Cpath d='M71.897 0a1.5 1.5 0 0 1 1.31.769l22.605 40.5a1.5 1.5 0 0 1 0 1.462l-22.605 40.5a1.5 1.5 0 0 1-1.31.769H49.481a1 1 0 0 1-.873-1.487L70.812 42.73a1.5 1.5 0 0 0 0-1.462L48.608 1.487A1 1 0 0 1 49.481 0ZM24.655.564l22.72 40.705a1.5 1.5 0 0 1 0 1.462l-22.72 40.705a1 1 0 0 1-1.746 0L.19 42.73a1.5 1.5 0 0 1 0-1.462L22.91.564a1 1 0 0 1 1.746 0Z'/%3E%3C/clipPath%3E%3C/defs%3E%3Cg clip-path='url(%23a)'%3E%3Cg clip-path='url(%23b)'%3E%3Cpath fill='<%= url_encode @theme.favicon_dark_mode %>' d='M0 0h96v84H0V0z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E"
20
+ href="data:image/svg+xml,%3Csvg viewBox='0 0 167 204' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23FFF' fill-rule='nonzero'%3E%3Cpath d='M157 0c5.523 0 10 4.477 10 10v184c0 5.523-4.477 10-10 10H32.969C17 204 3.687 192.638.65 177.554A9.97 9.97 0 0 1 0 174c0-.512.011-1.017.033-1.516A33.115 33.115 0 0 1 0 171V33C0 14.778 14.758 0 32.969 0H157Zm-10 166H32.969c-8.292 0-12.22 2.22-12.871 6.606.79 6.424 6.253 11.394 12.87 11.394H147v-18Zm0-146H32.969c-7.056 0-12.8 5.65-12.965 12.689L20 33v114.762c3.932-1.167 8.3-1.762 12.969-1.762H147V20Z'/%3E%3Cpath d='M64.022 126c-4.107 0-7.304-1.143-9.591-3.428-2.287-2.285-3.431-5.48-3.431-9.583l.14-63.978c0-4.197 1.12-7.415 3.36-9.653C56.74 37.119 59.916 36 64.023 36c4.2 0 7.398 1.12 9.592 3.358 2.193 2.238 3.29 5.456 3.29 9.653l-.14 55.584h34.166c3.547 0 6.277.91 8.19 2.728 1.915 1.819 2.871 4.454 2.871 7.905 0 3.45-.956 6.109-2.87 7.974-1.914 1.865-4.644 2.798-8.191 2.798H64.022Z'/%3E%3C/g%3E%3C/svg%3E"
21
21
  media="(prefers-color-scheme: dark)">
22
22
  <link
23
23
  rel="icon"
24
- href="data:image/svg+xml,%3Csvg width='96' height='84' viewBox='0 0 96 84' xmlns='http://www.w3.org/2000/svg'%3E%3Cdefs%3E%3CclipPath id='a'%3E%3Cpath d='M96 0v84H0V0h96Z'/%3E%3C/clipPath%3E%3CclipPath id='b'%3E%3Cpath d='M71.897 0a1.5 1.5 0 0 1 1.31.769l22.605 40.5a1.5 1.5 0 0 1 0 1.462l-22.605 40.5a1.5 1.5 0 0 1-1.31.769H49.481a1 1 0 0 1-.873-1.487L70.812 42.73a1.5 1.5 0 0 0 0-1.462L48.608 1.487A1 1 0 0 1 49.481 0ZM24.655.564l22.72 40.705a1.5 1.5 0 0 1 0 1.462l-22.72 40.705a1 1 0 0 1-1.746 0L.19 42.73a1.5 1.5 0 0 1 0-1.462L22.91.564a1 1 0 0 1 1.746 0Z'/%3E%3C/clipPath%3E%3C/defs%3E%3Cg clip-path='url(%23a)'%3E%3Cg clip-path='url(%23b)'%3E%3Cpath fill='<%= url_encode @theme.favicon_light_mode %>' d='M0 0h96v84H0V0z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E"
24
+ href="data:image/svg+xml,%3Csvg viewBox='0 0 167 204' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%233730A3' fill-rule='nonzero'%3E%3Cpath d='M157 0c5.523 0 10 4.477 10 10v184c0 5.523-4.477 10-10 10H32.969C17 204 3.687 192.638.65 177.554A9.97 9.97 0 0 1 0 174c0-.512.011-1.017.033-1.516A33.115 33.115 0 0 1 0 171V33C0 14.778 14.758 0 32.969 0H157Zm-10 166H32.969c-8.292 0-12.22 2.22-12.871 6.606.79 6.424 6.253 11.394 12.87 11.394H147v-18Zm0-146H32.969c-7.056 0-12.8 5.65-12.965 12.689L20 33v114.762c3.932-1.167 8.3-1.762 12.969-1.762H147V20Z'/%3E%3Cpath d='M64.022 126c-4.107 0-7.304-1.143-9.591-3.428-2.287-2.285-3.431-5.48-3.431-9.583l.14-63.978c0-4.197 1.12-7.415 3.36-9.653C56.74 37.119 59.916 36 64.023 36c4.2 0 7.398 1.12 9.592 3.358 2.193 2.238 3.29 5.456 3.29 9.653l-.14 55.584h34.166c3.547 0 6.277.91 8.19 2.728 1.915 1.819 2.871 4.454 2.871 7.905 0 3.45-.956 6.109-2.87 7.974-1.914 1.865-4.644 2.798-8.191 2.798H64.022Z'/%3E%3C/g%3E%3C/svg%3E"
25
25
  media="(prefers-color-scheme: light)">
26
26
  <% end %>
27
27
 
@@ -0,0 +1,40 @@
1
+ <div class="bg-red-50 h-[calc(100vh_-_40px)] w-full overflow-y-auto">
2
+ <div>
3
+ <header class="px-8 py-6">
4
+ <h2 class="text-xl font-bold text-red-700"><%= @error.type %></h2>
5
+ </header>
6
+
7
+ <div class="px-8 py-6 mb-8 border-t border-b border-red-200 bg-red-100 text-base leading-relaxed">
8
+ <pre class="whitespace-pre-wrap font-sans leading-tight text-red-900"><%= @error.message %></pre>
9
+ </div>
10
+
11
+ <% if @error.file_path %>
12
+ <div class="text-sm mx-8 mb-3 font-mono">
13
+ <span><%= @error.relative_file_path %></span>
14
+ <% if @error.line_number %>
15
+ <span>[line <strong><%= @error.line_number %></strong>]</span>
16
+ <% end %>
17
+ </div>
18
+
19
+ <div class="px-8">
20
+ <%= lookbook_render :file_source,
21
+ file_path: @error.file_path,
22
+ highlight_lines: [@error.line_number],
23
+ lines_around_highlight: 5,
24
+ source: @error.source,
25
+ class: "border border-red-200" %>
26
+ </div>
27
+ <% end %>
28
+
29
+ <h3 class="font-bold mb-2 px-8 py-2 mt-8">Full stack trace:</h3>
30
+ <div class="text-xs font-mono w-full overflow-auto">
31
+ <div class="px-8 pb-10 text-gray-400 leading-relaxed whitespace-nowrap">
32
+ <% @error.backtrace.each do |line| %>
33
+ <div class="hover:text-gray-900 transition-colors duration-100">
34
+ <%= line %>
35
+ </div>
36
+ <% end %>
37
+ </div>
38
+ </div>
39
+ </div>
40
+ </div>
@@ -0,0 +1,10 @@
1
+ <%= render "lookbook/partials/blank_slate" do %>
2
+ <%= lookbook_render :message,
3
+ id: "not-found-message",
4
+ title: @error.message,
5
+ icon: :file_x,
6
+ icon_position: :right,
7
+ theme: :error do %>
8
+ <%= @error.detail || "It may have been moved or deleted." %>
9
+ <% end %>
10
+ <% end %>
@@ -1,25 +1,30 @@
1
- <div id="landing" class="flex flex-col items-center justify-center h-full w-full">
2
- <div class="text-center" id="landing-<%= @previews.any? ? "with" : "no" %>-content">
3
- <% if @config.project_name.downcase == "lookbook" %>
4
- <div class="flex justify-center pb-4">
5
- <svg class="flex-none mx-auto w-[140px]" viewBox="0 0 275 36">
6
- <g fill-rule="nonzero" fill="none">
7
- <path d="M4.536 35c-1.408 0-2.504-.392-3.288-1.176-.784-.784-1.176-1.88-1.176-3.288V5.576c0-1.44.384-2.544 1.152-3.312.768-.768 1.856-1.152 3.264-1.152 1.44 0 2.536.384 3.288 1.152.752.768 1.128 1.872 1.128 3.312v22.08h11.712c1.216 0 2.152.312 2.808.936.656.624.984 1.528.984 2.712 0 1.184-.328 2.096-.984 2.736-.656.64-1.592.96-2.808.96H4.536ZM42.066.632c3.425 0 6.425.72 9 2.16 2.577 1.44 4.585 3.464 6.025 6.072 1.44 2.608 2.16 5.672 2.16 9.192 0 2.624-.408 5.008-1.224 7.152-.816 2.144-1.984 3.992-3.504 5.544-1.52 1.552-3.336 2.736-5.448 3.552-2.112.816-4.448 1.224-7.008 1.224-3.424 0-6.432-.728-9.024-2.184-2.592-1.456-4.6-3.496-6.024-6.12-1.424-2.624-2.136-5.68-2.136-9.168 0-2.624.408-5.008 1.224-7.152.816-2.144 1.984-3.984 3.504-5.52 1.52-1.536 3.336-2.712 5.448-3.528C37.17 1.04 39.507.632 42.067.632Zm0 7.392c-1.663 0-3.095.392-4.295 1.176-1.2.784-2.12 1.92-2.76 3.408-.64 1.488-.96 3.304-.96 5.448 0 3.168.704 5.64 2.112 7.416 1.408 1.776 3.376 2.664 5.904 2.664 1.696 0 3.136-.4 4.32-1.2 1.07-.723 1.917-1.733 2.543-3.031-.39-1.314-.934-2.855-2.087-5.286-.07-.147-.07-.233 0-.38l2.187-5.84a8.262 8.262 0 0 0-1.06-1.735c-1.407-1.76-3.375-2.64-5.903-2.64ZM80.27.632c3.424 0 6.424.72 9 2.16 2.576 1.44 4.584 3.464 6.024 6.072 1.44 2.608 2.16 5.672 2.16 9.192 0 2.624-.408 5.008-1.224 7.152-.816 2.144-1.984 3.992-3.504 5.544-1.52 1.552-3.336 2.736-5.448 3.552-2.112.816-4.448 1.224-7.008 1.224-3.424 0-6.432-.728-9.024-2.184-2.592-1.456-4.6-3.496-6.024-6.12-1.424-2.624-2.136-5.68-2.136-9.168 0-2.624.408-5.008 1.224-7.152.816-2.144 1.984-3.984 3.504-5.52 1.52-1.536 3.336-2.712 5.448-3.528C75.373 1.04 77.71.632 80.27.632Zm0 7.392c-1.664 0-3.096.392-4.296 1.176-1.2.784-2.12 1.92-2.76 3.408-.64 1.488-.96 3.304-.96 5.448 0 3.168.704 5.64 2.112 7.416 1.408 1.776 3.376 2.664 5.904 2.664 1.696 0 3.136-.4 4.32-1.2.999-.675 1.804-1.6 2.416-2.775-.395-1.37-.933-2.95-2.162-5.542-.07-.147-.07-.233 0-.38l2.276-6.08a8.166 8.166 0 0 0-.946-1.495c-1.408-1.76-3.376-2.64-5.904-2.64Zm26.299 27.408c-1.408 0-2.496-.392-3.264-1.176-.768-.784-1.152-1.88-1.152-3.288V5.192c0-1.472.384-2.584 1.152-3.336.768-.752 1.856-1.128 3.264-1.128 1.44 0 2.536.376 3.288 1.128.752.752 1.128 1.864 1.128 3.336v10.464h.096l11.664-12.864a7.705 7.705 0 0 1 1.944-1.512c.688-.368 1.464-.552 2.328-.552 1.344 0 2.312.344 2.904 1.032.592.688.864 1.488.816 2.4-.048.912-.424 1.752-1.128 2.52l-11.616 12.336v-3.6l12.192 13.776c.832.928 1.248 1.88 1.248 2.856s-.328 1.784-.984 2.424c-.656.64-1.624.96-2.904.96-1.088 0-1.96-.216-2.616-.648-.656-.432-1.368-1.08-2.136-1.944L111.08 19.736h-.096v11.232c0 1.408-.368 2.504-1.104 3.288-.736.784-1.84 1.176-3.312 1.176Z" fill="#919191"/>
8
- <path d="M140.403 35c-1.504 0-2.648-.392-3.432-1.176-.784-.784-1.176-1.912-1.176-3.384V5.72c0-1.472.392-2.6 1.176-3.384.784-.784 1.928-1.176 3.432-1.176h11.712c2.432 0 4.504.36 6.216 1.08 1.712.72 3.016 1.736 3.912 3.048.896 1.312 1.344 2.848 1.344 4.608 0 1.984-.568 3.68-1.704 5.088-1.136 1.408-2.68 2.368-4.632 2.88v-.768c2.304.416 4.088 1.344 5.352 2.784 1.264 1.44 1.896 3.28 1.896 5.52 0 2.976-1.064 5.32-3.192 7.032-2.128 1.712-5.032 2.568-8.712 2.568h-12.192Zm3.84-6.48h7.152c1.632 0 2.824-.312 3.576-.936.752-.624 1.128-1.56 1.128-2.808 0-1.248-.376-2.176-1.128-2.784-.752-.608-1.944-.912-3.576-.912h-7.152v7.44Zm0-13.92h6.288c1.6 0 2.776-.288 3.528-.864.752-.576 1.128-1.456 1.128-2.64 0-1.184-.376-2.056-1.128-2.616-.752-.56-1.928-.84-3.528-.84h-6.288v6.96Zm41.034 20.928c-3.424 0-6.432-.728-9.024-2.184-2.592-1.456-4.6-3.496-6.024-6.12-1.424-2.624-2.136-5.68-2.136-9.168 0-2.624.408-5.008 1.224-7.152.816-2.144 1.984-3.984 3.504-5.52 1.52-1.536 3.336-2.712 5.448-3.528 2.112-.816 4.448-1.224 7.008-1.224 3.424 0 6.424.72 9 2.16 2.576 1.44 4.584 3.464 6.024 6.072 1.44 2.608 2.16 5.672 2.16 9.192 0 2.624-.408 5.008-1.224 7.152-.816 2.144-1.984 3.992-3.504 5.544-1.52 1.552-3.336 2.736-5.448 3.552-2.112.816-4.448 1.224-7.008 1.224Zm0-7.392c1.696 0 3.136-.4 4.32-1.2 1.184-.8 2.096-1.952 2.736-3.456.64-1.504.96-3.312.96-5.424 0-3.168-.704-5.632-2.112-7.392-1.408-1.76-3.376-2.64-5.904-2.64-1.664 0-3.096.392-4.296 1.176-1.2.784-2.12 1.92-2.76 3.408-.64 1.488-.96 3.304-.96 5.448 0 3.168.704 5.64 2.112 7.416 1.408 1.776 3.376 2.664 5.904 2.664Zm38.203 7.392c-3.424 0-6.432-.728-9.024-2.184-2.592-1.456-4.6-3.496-6.024-6.12-1.424-2.624-2.136-5.68-2.136-9.168 0-2.624.408-5.008 1.224-7.152.816-2.144 1.984-3.984 3.504-5.52 1.52-1.536 3.336-2.712 5.448-3.528 2.112-.816 4.448-1.224 7.008-1.224 3.424 0 6.424.72 9 2.16 2.576 1.44 4.584 3.464 6.024 6.072 1.44 2.608 2.16 5.672 2.16 9.192 0 2.624-.408 5.008-1.224 7.152-.816 2.144-1.984 3.992-3.504 5.544-1.52 1.552-3.336 2.736-5.448 3.552-2.112.816-4.448 1.224-7.008 1.224Zm0-7.392c1.696 0 3.136-.4 4.32-1.2 1.184-.8 2.096-1.952 2.736-3.456.64-1.504.96-3.312.96-5.424 0-3.168-.704-5.632-2.112-7.392-1.408-1.76-3.376-2.64-5.904-2.64-1.664 0-3.096.392-4.296 1.176-1.2.784-2.12 1.92-2.76 3.408-.64 1.488-.96 3.304-.96 5.448 0 3.168.704 5.64 2.112 7.416 1.408 1.776 3.376 2.664 5.904 2.664Zm26.299 7.296c-1.408 0-2.496-.392-3.264-1.176-.768-.784-1.152-1.88-1.152-3.288V5.192c0-1.472.384-2.584 1.152-3.336.768-.752 1.856-1.128 3.264-1.128 1.44 0 2.536.376 3.288 1.128.752.752 1.128 1.864 1.128 3.336v10.464h.096l11.664-12.864a7.705 7.705 0 0 1 1.944-1.512c.688-.368 1.464-.552 2.328-.552 1.344 0 2.312.344 2.904 1.032.592.688.864 1.488.816 2.4-.048.912-.424 1.752-1.128 2.52l-11.616 12.336v-3.6l12.192 13.776c.832.928 1.248 1.88 1.248 2.856s-.328 1.784-.984 2.424c-.656.64-1.624.96-2.904.96-1.088 0-1.96-.216-2.616-.648-.656-.432-1.368-1.08-2.136-1.944L254.29 19.736h-.096v11.232c0 1.408-.368 2.504-1.104 3.288-.736.784-1.84 1.176-3.312 1.176Z" fill="#ABABAB"/>
9
- </g>
10
- </svg>
11
- </div>
12
- <% elsif @config.project_name != false %>
13
- <h5 class="text-base text-lookbook-blank-slate-title truncate uppercase font-black tracking-wide mb-2">
14
- <%= @config.project_name %>
15
- </h5>
1
+ <%= render "lookbook/partials/blank_slate" do %>
2
+ <% if @blank_slate %>
3
+ <%= lookbook_render :message,
4
+ id: "welcome-message",
5
+ title: "Welcome to your Lookbook!",
6
+ icon: :logo do %>
7
+ <p>
8
+ There isn't much to see yet, but
9
+ <%= link_to "component previews",
10
+ "#{@config.links.docs}/guide/previews",
11
+ target: "_blank"
12
+ %>
13
+ and
14
+ <%= link_to "content pages",
15
+ "#{@config.links.docs}/guide/pages",
16
+ target: "_blank"
17
+ %>
18
+ will show up here as soon as they are added.
19
+ </p>
20
+ <% end %>
21
+ <% else %>
22
+ <%= lookbook_render :message,
23
+ id: "get-started-message",
24
+ title: @config.project_name,
25
+ icon: :inspect,
26
+ icon_position: :right do %>
27
+ <p>Select a preview from the nav to get started.</p>
28
+ <% end %>
16
29
  <% end %>
17
- <div class="opacity-60">
18
- <% if @previews.any? %>
19
- <p>Select a preview from the nav to get started.</p>
20
- <% else %>
21
- <p><a class="underline" href="https://lookbook.build/guide/previews" target="_blank">Create a preview</a> to get started.</p>
22
- <% end %>
23
- </div>
24
- </div>
25
- </div>
30
+ <% end %>
@@ -1,8 +1,7 @@
1
1
  <main
2
2
  class="h-[calc(100vh_-_40px)]"
3
3
  x-data="{}"
4
- @navigation:complete.window="$refs.scroller.scrollTop = 0;"
5
- @dom:update-complete.window="Lookbook.initEmbeds();">
4
+ @navigation:complete.window="$refs.scroller.scrollTop = 0">
6
5
  <div class="h-full bg-lookbook-page-bg relative">
7
6
  <% unless @error %>
8
7
 
@@ -46,12 +45,14 @@
46
45
  <div class="px-4 md:px-10 pt-8 md:pt-10 overflow-auto scroll-smooth w-full max-h-full pb-12" x-ref="scroller">
47
46
  <div class="w-full max-w-screen-lg mx-auto h-full flex flex-col">
48
47
  <% if @page.header? %>
49
- <header id="page-header" class="mb-8 prose max-w-none flex-none">
50
- <h1><%= @page.title %></h1>
48
+ <header id="page-header" class="mb-7 pb-6 lg:mb-9 lg:pb-8 border-b border-lookbook-divider">
49
+ <%= lookbook_render :prose, size: :md, markdown: false, class: "max-w-none flex-none" do %>
50
+ <h1><%= @page.title %></h1>
51
+ <% end %>
51
52
  </header>
52
53
  <% end %>
53
54
 
54
- <%= lookbook_render :prose, id: "page-content", markdown: false, class: "max-w-none flex-none" do %>
55
+ <%= lookbook_render :prose, size: :md, id: "page-content", markdown: false, class: "max-w-none flex-none min-h-[50vh]" do %>
55
56
  <%= @page_content %>
56
57
  <% end %>
57
58
 
@@ -0,0 +1,7 @@
1
+ <div class="flex justify-center w-full h-full bg-checked">
2
+ <div class="px-4 py-6 xs:py-8 sm:p-8 md:p-12">
3
+ <div class="w-full xs:w-auto xs:mx-auto xs:min-w-[440px] xs:max-w-[680px]">
4
+ <%= yield %>
5
+ </div>
6
+ </div>
7
+ </div>
data/config/app.yml CHANGED
@@ -42,6 +42,7 @@ shared:
42
42
  component_paths: [app/views]
43
43
 
44
44
  reload_on_change: ~
45
+ live_updates: false
45
46
  listen_paths: []
46
47
  listen_extensions: [rb, html.*]
47
48
 
@@ -55,8 +56,15 @@ shared:
55
56
  debug_menu: false
56
57
  experimental_features: false
57
58
 
59
+ links:
60
+ docs: https://v2.lookbook.build
61
+ demo: https://v2-demo.lookbook.build
62
+ repo: https://github.com/ViewComponent/lookbook/tree/v2
63
+
58
64
  development:
59
65
  debug_menu: true
66
+ live_updates: true
60
67
 
61
68
  test:
62
69
  debug_menu: true
70
+ live_updates: false
data/config/routes.rb CHANGED
@@ -17,4 +17,6 @@ Lookbook::Engine.routes.draw do
17
17
  get "/embed", to: "embeds#lookup", as: :lookbook_embed_lookup
18
18
  get "/embed/*path", to: "embeds#show", as: :lookbook_embed
19
19
  end
20
+
21
+ get "/*path", to: "application#not_found", via: :all
20
22
  end
@@ -79,7 +79,10 @@ module Lookbook
79
79
  end
80
80
 
81
81
  def auto_refresh?
82
- reloading? && runtime_context.web? && FileWatcher.evented?
82
+ opts.live_updates == true &&
83
+ reloading? &&
84
+ runtime_context.web? &&
85
+ FileWatcher.evented?
83
86
  end
84
87
 
85
88
  def preview_embeds_allowed?
@@ -130,8 +133,8 @@ module Lookbook
130
133
 
131
134
  def view_paths
132
135
  # handle view path registry changes in Rails 7.1
133
- paths = if defined?(ActionView::ViewPaths::Registry)
134
- ActionView::ViewPaths::Registry.all_file_system_resolvers.map(&:path)
136
+ paths = if defined?(ActionView::PathRegistry)
137
+ ActionView::PathRegistry.all_file_system_resolvers.map(&:path)
135
138
  else
136
139
  ActionView::ViewPaths.all_view_paths.flat_map(&paths)
137
140
  end
@@ -1,23 +1,48 @@
1
1
  module Lookbook
2
- # @api private
3
2
  module AnnotatableEntity
4
3
  extend ActiveSupport::Concern
5
4
 
6
5
  included do
7
6
  delegate :has_tag?, to: :code_object
8
7
 
8
+ # @!group Annotations
9
+
10
+ # Any notes added to the entity.
11
+ # Returns the raw (unrendered) string which may contain markdown formatting.
12
+ #
13
+ # @return [String] The notes, or an empty string if none have been added
9
14
  def notes
10
15
  code_object.docstring.to_s.strip
11
16
  end
12
17
 
18
+ # All tags that have been added to the entity.
19
+ # Can be filtered by tag name by providing the name as an argument.
20
+ #
21
+ # @example :ruby
22
+ # all_tags = entity.tags
23
+ # display_tags = entity.tags(:display)
24
+ #
25
+ # @param name [Symbol] Optional tag type to filter by
26
+ # @return [Array<YardTag>] Array of tags
13
27
  def tags(name = nil)
14
28
  code_object.tags(name)
15
29
  end
16
30
 
31
+ # The first tag (optionally of a particular type)
32
+ # added to the entity.
33
+ #
34
+ # @example :ruby
35
+ # first_tag = entity.tag
36
+ # first_display_tag = entity.tag(:display)
37
+ #
38
+ # @param name [Symbol] Optional tag type to filter by
39
+ # @return [Array<YardTag>] Array of tags
17
40
  def tag(name = nil)
18
41
  tags(name).first
19
42
  end
20
43
 
44
+ # @!endgroup
45
+
21
46
  protected
22
47
 
23
48
  attr_reader :code_object
@@ -1,9 +1,13 @@
1
1
  module Lookbook
2
- # @api private
3
2
  module InspectableEntity
4
3
  extend ActiveSupport::Concern
5
4
 
6
5
  included do
6
+ # @!group Source
7
+
8
+ # Scenario method source code
9
+ #
10
+ # @return [String] The source code0
7
11
  def source
8
12
  source_code = if custom_source?
9
13
  File.read(source_file_path)
@@ -19,10 +23,21 @@ module Lookbook
19
23
  source_code.strip_heredoc.strip
20
24
  end
21
25
 
26
+ # Source code language info.
27
+ #
28
+ # Returns a Hash with `name`, `ext` & `label` entries.
29
+ #
30
+ # @example :ruby
31
+ # source_lang_name = entity.lang[:name]
32
+ #
33
+ # @return [Hash] Language info hash
22
34
  def source_lang
23
35
  custom_source? ? Lang.guess(source_file_path, :ruby) : Lang.find(:ruby)
24
36
  end
25
37
 
38
+ # @!endgroup
39
+
40
+ # @api private
26
41
  def custom_source?
27
42
  source_file_path.present?
28
43
  end
@@ -35,7 +50,7 @@ module Lookbook
35
50
  @_source_path ||= if code_object.has_tag?(:source)
36
51
  source_path = code_object.tag(:source).value
37
52
  unless source_path.present? && File.exist?(source_path)
38
- raise LookbookError, "Could not find source file '#{source_path}'"
53
+ raise Lookbook::Error, "Could not find source file '#{source_path}'"
39
54
  end
40
55
  source_path
41
56
  end
@@ -1,40 +1,77 @@
1
1
  module Lookbook
2
- # @api private
3
2
  module LocatableEntity
4
3
  extend ActiveSupport::Concern
5
4
 
6
5
  included do
7
- attr_reader :file_path, :base_directories
8
-
6
+ # @!group Paths
7
+
8
+ # Full path to the entity file
9
+ #
10
+ # @return [Pathname] File patj
11
+ attr_reader :file_path
12
+
13
+ # @api private
14
+ attr_reader :base_directories
15
+
16
+ # Name of the entity file.
17
+ #
18
+ # Includes file extension unless the `strip_ext` argument is `true`.
19
+ #
20
+ # @param strip_ext [Boolean] Whether or not to remove the file extension
21
+ # @return [String] File name
9
22
  def file_name(strip_ext = false)
10
23
  basename = file_pathname.basename
11
24
  (strip_ext ? basename.to_s.split(".").first : basename).to_s
12
25
  end
13
26
 
14
- def file_name_base
15
- @_file_name_slug ||= file_name(true).gsub(/(_component_preview|component_preview|preview)$/, "")
16
- end
17
-
27
+ # Extension of the entity file.
28
+ #
29
+ # @return [String] File extension
18
30
  def file_extension
19
31
  @_file_extension ||= file_pathname.extname
20
32
  end
21
33
 
34
+ # Full directory path for the entity file.
35
+ #
36
+ # @return [Pathname] Directory path
22
37
  def directory_path
23
38
  @_directory_path ||= Pathname(file_pathname.dirname)
24
39
  end
25
40
 
41
+ # Relative path to the entity file.
42
+ #
43
+ # Returned path is relative to the appropriate base directory
44
+ # (i.e. the preview directory for previews).
45
+ #
46
+ # @return [Pathname] Relative file path
26
47
  def relative_file_path
27
48
  @_relative_file_path ||= file_pathname.relative_path_from(base_directory)
28
49
  end
29
50
 
51
+ # Relative directory path for the entity file.
52
+ #
53
+ # Returned path is relative to the appropriate base directory
54
+ # (i.e. the preview directory for previews).
55
+ #
56
+ # @return [Pathname] Relative directory path
30
57
  def relative_directory_path
31
58
  @_relative_directory_path ||= directory_path.relative_path_from(base_directory)
32
59
  end
33
60
 
61
+ # Time that the entity file was last modified
62
+ #
63
+ # @return [Time] Time last modified
34
64
  def last_modified
35
65
  @_last_modified ||= File.mtime(file_path)
36
66
  end
37
67
 
68
+ # 'Virtual' path to the entity.
69
+ #
70
+ # Determines where the entity is located in heirarchical trees.
71
+ # Can be altered using the `@logical_path` tag.
72
+ #
73
+ # @api private
74
+ # @return [String] The logical path
38
75
  def logical_path
39
76
  return @_logical_path if @_logical_path
40
77
 
@@ -42,6 +79,13 @@ module Lookbook
42
79
  @_logical_path ||= PathUtils.to_path(directory, file_name_base)
43
80
  end
44
81
 
82
+ # @!endgroup
83
+
84
+ # @api private
85
+ def file_name_base
86
+ @_file_name_slug ||= file_name(true)
87
+ end
88
+
45
89
  alias_method :full_path, :file_path
46
90
  alias_method :rel_path, :relative_file_path
47
91
  alias_method :dir_path, :directory_path
@@ -1,17 +1,27 @@
1
1
  module Lookbook
2
- # @api private
3
2
  module NavigableEntity
4
3
  extend ActiveSupport::Concern
5
4
 
6
5
  included do
6
+ # @!group Visibility
7
+
8
+ # Whether or not the entity is hidden (i.e. hidden from navigation)
9
+ #
10
+ # @return [Boolean] true if hidden
7
11
  def hidden?
8
12
  fetch_config(:hidden, false)
9
13
  end
10
14
 
15
+ # Whether or not the entity is visible (i.e. present in navigation)
16
+ #
17
+ # @return [Boolean] true if visible
11
18
  def visible?
12
19
  !hidden?
13
20
  end
14
21
 
22
+ # @!endgroup
23
+
24
+ # @api private
15
25
  def priority
16
26
  return @_priority if @_priority
17
27
 
@@ -24,14 +34,17 @@ module Lookbook
24
34
  @_priority ||= pos.to_i
25
35
  end
26
36
 
37
+ # @api private
27
38
  def depth
28
39
  lookup_path.split("/").size
29
40
  end
30
41
 
42
+ # @api private
31
43
  def default_priority
32
44
  @default_priority || 10000
33
45
  end
34
46
 
47
+ # @api private
35
48
  def <=>(other)
36
49
  if respond_to?(:sort_handler, true)
37
50
  sort_handler(other)