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

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 (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)