lookbook 1.0.0.beta.2 → 1.0.0.beta.3

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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +180 -40
  3. data/app/components/lookbook/{component.rb → base_component.rb} +1 -1
  4. data/app/components/lookbook/button/component.rb +1 -1
  5. data/app/components/lookbook/button_group/component.rb +1 -1
  6. data/app/components/lookbook/code/component.rb +1 -1
  7. data/app/components/lookbook/copy_button/component.html.erb +1 -1
  8. data/app/components/lookbook/copy_button/component.rb +1 -1
  9. data/app/components/lookbook/dimensions_display/component.rb +1 -1
  10. data/app/components/lookbook/embed/component.html.erb +3 -2
  11. data/app/components/lookbook/embed/component.rb +1 -1
  12. data/app/components/lookbook/filter/component.html.erb +1 -1
  13. data/app/components/lookbook/filter/component.rb +1 -1
  14. data/app/components/lookbook/header/component.html.erb +5 -10
  15. data/app/components/lookbook/header/component.rb +1 -1
  16. data/app/components/lookbook/icon/component.rb +1 -1
  17. data/app/components/lookbook/nav/component.rb +1 -1
  18. data/app/components/lookbook/nav/item/component.html.erb +2 -2
  19. data/app/components/lookbook/nav/item/component.rb +1 -1
  20. data/app/components/lookbook/page_tabs/component.rb +1 -1
  21. data/app/components/lookbook/params_editor/component.rb +1 -1
  22. data/app/components/lookbook/params_editor/field/component.rb +1 -1
  23. data/app/components/lookbook/prose/component.rb +1 -1
  24. data/app/components/lookbook/split_layout/component.rb +1 -1
  25. data/app/components/lookbook/tab_panels/component.rb +1 -1
  26. data/app/components/lookbook/tab_panels/panel/component.rb +2 -2
  27. data/app/components/lookbook/tabs/component.js +6 -6
  28. data/app/components/lookbook/tabs/component.rb +1 -1
  29. data/app/components/lookbook/tabs/dropdown_tab/component.rb +1 -1
  30. data/app/components/lookbook/tabs/tab/component.rb +1 -1
  31. data/app/components/lookbook/toolbar/component.rb +1 -1
  32. data/app/components/lookbook/viewport/component.rb +1 -1
  33. data/app/controllers/lookbook/previews_controller.rb +24 -29
  34. data/app/helpers/lookbook/application_helper.rb +6 -0
  35. data/app/helpers/lookbook/component_helper.rb +4 -0
  36. data/app/helpers/lookbook/page_helper.rb +1 -1
  37. data/app/views/layouts/lookbook/application.html.erb +1 -1
  38. data/app/views/layouts/lookbook/shell.html.erb +1 -1
  39. data/app/views/layouts/lookbook/skeleton.html.erb +7 -1
  40. data/app/views/lookbook/404.html.erb +1 -1
  41. data/app/views/lookbook/index.html.erb +1 -1
  42. data/app/views/lookbook/pages/show.html.erb +2 -2
  43. data/app/views/lookbook/previews/panels/_notes.html.erb +1 -1
  44. data/app/views/lookbook/previews/show.html.erb +3 -3
  45. data/lib/lookbook/collection.rb +1 -1
  46. data/lib/lookbook/component.rb +31 -0
  47. data/lib/lookbook/config.rb +54 -9
  48. data/lib/lookbook/engine.rb +72 -12
  49. data/lib/lookbook/page.rb +2 -2
  50. data/lib/lookbook/parser.rb +1 -4
  51. data/lib/lookbook/preview.rb +24 -7
  52. data/lib/lookbook/preview_example.rb +1 -1
  53. data/lib/lookbook/source_inspector.rb +10 -0
  54. data/lib/lookbook/utils.rb +2 -2
  55. data/lib/lookbook/version.rb +1 -1
  56. data/lib/lookbook.rb +1 -12
  57. data/public/lookbook-assets/js/lookbook.js +105 -104
  58. data/public/lookbook-assets/js/lookbook.js.map +1 -1
  59. metadata +3 -2
