lookbook 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/lookbook/js/helpers/string.js +23 -1
  3. data/app/assets/lookbook/js/lookbook.js +0 -1
  4. data/app/components/lookbook/display_options/editor/component.html.erb +13 -0
  5. data/app/components/lookbook/display_options/editor/component.rb +7 -0
  6. data/app/components/lookbook/display_options/field/component.css +33 -0
  7. data/app/components/lookbook/display_options/field/component.html.erb +8 -0
  8. data/app/components/lookbook/display_options/field/component.js +30 -0
  9. data/app/components/lookbook/display_options/field/component.rb +28 -0
  10. data/app/components/lookbook/inspector_panel/component.html.erb +1 -1
  11. data/app/components/lookbook/inspector_panel/component.rb +10 -11
  12. data/app/components/lookbook/params/editor/component.rb +6 -3
  13. data/app/components/lookbook/params/field/component.rb +1 -5
  14. data/app/components/lookbook/tab_panels/panel/component.html.erb +1 -1
  15. data/app/components/lookbook/tab_panels/panel/component.rb +1 -2
  16. data/app/components/lookbook/tabs/dropdown_tab/component.html.erb +1 -0
  17. data/app/components/lookbook/tabs/tab/component.html.erb +1 -0
  18. data/app/components/lookbook/viewport/component.html.erb +1 -1
  19. data/app/components/lookbook/viewport/component.rb +2 -1
  20. data/app/controllers/lookbook/previews_controller.rb +40 -29
  21. data/app/helpers/lookbook/preview_helper.rb +1 -1
  22. data/app/views/lookbook/preview.html.erb +1 -1
  23. data/app/views/lookbook/previews/panels/_params.html.erb +1 -1
  24. data/app/views/lookbook/previews/panels/_preview.html.erb +9 -6
  25. data/app/views/lookbook/previews/show.html.erb +29 -11
  26. data/config/app.yml +36 -0
  27. data/config/hooks.yml +4 -0
  28. data/config/inputs.yml +48 -0
  29. data/config/panels.yml +30 -0
  30. data/config/routes.rb +1 -1
  31. data/config/tags.yml +29 -0
  32. data/lib/lookbook/engine.rb +40 -87
  33. data/lib/lookbook/markdown.rb +1 -11
  34. data/lib/lookbook/page.rb +1 -1
  35. data/lib/lookbook/params.rb +0 -7
  36. data/lib/lookbook/parser.rb +3 -10
  37. data/lib/lookbook/preview.rb +7 -3
  38. data/lib/lookbook/preview_example.rb +7 -3
  39. data/lib/lookbook/preview_group.rb +2 -2
  40. data/lib/lookbook/services/config_loader.rb +20 -0
  41. data/lib/lookbook/services/search_param_builder.rb +13 -0
  42. data/lib/lookbook/services/search_param_parser.rb +15 -0
  43. data/lib/lookbook/services/tags/key_value_tag_parser.rb +24 -0
  44. data/lib/lookbook/source_inspector.rb +10 -16
  45. data/lib/lookbook/stores/config_store.rb +80 -0
  46. data/lib/lookbook/stores/hook_store.rb +28 -0
  47. data/lib/lookbook/stores/input_store.rb +58 -0
  48. data/lib/lookbook/stores/panel_store.rb +141 -0
  49. data/lib/lookbook/stores/tag_store.rb +46 -0
  50. data/lib/lookbook/support/errors/config_error.rb +7 -0
  51. data/lib/lookbook/support/errors/lookbook_error.rb +21 -0
  52. data/lib/lookbook/support/errors/parser_error.rb +7 -0
  53. data/lib/lookbook/support/service.rb +7 -0
  54. data/lib/lookbook/support/store.rb +77 -0
  55. data/lib/lookbook/support/utils/attribute_utils.rb +9 -0
  56. data/lib/lookbook/support/utils/path_utils.rb +19 -0
  57. data/lib/lookbook/tags.rb +5 -14
  58. data/lib/lookbook/version.rb +1 -1
  59. data/lib/lookbook.rb +106 -30
  60. data/public/lookbook-assets/css/lookbook.css +33 -0
  61. data/public/lookbook-assets/css/lookbook.css.map +1 -1
  62. data/public/lookbook-assets/js/lookbook.js +158 -21
  63. data/public/lookbook-assets/js/lookbook.js.map +1 -1
  64. metadata +43 -7
  65. data/lib/lookbook/config.rb +0 -282
  66. data/lib/lookbook/data.rb +0 -11
  67. data/lib/lookbook/hooks.rb +0 -21
  68. data/lib/lookbook/panels.rb +0 -25
  69. data/lib/lookbook/store.rb +0 -48
