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

Sign up to get free protection for your applications and to get access to all the features.
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 }