@@ -117,41 +117,36 @@ module Lookbook
117
117
  def inspector_data
118
118
  return @inspector_data if @inspector_data.present?
119
119
 
120
- request_data = {
120
+ context_data = {
121
121
  preview_params: preview_params,
122
122
  path: params[:path],
123
- query_parameters: request.query_parameters,
124
- original: request
125
123
  }
126
124
 
127
- preview_data = {
128
- relative_path: @preview.full_path.relative_path_from(Rails.root.to_s),
129
- full_path: @preview.full_path,
130
- example_label: @example.label,
131
- params: @example.params,
132
- }
133
- [:id, :label, :notes, :lookup_path, :full_path].each do |prop|
134
- preview_data[prop] = @preview.public_send(prop)
135
- end
125
+ example = @example
126
+ preview = @preview
127
+ preview.define_singleton_method(:params, proc {
128
+ example.params
129
+ })
136
130
 
137
- examples_data = target_examples.map do |example|
131
+ examples = target_examples.map do |example|
138
132
  render_args = @preview.render_args(example.name, params: preview_controller.params)
139
133
  has_template = render_args[:template] != "view_components/preview"
140
- example_data = Lookbook::Store.new({
141
- output: preview_controller.process(:render_example_to_string, @preview, example.name),
142
- source: has_template ? example.template_source(render_args[:template]) : example.method_source,
143
- source_lang: has_template ? example.template_lang(render_args[:template]) : example.source_lang,
144
- })
145
- [:id, :label, :notes, :lookup_path, :params, :display_params].each do |prop|
146
- example_data[prop] = example.public_send(prop)
147
- end
148
- example_data
134
+ output = preview_controller.process(:render_example_to_string, @preview, example.name)
135
+ source = has_template ? example.template_source(render_args[:template]) : example.method_source
136
+ source_lang = has_template ? example.template_lang(render_args[:template]) : example.lang
137
+
138
+ example.define_singleton_method(:output, proc { output })
139
+ example.define_singleton_method(:source, proc { source })
140
+ example.define_singleton_method(:source_lang, proc { source_lang })
141
+ example
149
142
  end
150
143
 
151
144
  @inspector_data ||= Lookbook::Store.new({
152
- request: request_data,
153
- preview: preview_data,
154
- examples: examples_data
145
+ context: context_data,
146
+ preview: preview,
147
+ examples: examples,
148
+ components: preview.components,
149
+ app: Lookbook
155
150
  })
156
151
  end
157
152
 
@@ -163,7 +158,7 @@ module Lookbook
163
158
 
164
159
  callable_data = {
165
160
  name: name.to_s,
166
- index_position: (@panels.filter { |p| p.pane == config.pane }.size + 1),
161
+ index_position: (@panels.select { |p| p.pane == config.pane }.size + 1),
167
162
  **inspector_data
168
163
  }
169
164
 
@@ -175,15 +170,15 @@ module Lookbook
175
170
  @panels << Lookbook::Store.new(resolved_config, deep: false)
176
171
  end
177
172
 
178
- @panels.filter(&:show).sort_by { |p| [p.position, p.label] }
173
+ @panels = @panels.select(&:show).sort_by { |p| [p.position, p.label] }
179
174
  end
180
175
 
181
176
  def main_panels
182
- panels.filter { |panel| panel.pane == :main }
177
+ panels.select { |panel| panel.pane == :main }
183
178
  end
184
179
 
185
180
  def drawer_panels
186
- panels.filter { |panel| panel.pane == :drawer }
181
+ panels.select { |panel| panel.pane == :drawer }
187
182
  end
188
183
 
189
184
  def preview_controller
@@ -20,5 +20,11 @@ module Lookbook
20
20
  def generate_id(*args)
21
21
  args.map { |args| args.delete_prefix("/").tr("&?=/_\-", "-") }.join("-")
22
22
  end
23
+
24
+ def append_styles(&block)
25
+ content_for :styles do
26
+ capture(&block)
27
+ end
28
+ end
23
29
  end
24
30
  end
@@ -2,6 +2,10 @@ module Lookbook
2
2
  module ComponentHelper
3
3
  COMPONENT_CLASSES = {} # cache for constantized references
4
4
 
5
+ def icon(name, **attrs)
6
+ render Lookbook::Icon::Component.new(name: name, **attrs)
7
+ end
8
+
5
9
  def render_component(ref, **attrs, &block)
6
10
  klass = component_class(ref)
7
11
  comp = attrs.key?(:content) ? klass.new(**attrs.except(:content)).with_content(attrs[:content]) : klass.new(**attrs)
@@ -16,7 +16,7 @@ module Lookbook
16
16
 
17
17
  @embed_counter ||= 0
18
18
 
19
- preview_lookup = args.first.is_a?(Symbol) ? args.first : preview_class_name(args.first)
19
+ preview_lookup = args.first.is_a?(Symbol) ? args.first : preview_class_path(args.first)
20
20
  preview = Lookbook.previews.find(preview_lookup)
21
21
  example = args[1] ? preview&.example(args[1]) : preview&.default_example
22
22
 
@@ -40,7 +40,7 @@
40
40
  <div x-data="{hidden: false}" class="flex-none border-t border-lookbook-divider absolute bottom-0 left-0 right-0" x-show="!hidden">
41
41
  <%= render_component :toolbar do |toolbar| %>
42
42
  <% toolbar.section padded: true, class: "flex items-center" do %>
43
- <%= render_component :icon, name: :alert_triangle, size: 4, class: "text-red-700" %>
43
+ <%= icon :alert_triangle, size: 4, class: "text-red-700" %>
44
44
  <span class="ml-2">Preview load errors</span>
45
45
  <% end %>
46
46
  <% toolbar.section align: :right do %>
@@ -28,7 +28,7 @@
28
28
  <span class="opacity-60 mr-1">Lookbook</span>
29
29
  <span class="mr-6">v<%= Lookbook::VERSION %></span>
30
30
  <a href="https://github.com/allmarkedup/lookbook" target="_blank" class="ml-auto opacity-70">
31
- <%= render_component :icon, name: :github, size: 3 %>
31
+ <%= icon :github, size: 3 %>
32
32
  </a>
33
33
  </div>
34
34
  <div class="px-3 py-2">
@@ -8,11 +8,17 @@
8
8
  <link href="/lookbook-assets/css/lookbook.css?v=<%= Lookbook::VERSION %>" rel="stylesheet">
9
9
  <link href="/lookbook-assets/css/themes/<%= config.ui_theme %>.css?v=<%= Lookbook::VERSION %>" rel="stylesheet">
10
10
  <% if @theme_overrides.present? %>
11
- <style>
11
+ <style media="all">
12
12
  <%== @theme_overrides %>
13
13
  </style>
14
14
  <% end %>
15
15
 
16
+ <% if content_for? :styles %>
17
+ <style media="all">
18
+ <%= content_for :styles %>
19
+ </style>
20
+ <% end %>
21
+
16
22
  <% if config.ui_favicon != false %>
17
23
  <link rel="icon" href="<%= config.ui_favicon || "data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>👀</text></svg>" %>">
18
24
  <% end %>
@@ -1,6 +1,6 @@
1
1
  <div class="bg-white flex flex-col items-center justify-center h-screen w-full">
2
2
  <div class="px-4 text-center max-w-sm">
3
- <%= render_component :icon, name: :alert_triangle, size: 10, class: "text-red-300 mx-auto" %>
3
+ <%= icon :alert_triangle, size: 10, class: "text-red-300 mx-auto" %>
4
4
  <div class="mt-3">
5
5
  <h5 class="text-base">
6
6
  <%== message %>
@@ -1,7 +1,7 @@
1
1
  <div id="welcome-message" class="flex flex-col h-full w-full">
2
2
  <div class="flex flex-col items-center justify-center h-full">
3
3
  <div class="p-4 text-center mx-auto">
4
- <%= render_component :icon, name: :layers, size: 10, class: "opacity-30 mx-auto" %>
4
+ <%= icon :layers, size: 10, class: "opacity-30 mx-auto" %>
5
5
  <div class="mt-6 text-base opacity-40">
6
6
  <% if Lookbook.previews.any? %>
7
7
  <h5>Select a preview to get started</h5>
@@ -25,7 +25,7 @@
25
25
  <% if @previous_page %>
26
26
  <a href="<%= lookbook_page_path @previous_page.lookup_path %>"
27
27
  class="flex items-center flex-none">
28
- <%= render_component :icon, name: :arrow_left, size: 4, class: "hover:text-indigo-800" %>
28
+ <%= icon :arrow_left, size: 4, class: "hover:text-indigo-800" %>
29
29
  <span class="ml-2 underline"><%= @previous_page.title %></span>
30
30
  </a>
31
31
  <% end %>
@@ -34,7 +34,7 @@
34
34
  <a href="<%= lookbook_page_path @next_page.lookup_path %>"
35
35
  class="flex items-center flex-none ml-auto">
36
36
  <span class="mr-2 underline"><%= @next_page.title %></span>
37
- <%= render_component :icon, name: :arrow_right, size: 4, class: "hover:text-indigo-800" %>
37
+ <%= icon :arrow_right, size: 4, class: "hover:text-indigo-800" %>
38
38
  </a>
39
39
  <% end %>
40
40
  </footer>
@@ -1,4 +1,4 @@
1
- <% items = examples.filter { |example| example.notes.present? } %>
1
+ <% items = examples.select { |example| example.notes.present? } %>
2
2
  <% if items.many? %>
3
3
  <div class="divide-y divide-dashed divide-lookbook-divider bg-lookbook-prose h-full w-full">
4
4
  <% items.each do |item| %>
@@ -55,7 +55,7 @@
55
55
  <div class="h-full relative overflow-auto">
56
56
  <%= render_component :tab_panels, alpine_data: "$store.inspector.main" do |tabs| %>
57
57
  <% @main_panels.each do |panel| %>
58
- <% tabs.panel name: panel.name, class: panel.panel_classes do %>
58
+ <% tabs.panel id: panel.id, name: panel.name, class: [panel.panel_classes, { "p-4": panel.padded, "prose": panel.prose }] do %>
59
59
  <%= render panel.partial, **@inspector_data, panel: panel, **panel.locals %>
60
60
  <% end %>
61
61
  <% end %>
@@ -80,7 +80,7 @@
80
80
 
81
81
  <% toolbar.section align: :right, class: "flex-none relative z-10" do %>
82
82
  <%= render_component :button_group do |group| %>
83
- <%= @drawer_panels.filter { |p| !p.disabled && p.copy }.each do |panel| %>
83
+ <%= @drawer_panels.select { |p| !p.disabled && p.copy }.each do |panel| %>
84
84
  <% group.button icon: :copy,
85
85
  tooltip: "Copy panel contents",
86
86
  copy: !!panel.copy,
@@ -123,7 +123,7 @@
123
123
  <div class="h-full overflow-auto">
124
124
  <%= render_component :tab_panels, alpine_data: "$store.inspector.drawer" do |tabs| %>
125
125
  <% @drawer_panels.each do |panel| %>
126
- <% tabs.panel name: panel.name do %>
126
+ <% tabs.panel id: panel.id, name: panel.name, class: [panel.panel_classes, { "p-4": panel.padded, "prose": panel.prose }] do %>
127
127
  <%= render panel.partial, **@inspector_data, panel: panel, **panel.locals %>
128
128
  <% end %>
129
129
  <% end %>
@@ -42,7 +42,7 @@ module Lookbook
42
42
  end
43
43
 
44
44
  def non_empty_items
45
- items.filter do |item|
45
+ items.select do |item|
46
46
  !item.is_a?(Lookbook::Collection) || item.items.any?
47
47
  end
48
48
  end
@@ -0,0 +1,31 @@
1
+ module Lookbook
2
+ class Component < Entity
3
+
4
+ attr_accessor :name
5
+
6
+ def initialize(name)
7
+ @name = name
8
+ super(path)
9
+ end
10
+
11
+ def path
12
+ name.underscore
13
+ end
14
+
15
+ def full_path
16
+ Pathname.new("#{Lookbook.config.components_path}/#{path}.rb")
17
+ end
18
+
19
+ def dir_path
20
+ full_path.dirname
21
+ end
22
+
23
+ def template_path
24
+ Dir.glob("#{Lookbook.config.components_path}/#{path}.*.erb").first
25
+ end
26
+
27
+ def inline?
28
+ template_path.present?
29
+ end
30
+ end
31
+ end
@@ -11,6 +11,8 @@ module Lookbook
11
11
  project_name: "Lookbook",
12
12
  log_level: 2,
13
13
  auto_refresh: true,
14
+
15
+ components_path: "app/components",
14
16
 
15
17
  page_controller: "Lookbook::PageController",
16
18
  page_route: "pages",
@@ -37,13 +39,22 @@ module Lookbook
37
39
  ui_theme: "indigo",
38
40
  ui_theme_overrides: {},
39
41
 
42
+ hooks: {
43
+ after_initialize: [],
44
+ before_exit: [],
45
+ after_change: [],
46
+ },
47
+
48
+ experimental_features: false,
49
+
40
50
  inspector_panels: {
41
51
  preview: {
42
52
  pane: :main,
43
53
  position: 1,
44
54
  partial: "lookbook/previews/panels/preview",
45
55
  hotkey: "v",
46
- panel_classes: "overflow-hidden"
56
+ panel_classes: "overflow-hidden",
57
+ padded: false
47
58
  },
48
59
  output: {
49
60
  pane: :main,
@@ -51,6 +62,7 @@ module Lookbook
51
62
  partial: "lookbook/previews/panels/output",
52
63
  label: "HTML",
53
64
  hotkey: "h",
65
+ padded: false
54
66
  },
55
67
  source: {
56
68
  pane: :drawer,
@@ -58,7 +70,8 @@ module Lookbook
58
70
  partial: "lookbook/previews/panels/source",
59
71
  label: "Source",
60
72
  hotkey: "s",
61
- copy: ->(data) { data.examples.map { |e| e[:source] }.join("\n") }
73
+ copy: ->(data) { data.examples.map { |e| e.source }.join("\n") },
74
+ padded: false
62
75
  },
63
76
  notes: {
64
77
  pane: :drawer,
@@ -66,7 +79,8 @@ module Lookbook
66
79
  partial: "lookbook/previews/panels/notes",
67
80
  label: "Notes",
68
81
  hotkey: "n",
69
- disabled: ->(data) { data.examples.filter { |e| e.notes.present? }.none? }
82
+ disabled: ->(data) { data.examples.select { |e| e.notes.present? }.none? },
83
+ padded: false
70
84
  },
71
85
  params: {
72
86
  pane: :drawer,
@@ -74,7 +88,8 @@ module Lookbook
74
88
  partial: "lookbook/previews/panels/params",
75
89
  label: "Params",
76
90
  hotkey: "p",
77
- disabled: ->(data) { data.preview.params.none? }
91
+ disabled: ->(data) { data.preview.params.none? },
92
+ padded: false
78
93
  }
79
94
  },
80
95
 
@@ -90,10 +105,9 @@ module Lookbook
90
105
  show: true,
91
106
  copy: nil,
92
107
  panel_classes: nil,
93
- locals: {}
108
+ locals: {},
109
+ padded: true
94
110
  },