data/config/panels.yml ADDED
@@ -0,0 +1,30 @@
1
+ shared:
2
+ main:
3
+ - name: preview
4
+ partial: lookbook/previews/panels/preview
5
+ label: Preview
6
+ hotkey: v
7
+
8
+ - name: output
9
+ partial: lookbook/previews/panels/output
10
+ label: HTML
11
+ hotkey: h
12
+
13
+ drawer:
14
+ - name: source
15
+ partial: lookbook/previews/panels/source
16
+ label: Source
17
+ hotkey: s
18
+ copy: "->(data) { data.examples.map { |e| e.source }.join(\n) }"
19
+
20
+ - name: notes
21
+ partial: lookbook/previews/panels/notes
22
+ label: Notes
23
+ hotkey: n
24
+ disabled: ->(data) { data.examples.select { |e| e.notes.present? }.none? }
25
+
26
+ - name: params
27
+ partial: lookbook/previews/panels/params
28
+ label: Params
29
+ hotkey: p
30
+ disabled: ->(data) { data.preview.params.none? }
data/config/routes.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  Lookbook::Engine.routes.draw do
2
2
  if Lookbook::Engine.websocket?
3
- mount Lookbook::Engine.websocket => Lookbook.config.cable_mount_path, :as => :cable
3
+ mount Lookbook::Engine.websocket => "/cable", :as => :cable
4
4
  end
5
5
 
6
6
  root to: "application#index", as: :lookbook_home
data/config/tags.yml ADDED
@@ -0,0 +1,29 @@
1
+ shared:
2
+ hidden:
3
+ label: Hidden status
4
+ opts: {}
5
+
6
+ label:
7
+ label: Label
8
+ opts: {}
9
+
10
+ display:
11
+ label: Display
12
+ opts: {}
13
+
14
+ position:
15
+ label: Position
16
+ opts: {}
17
+
18
+ id:
19
+ label: Id
20
+ opts: {}
21
+
22
+ component:
23
+ label: Component
24
+ opts: {}
25
+
26
+ param:
27
+ label: Param
28
+ yard_parser: with_name
29
+ opts: {}
@@ -3,99 +3,36 @@ require "action_cable/engine"
3
3
  require "listen"
4
4
 
5
5
  module Lookbook