95
-
96
- experimental_features: false,
97
111
  })
98
112
  end
99
113
 
@@ -105,6 +119,33 @@ module Lookbook
105
119
  end
106
120
  end
107
121
 
122
+ def define_inspector_panel(name, opts = {})
123
+ inspector_panels[name] = opts
124
+ if opts[:position].present?
125
+ pane = inspector_panels[name].pane.presence || :drawer
126
+ siblings = inspector_panels.select do |key, panel|
127
+ panel.pane == pane && key != name.to_sym
128
+ end
129
+ siblings.each do |key, panel|
130
+ if panel.position >= opts[:position]
131
+ panel.position += 1
132
+ end
133
+ end
134
+ end
135
+ end
136
+
137
+ def amend_inspector_panel(name, opts = {})
138
+ if opts == false
139
+ inspector_panels[name] = false
140
+ else
141
+ inspector_panels[name].merge!(opts)
142
+ end
143
+ end
144
+
145
+ def remove_inspector_panel(name)
146
+ amend_inspector_panel(name, false)
147
+ end
148
+
108
149
  def ui_theme=(name)
109
150
  name = name.to_s
110
151
  if Theme.valid_theme?(name)
@@ -141,7 +182,7 @@ module Lookbook
141
182
  protected
142
183
 
143
184
  def get_inspector_panels(panels)
144
- panels.filter! { |key, panel| panel }
185
+ panels.select! { |key, panel| panel }
145
186
  panels
146
187
  end
147
188
 
@@ -149,9 +190,13 @@ module Lookbook
149
190
  name == false ? nil : name
150
191
  end
151
192
 
193
+ def get_components_path(path)
194
+ absolute_path(path)
195
+ end
196
+
152
197
  def normalize_paths(paths)
153
198
  paths.map! { |path| absolute_path(path) }
154
- paths.filter! { |path| Dir.exist?(path) }
199
+ paths.select! { |path| Dir.exist?(path) }
155
200
  paths
156
201
  end
157
202
 
@@ -8,16 +8,20 @@ module Lookbook
8
8
  autoload :Config, "lookbook/config"
9
9
 
10
10
  class << self
11
+ def version
12
+ Lookbook::VERSION
13
+ end
14
+
11
15
  def config
12
16
  @config ||= Config.new
13
17
  end
14
18
 
15
- def logger
16
- @logger ||= Rails.env.development? ? Logger.new($stdout) : Rails.logger
19
+ def configure
20
+ yield(config)
17
21
  end
18
22
 
19
- def version
20
- Lookbook::VERSION
23
+ def logger
24
+ @logger ||= Rails.env.development? ? Logger.new($stdout) : Rails.logger
21
25
  end