6
- autoload :Config, "lookbook/config"
7
- autoload :Data, "lookbook/data"
8
- autoload :Hooks, "lookbook/hooks"
9
- autoload :Panels, "lookbook/panels"
10
- autoload :Tags, "lookbook/tags"
11
-
12
- class << self
13
- include Lookbook::Data
14
- include Lookbook::Hooks
15
- include Lookbook::Panels
16
- include Lookbook::Tags
17
-
18
- def version
19
- Lookbook::VERSION
20
- end
21
-
22
- def config
23
- @config ||= Config.new
24
- end
25
-
26
- def configure
27
- yield(config)
28
- end
29
-
30
- def logger
31
- @logger ||= if Rails.logger.present? && config.log_use_rails_logger
32
- Rails.logger
33
- else
34
- logger = Logger.new($stdout)
35
- logger.level = config.log_level
36
- logger
37
- end
38
- end
39
-
40
- def debug_data
41
- {
42
- version: version,
43
- env: Rails.env.to_s,
44
- config: config.to_h
45
- }
46
- end
47
-
48
- def previews
49
- Preview.all
50
- end
51
-
52
- def pages
53
- Page.all
54
- end
55
-
56
- def broadcast(event_name, data = {})
57
- Engine.websocket&.broadcast(event_name.to_s, data)
58
- end
59
-
60
- def theme
61
- @theme ||= Lookbook::Theme.new(config.ui_theme, config.ui_theme_overrides)
62
- end
63
-
64
- def define_param_input(input, partial, input_options = nil)
65
- config.preview_param_inputs[input.to_sym] = {
66
- partial: partial,
67
- input_options: input_options || {}
68
- }
69
- end
70
- end
71
-
72
6
  class Engine < Rails::Engine
73
7
  isolate_namespace Lookbook
74
8
 
75
- config.lookbook = Lookbook.config
76
- config.autoload_paths << File.expand_path(Lookbook::Engine.root.join("app/components"))
9
+ config.autoload_paths << File.expand_path(root.join("app/components"))
77
10
 
78
11
  initializer "lookbook.viewcomponent.config" do
79
- config.lookbook.preview_paths += config.view_component.preview_paths
80
- config.lookbook.preview_controller ||= config.view_component.preview_controller
12
+ Lookbook.config.preview_paths += config.view_component.preview_paths
13
+ Lookbook.config.preview_controller ||= config.view_component.preview_controller
81
14
 
82
- config.lookbook.components_path = config.view_component.view_component_path if config.view_component.view_component_path.present?
15
+ Lookbook.config.components_path = config.view_component.view_component_path if config.view_component.view_component_path.present?
83
16
 
84
- config.lookbook.listen_paths += config.lookbook.preview_paths
85
- config.lookbook.listen_paths << config.lookbook.components_path
17
+ Lookbook.config.listen_paths += Lookbook.config.preview_paths
18
+ Lookbook.config.listen_paths << Lookbook.config.components_path
86
19
  end
87
20
 
88
21
  initializer "lookbook.parser.tags" do
89
- Lookbook::Parser.define_tags(Lookbook.config.preview_tags)
22
+ Lookbook::Parser.define_tags(Engine.tags)
90
23
  end
91
24
 
92
25
  initializer "lookbook.assets.serve" do
93
26
  config.app_middleware.use(
94
27
  Rack::Static,
95
- urls: ["/lookbook-assets"], root: Lookbook::Engine.root.join("public").to_s
28
+ urls: ["/lookbook-assets"], root: root.join("public").to_s
96
29
  )
97
30
  end
98
31
 
32
+ config.before_configuration do
33
+ config.lookbook = Lookbook.config
34
+ end
35
+
99
36
  config.after_initialize do
100
37
  @preview_controller = Lookbook.config.preview_controller.constantize
101
38
  @preview_controller.include(Lookbook::PreviewController)
@@ -112,31 +49,30 @@ module Lookbook
112
49
  end
113
50
  else
114
51
  # Fallback for older Rails versions - don't start listeners if running in a rake task.
115
- unless Lookbook::Engine.prevent_listening?
52
+ unless prevent_listening?
116
53
  init_listeners
117
54
  end
118
55
  end
119
56
 
120
57
  parser.parse do
121
- Lookbook::Engine.run_hooks(:after_initialize)
58
+ run_hooks(:after_initialize)
122
59
  end
123
60
  end
124
61
 
125
62
  at_exit do
126
- if Lookbook::Engine.listeners.any?
63
+ if listeners.any?
127
64
  Lookbook.logger.debug "Stopping listeners"
128
- Lookbook::Engine.stop_listeners
65
+ stop_listeners
129
66
  end
130
- Lookbook::Engine.run_hooks(:before_exit)
67
+ run_hooks(:before_exit)
131
68
  end