22
26
 
23
27
  def debug_data
@@ -28,8 +32,46 @@ module Lookbook
28
32
  }
29
33
  end
30
34
 
31
- def configure
32
- yield(config)
35
+ def previews
36
+ Preview.all
37
+ end
38
+
39
+ def pages
40
+ Page.all
41
+ end
42
+
43
+ def after_initialize(&block)
44
+ add_hook(:after_initialize, block)
45
+ end
46
+
47
+ def before_exit(&block)
48
+ add_hook(:before_exit, block)
49
+ end
50
+
51
+ def after_change(&block)
52
+ add_hook(:after_change, block)
53
+ end
54
+
55
+ def define_panel(name, opts = {})
56
+ config.define_inspector_panel(name, opts)
57
+ end
58
+
59
+ def amend_panel(name, opts = {})
60
+ config.amend_inspector_panel(name, opts)
61
+ end
62
+
63
+ def remove_panel(name)
64
+ config.remove_inspector_panel(name)
65
+ end
66
+
67
+ def broadcast(event_name, data = {})
68
+ Engine.websocket&.broadcast(event_name.to_s, data)
69
+ end
70
+
71
+ protected
72
+
73
+ def add_hook(event_name, block)
74
+ config.hooks[event_name] << block
33
75
  end
34
76
  end
35
77
 
@@ -43,8 +85,10 @@ module Lookbook
43
85
  config.lookbook.preview_paths += config.view_component.preview_paths
44
86
  config.lookbook.preview_controller ||= config.view_component.preview_controller
45
87
 
88
+ config.lookbook.components_path = config.view_component.view_component_path if config.view_component.view_component_path.present?
89
+
46
90
  config.lookbook.listen_paths += config.lookbook.preview_paths
47
- config.lookbook.listen_paths << (config.view_component.view_component_path.presence || "app/components")
91
+ config.lookbook.listen_paths << config.lookbook.components_path
48
92
  end
49
93
 
50
94
  initializer "lookbook.logging.development" do
@@ -73,12 +117,14 @@ module Lookbook
73
117
  only: /\.(rb|html.*)$/,
74
118
  force_polling: Lookbook.config.listen_use_polling
75
119
  ) do |modified, added, removed|
120
+ changes = { modified: modified, added: added, removed: removed }
76
121
  begin
77
122
  parser.parse
78
123
  rescue
79
124
  end
80
125
  Lookbook::Preview.clear_cache
81
- Lookbook::Engine.websocket&.broadcast("reload", {})
126
+ Lookbook::Engine.reload_ui(changes)
127
+ Lookbook::Engine.run_hooks(:after_change, changes)
82
128
  end