132
69
 
133
70
  class << self
134
71
  def init_listeners
135
72
  config = Lookbook.config
136
73
  return unless config.listen == true
137
- Listen.logger = Lookbook.logger
138
74
 
139
- listen_paths = config.listen_paths.uniq
75
+ listen_paths = PathUtils.normalize_all(config.listen_paths)
140
76
  if listen_paths.any?
141
77
  preview_listener = Listen.to(*listen_paths,
142
78
  only: /\.(#{config.listen_extensions.join("|")})$/,
@@ -149,7 +85,7 @@ module Lookbook
149
85
  register_listener(preview_listener)
150
86
  end
151
87
 
152
- page_paths = config.page_paths.uniq
88
+ page_paths = PathUtils.normalize_all(config.page_paths)
153
89
  if page_paths.any?
154
90
  page_listener = Listen.to(*page_paths,
155
91
  only: /\.(html.*|md.*)$/,
@@ -184,7 +120,7 @@ module Lookbook
184
120
  end
185
121
 
186
122
  def websocket_mount_path
187
- "#{mounted_path}#{config.lookbook.cable_mount_path}".gsub("//", "/") if websocket?
123
+ "#{mounted_path}/cable".gsub("//", "/") if websocket?
188
124
  end
189
125
 
190
126
  def websocket?
@@ -192,11 +128,12 @@ module Lookbook
192
128
  end
193
129
 
194
130
  def mounted_path
195
- Lookbook::Engine.routes.find_script_name({})
131
+ routes.find_script_name({})
196
132
  end
197
133
 
198
134
  def parser
199
- @parser ||= Lookbook::Parser.new(config.lookbook.preview_paths)
135
+ preview_paths = PathUtils.normalize_all(Lookbook.config.preview_paths)
136
+ @parser ||= Lookbook::Parser.new(preview_paths)
200
137
  end
201
138
 
202
139
  def log_level
@@ -226,7 +163,7 @@ module Lookbook
226
163
  end
227
164
 
228
165
  def run_hooks(event_name, *args)
229
- config.lookbook.hooks[event_name].each do |hook|
166
+ hooks.for_event(event_name).each do |hook|
230
167
  hook.call(Lookbook, *args)
231
168
  end
232
169
  end
@@ -247,6 +184,22 @@ module Lookbook
247
184
  end
248
185
  end
249
186
 
187
+ def panels
188
+ @panels ||= PanelStore.init_from_config
189
+ end
190
+
191
+ def inputs
192
+ @inputs ||= InputStore.init_from_config
193
+ end
194
+
195
+ def tags
196
+ @tags ||= TagStore.init_from_config
197
+ end
198
+
199
+ def hooks
200
+ @hooks ||= HookStore.init_from_config
201
+ end
202
+
250
203
  attr_reader :preview_controller
251
204
  end
252
205
  end
@@ -2,19 +2,9 @@ require "redcarpet"
2
2
 
3
3
  module Lookbook
4
4
  class Markdown
5
- DEFAULT_OPTIONS = {
6
- tables: true,
7
- fenced_code_blocks: true,
8
- disable_indented_code_blocks: true,
9
- strikethrough: true,
10
- highlight: true,
11
- with_toc_data: true,
12
- lax_spacing: true
13
- }
14
-
15
5
  def self.render(text)
16
6
  Utils.strip_action_view_annotations!(text)
17
- markdown = Redcarpet::Markdown.new(Renderer, Lookbook.config.markdown_options)
7
+ markdown = Redcarpet::Markdown.new(Renderer, Lookbook.config.markdown_options.to_h)
18
8
  markdown.render(text).html_safe
19
9
  end
20
10
 
data/lib/lookbook/page.rb CHANGED
@@ -180,7 +180,7 @@ module Lookbook
180
180
  end
181
181
 
182
182
  def page_paths
183
- Lookbook.config.page_paths.select { |dir| Dir.exist? dir }
183
+ PathUtils.normalize_all(Lookbook.config.page_paths)
184
184
  end
185
185
 
186
186
  def section_path?(path)
@@ -117,13 +117,6 @@ module Lookbook
117
117
  end
118
118
  end
119
119
 
120
- def inputs
121
- @inputs ||= Lookbook.config.preview_param_inputs.map do |name, config|
122
- config = {partial: config} if config.is_a?(String)
123
- [name, {input_options: {}}.merge(config)]
124
- end.to_h
125
- end
126
-
127
120
  private
128
121
 
129
122
  def guess_input(value_type, default)
@@ -32,16 +32,9 @@ module Lookbook
32
32
  end
33
33
 
34
34
  class << self
35
- def define_tags(custom = {})
36
- YARD::Tags::Library.define_tag("Hidden status", :hidden)
37
- YARD::Tags::Library.define_tag("Label", :label)
38
- YARD::Tags::Library.define_tag("Display", :display)
39
- YARD::Tags::Library.define_tag("Position", :position)
40
- YARD::Tags::Library.define_tag("ID", :id)
41
- YARD::Tags::Library.define_tag("Component", :component)
42
- YARD::Tags::Library.define_tag("Param", :param, :with_name)
43
- custom.each do |name, opts|
44
- YARD::Tags::Library.define_tag(name.to_s.titleize, name)
35
+ def define_tags(tags = nil)
36
+ tags.to_h.each do |name, tag|
37
+ YARD::Tags::Library.define_tag(tag[:label], name, tag[:yard_parser])
45
38
  end
46
39
  end
47
40
  end
@@ -70,7 +70,7 @@ module Lookbook
70
70
  end
71
71
 
72
72
  def full_path
73
- base_path = Array(Lookbook.config.preview_paths).detect do |preview_path|
73
+ base_path = preview_paths.detect do |preview_path|
74
74
  Dir["#{preview_path}/#{rel_path}"].first
75
75
  end
76
76
  Pathname.new(Dir["#{base_path}/#{rel_path}"].first)
@@ -92,8 +92,8 @@ module Lookbook
92
92
  @preview.instance_variable_get(:@layout)
93
93
  end
94
94
 
95
- def display_params
96
- Lookbook.config.preview_display_params.deep_merge(@preview_inspector&.display_params)
95
+ def display_options
96
+ Lookbook.config.preview_display_options.deep_merge(@preview_inspector&.display_options)
97
97
  end
98
98
 
99
99
  def collapsible?
@@ -111,6 +111,10 @@ module Lookbook
111
111
  end
112
112
  end
113
113
 
114
+ def preview_paths
115
+ PathUtils.normalize_all(Lookbook.config.preview_paths)
116
+ end
117
+
114
118
  protected
115
119
 
116
120
  @preview_objects = nil
@@ -22,8 +22,8 @@ module Lookbook
22
22
  @example_inspector.label.presence || name.titleize
23
23
  end
24
24
 
25
- def display_params
26
- @preview.display_params.merge(@example_inspector.display_params)
25
+ def display_options
26
+ @preview.display_options.merge(@example_inspector.display_options)
27
27
  end
28
28
 
29
29
  def method_source
@@ -63,13 +63,17 @@ module Lookbook
63
63
 
64
64
  def full_template_path(template_path)
65
65
  template_path = strip_ext template_path
66
- base_path = Array(Lookbook.config.preview_paths).detect do |p|
66
+ base_path = preview_paths.detect do |p|
67
67
  Dir["#{p}/#{template_path}.html.*"].first
68
68
  end
69
69
  path = Dir["#{base_path}/#{template_path}.html.*"].first
70
70
  path ? Pathname.new(path) : nil
71
71
  end
72
72
 
73
+ def preview_paths
74
+ PathUtils.normalize_all(Lookbook.config.preview_paths)
75
+ end
76
+
73
77
  class << self
74
78
  def all
75
79
  Preview.all.map { |preview| preview.examples }.flatten
@@ -25,10 +25,10 @@ module Lookbook
25
25
  examples.map(&:params).flatten.uniq { |param| param[:name] }
26
26
  end
27
27
 
28
- def display_params
28
+ def display_options
29
29
  merged = {}
30
30
  examples.reverse.map do |example|
31
- merged.merge! example.display_params
31
+ merged.merge! example.display_options
32
32
  end
33
33
  merged
34
34
  end
@@ -0,0 +1,20 @@
1
+ module Lookbook
2
+ class ConfigLoader < Service
3
+ attr_reader :file, :env
4
+
5
+ def initialize(path, env: Rails.env)
6
+ @file = Engine.root.join(path)
7
+ @env = env.to_sym
8
+ end
9
+
10
+ def call
11
+ if file.exist?
12
+ config = YAML.load_file(file).deep_symbolize_keys
13
+ env_config = config[:shared].to_h.deep_merge(config[env].to_h)
14
+ Store.new(env_config)
15
+ else
16
+ raise ConfigError.new("Could not load configuration. No such file - #{file}")
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,13 @@
1
+ module Lookbook
2
+ class SearchParamBuilder < Service
3
+ attr_reader :data
4
+
5
+ def initialize(data)
6
+ @data = data
7
+ end
8
+
9
+ def call
10
+ data.map { "#{_1}:#{_2}" }.join("|")
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,15 @@
1
+ module Lookbook
2
+ class SearchParamParser < Service
3
+ attr_reader :param_value
4
+
5
+ def initialize(param_value)
6
+ @param_value = param_value.strip
7
+ end
8
+
9
+ def call
10
+ pairs_str = param_value.split("|")
11
+ pairs = pairs_str.map { [*_1.split(":").map(&:strip)] }
12
+ pairs.to_h.symbolize_keys
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,24 @@
1
+ module Lookbook
2
+ class KeyValueTagParser < Service
3
+ KEY_VALUE_REGEX = /^([^\s]+)\s+(.+)$/
4
+
5
+ attr_reader :text
6
+
7
+ def initialize(text)
8
+ @text = text.to_s
9
+ end
10
+
11
+ def call
12
+ text.strip.match(KEY_VALUE_REGEX) do |matches|
13
+ key = matches[1]
14
+ value = begin
15
+ YAML.safe_load(matches[2] || "~")
16
+ rescue ::Psych::SyntaxError => exception
17
+ raise ParserError.new("Invalid YAML in tag text '#{@text}'", scope: "key_value_tag.parser", original: exception)
18
+ end
19
+ return [key, value]
20
+ end
21
+ raise ParserError.new("Could not parse key:value pair from '#{@text}'", scope: "key_value_tag.parser")
22
+ end
23
+ end
24
+ end
@@ -52,22 +52,16 @@ module Lookbook
52
52
  end
53
53
  end
54
54
 
55
- def display_params
56
- return @display_params unless @display_params.nil?
57
- @display_params = {}.with_indifferent_access
58
- if code_object&.tags(:display).present?
59
- code_object.tags(:display).each do |tag|
60
- parts = tag.text.strip.match(/^([^\s]*)\s?(.*)$/)
61
- if parts.present?
62
- begin
63
- display_params[parts[1]] = YAML.safe_load(parts[2] || "~")
64
- rescue SyntaxError => err
65
- Lookbook.logger.error("\nšŸ‘€ [Lookbook] Invalid JSON in @display tag.\nšŸ‘€ [Lookbook] (#{err})\n")
66
- end
67
- end
68
- end
69
- end
70
- @display_params
55
+ def display_options
56
+ return @display_options unless @display_options.nil?
57
+ tags = code_object.tags(:display).to_a
58
+ pairs = tags.map { KeyValueTagParser.call(_1.text) }
59
+
60
+ # dynamic params set at the entity level are
61
+ # not (yet) supported so filter them out.
62
+ pairs.select! { |pair| !pair[1].is_a?(Array) && !pair[1].is_a?(Hash) }
63
+
64
+ pairs.to_h.symbolize_keys
71
65
  end
72
66
 
73
67
  def parameter_defaults
@@ -0,0 +1,80 @@
1
+ module Lookbook
2
+ class ConfigStore
3
+ CONFIG_FILE = "config/app.yml"
4
+
5
+ delegate_missing_to :store
6
+ attr_reader :store
7
+
8
+ def initialize(config = nil)
9
+ @store = Store.new(config, recursive: true)
10
+ end
11
+
12
+ def project_name=(name)
13
+ store[:project_name] = name == false ? nil : name
14
+ end
15
+
16
+ def page_paths=(paths = nil)
17
+ store[:page_paths] ||= []
18
+ store[:page_paths] += paths.to_a
19
+ end
20
+
21
+ def preview_paths=(paths = nil)
22
+ store[:preview_paths] ||= []
23
+ store[:preview_paths] += paths.to_a
24
+ end
25
+
26
+ def preview_display_params
27
+ Lookbook.logger.warn "The `preview_display_params` config option has been renamed to `preview_display_options` and will be removed in v2.0"
28
+ store[:preview_display_options]
29
+ end
30
+
31
+ def preview_display_params=(options)
32
+ Lookbook.logger.warn "The `preview_display_params` config option has been renamed to `preview_display_options` and will be removed in v2.0"
33
+ store[:preview_display_options] = options.to_h
34
+ end
35
+
36
+ def listen_extensions=(extensions = nil)
37
+ store[:listen_extensions] ||= []
38
+ store[:listen_extensions] += extensions.to_a
39
+ store[:listen_extensions].uniq!
40
+ end
41
+
42
+ def markdown_options=(options = nil)
43
+ store[:markdown_options] ||= {}
44
+ store[:markdown_options].merge!(options.to_h)
45
+ end
46
+
47
+ def ui_theme=(name)
48
+ name = name.to_s
49
+ if Theme.valid_theme?(name)
50
+ store[:ui_theme] = name
51
+ else
52
+ raise ConfigError.new("'#{name}' is not a valid Lookbook theme. ", scope: "app.config")
53
+ end
54
+ end
55
+
56
+ def ui_theme_overrides(&block)
57
+ if block
58
+ yield store[:ui_theme_overrides]
59
+ else
60
+ store[:ui_theme_overrides]
61
+ end
62
+ end
63
+
64
+ def runtime_parsing=(value)
65
+ Lookbook.logger.warn "The `runtime_parsing` config option has been deprecated and will be removed in v2.0"
66
+ end
67
+
68
+ def preview_srcdoc=(enable)
69
+ Lookbook.logger.warn "The `preview_srcdoc` config option is deprecated and will be removed in v2.0"
70
+ end
71
+
72
+ def self.init_from_config(env: Rails.env)
73
+ new(default_config(env: env))
74
+ end
75
+
76
+ def self.default_config(env: Rails.env)
77
+ ConfigLoader.call(CONFIG_FILE, env: env)
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,28 @@
1
+ module Lookbook
2
+ class HookStore
3
+ CONFIG_FILE = "config/hooks.yml"
4
+
5
+ attr_reader :store
6
+ delegate :to_h, to: :store
7
+
8
+ def initialize(config = nil)
9
+ @store = {}
10
+ end
11
+
12
+ def add_hook(event_name, callback)
13
+ for_event(event_name) << callback
14
+ end
15
+
16
+ def for_event(event_name)
17
+ store[event_name.to_sym] ||= []
18
+ end
19
+
20
+ def self.init_from_config
21
+ new(default_config)
22
+ end
23
+
24
+ def self.default_config
25
+ ConfigLoader.call(CONFIG_FILE)
26
+ end
27
+ end
28
+ end