83
129
  Lookbook::Engine.register_listener(preview_listener)
84
130
 
@@ -87,7 +133,9 @@ module Lookbook
87
133
  only: /\.(html.*|md.*)$/,
88
134
  force_polling: Lookbook.config.listen_use_polling
89
135
  ) do |modified, added, removed|
90
- Lookbook::Engine.websocket&.broadcast("reload", {})
136
+ changes = { modified: modified, added: added, removed: removed }
137
+ Lookbook::Engine.reload_ui(changes)
138
+ Lookbook::Engine.run_hooks(:after_change, changes)
91
139
  end
92
140
  Lookbook::Engine.register_listener(page_listener)
93
141
  end
@@ -103,18 +151,20 @@ module Lookbook
103
151
  "
104
152
  end
105
153
  end
154
+
155
+ Lookbook::Engine.run_hooks(:after_initialize)
106
156
  end
107
157
 
108
158
  at_exit do
109
159
  if config.lookbook.listen
110
160
  Lookbook.logger.debug "Stopping listeners"
111
- Lookbook::Engine.listeners.each do |listener|
112
- listener.stop
113
- end
161
+ Lookbook::Engine.listeners.each { |listener| listener.stop }
114
162
  end
163
+ Lookbook::Engine.run_hooks(:before_exit)
115
164
  end
116
165
 
117
166
  class << self
167
+
118
168
  def websocket
119
169
  if config.lookbook.auto_refresh
120
170
  cable = ActionCable::Server::Configuration.new
@@ -162,6 +212,16 @@ module Lookbook
162
212
  @listeners ||= []
163
213
  end
164
214
 
215
+ def run_hooks(event_name, *args)
216
+ Lookbook.config.hooks[event_name].each do |hook|
217
+ hook.call(Lookbook, *args)
218
+ end
219
+ end
220
+
221
+ def reload_ui(changed = {})
222
+ websocket&.broadcast("reload", changed)
223
+ end
224
+
165
225
  attr_reader :preview_controller
166
226
  end
167
227
  end
data/lib/lookbook/page.rb CHANGED
@@ -19,7 +19,7 @@ module Lookbook
19
19
 
20
20
  def initialize(path, base_path)
21
21
  @pathname = Pathname.new path
22
- @base_path = base_path
22
+ @base_path = Pathname.new base_path
23
23
  @options = nil
24
24
  @errors = []
25
25
  @sections = []
@@ -177,7 +177,7 @@ module Lookbook
177
177
  end
178
178
 
179
179
  def page_paths
180
- Lookbook.config.page_paths.filter { |dir| Dir.exist? dir }
180
+ Lookbook.config.page_paths.select { |dir| Dir.exist? dir }
181
181
  end
182
182
 
183
183
  def section_path?(path)
@@ -23,10 +23,6 @@ module Lookbook
23
23
  registry.get(path)
24
24
  end
25
25
 
26
- # def yardoc_file_path
27
- # Rails&.root ? Rails.root.join(YARDOC_FILE_PATH) : YARDOC_FILE_PATH
28
- # end
29
-
30
26
  class << self
31
27
  def define_tags
32
28
  YARD::Tags::Library.define_tag("Hidden status", :hidden)
@@ -34,6 +30,7 @@ module Lookbook
34
30
  YARD::Tags::Library.define_tag("Display", :display)
35
31
  YARD::Tags::Library.define_tag("Position", :position)
36
32
  YARD::Tags::Library.define_tag("ID", :id)
33
+ YARD::Tags::Library.define_tag("Component", :component)
37
34
  end
38
35
  end
39
36
  end
@@ -8,7 +8,7 @@ module Lookbook
8
8
  def initialize(preview)
9
9
  @preview = preview
10
10
  @preview_inspector = SourceInspector.new(@preview.name)
11
- super(preview_class_name(preview_class_basename(@preview.name)))
11
+ super(preview_class_path(@preview.name))
12
12
  end
13
13
 
14
14
  def id
@@ -34,7 +34,7 @@ module Lookbook
34
34
  def examples
35
35
  return @examples if @examples.present?
36
36
  public_methods = @preview.public_instance_methods(false)
37
- public_method_objects = @preview_inspector&.methods&.filter { |m| public_methods.include?(m.name) }
37
+ public_method_objects = @preview_inspector&.methods&.select { |m| public_methods.include?(m.name) }
38
38
  examples = (public_method_objects || []).map { |m| PreviewExample.new(m.name.to_s, self) }
39
39
  sorted = Lookbook.config.sort_examples ? examples.sort_by(&:label) : examples
40
40
  @examples = []
@@ -62,7 +62,7 @@ module Lookbook
62
62
  end
63
63
 
64
64
  def full_path
65
- base_path = Array(preview_paths).detect do |preview_path|
65
+ base_path = Array(Lookbook.config.preview_paths).detect do |preview_path|
66
66
  Dir["#{preview_path}/#{name.underscore}.rb"].first
67
67
  end
68
68
  Pathname.new(Dir["#{base_path}/#{name.underscore}.rb"].first)
@@ -72,10 +72,6 @@ module Lookbook
72
72
  lookbook_inspect_path lookup_path
73
73
  end
74
74
 
75
- def preview_paths
76
- ViewComponent::Base.preview_paths
77
- end
78
-
79
75
  def parent_collections_names
80
76
  File.dirname(path).split("/")
81
77
  end
@@ -96,6 +92,27 @@ module Lookbook
96
92
  true
97
93
  end
98
94
 
95
+ def component
96
+ components.first
97
+ end
98
+
99
+ def components
100
+ component_classes = @preview_inspector&.components.any? ? @preview_inspector&.components : [guess_component]
101
+ component_classes.map do |class_name|
102
+ Component.new(class_name.to_s)
103
+ end
104
+ end
105
+
106
+ protected
107
+
108
+ def guess_component
109
+ begin
110
+ name.chomp("Preview").constantize
111
+ rescue
112
+ nil
113
+ end
114
+ end
115
+
99
116
  class << self
100
117
  def find(path)
101
118
  all.find { |p| p.lookup_path == path }