lookbook 1.5.0 → 2.0.0.beta.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +11 -21
- data/app/assets/lookbook/css/lookbook.css +9 -0
- data/app/assets/lookbook/css/themes/blue.css +7 -0
- data/app/assets/lookbook/css/themes/green.css +7 -0
- data/app/assets/lookbook/css/themes/indigo.css +7 -0
- data/app/assets/lookbook/css/themes/rose.css +7 -0
- data/app/assets/lookbook/css/themes/zinc.css +7 -0
- data/app/assets/lookbook/css/tooltip.css +9 -6
- data/app/assets/lookbook/img/lucide-sprite.svg +4960 -0
- data/app/assets/lookbook/js/app.js +22 -4
- data/app/assets/lookbook/js/helpers/dom.js +4 -7
- data/app/assets/lookbook/js/helpers/string.js +4 -11
- data/app/assets/lookbook/js/{embed.js → iframe.js} +0 -0
- data/app/assets/lookbook/js/index.js +61 -0
- data/app/assets/lookbook/js/lib/lookbook.js +113 -0
- data/app/assets/lookbook/js/lib/tippy.js +1 -0
- data/app/assets/lookbook/js/lookbook-core.js +1 -0
- data/app/assets/lookbook/js/lookbook.js +2 -61
- data/app/components/lookbook/base_component.rb +3 -1
- data/app/components/lookbook/button/component.html.erb +13 -24
- data/app/components/lookbook/button/component.js +13 -3
- data/app/components/lookbook/button/component.rb +16 -25
- data/app/components/lookbook/code/component.rb +0 -2
- data/app/components/lookbook/copy_button/component.html.erb +4 -4
- data/app/components/lookbook/copy_button/component.rb +6 -3
- data/app/components/lookbook/debug_menu/component.html.erb +1 -0
- data/app/components/lookbook/debug_menu/component.rb +12 -1
- data/app/components/lookbook/display_options/editor/component.html.erb +1 -1
- data/app/components/lookbook/display_options/field/component.css +0 -26
- data/app/components/lookbook/display_options/field/component.html.erb +1 -1
- data/app/components/lookbook/embed/component.html.erb +6 -51
- data/app/components/lookbook/embed/component.rb +17 -16
- data/app/components/lookbook/embed/inspector/component.html.erb +102 -0
- data/app/components/lookbook/embed/inspector/component.js +46 -0
- data/app/components/lookbook/embed/inspector/component.rb +64 -0
- data/app/components/lookbook/embed_code_dropdown/component.css +12 -0
- data/app/components/lookbook/embed_code_dropdown/component.html.erb +19 -0
- data/app/components/lookbook/embed_code_dropdown/component.js +26 -0
- data/app/components/lookbook/embed_code_dropdown/component.rb +41 -0
- data/app/components/lookbook/header/component.html.erb +7 -6
- data/app/components/lookbook/header/component.rb +5 -1
- data/app/components/lookbook/icon/component.html.erb +1 -1
- data/app/components/lookbook/icon_button/component.html.erb +20 -0
- data/app/components/lookbook/icon_button/component.rb +46 -0
- data/app/components/lookbook/nav/component.html.erb +0 -1
- data/app/components/lookbook/nav/entity/component.rb +2 -2
- data/app/components/lookbook/nav/item/component.rb +1 -1
- data/app/components/lookbook/params/editor/component.rb +1 -0
- data/app/components/lookbook/prose/component.rb +1 -3
- data/app/components/lookbook/tabs/component.html.erb +2 -2
- data/app/components/lookbook/tabs/component.js +1 -1
- data/app/components/lookbook/tag_component.rb +2 -1
- data/app/components/lookbook/text_button/component.html.erb +26 -0
- data/app/components/lookbook/text_button/component.rb +42 -0
- data/app/components/lookbook/toolbar/component.html.erb +1 -1
- data/app/components/lookbook/viewport/component.rb +0 -4
- data/app/controllers/concerns/lookbook/targetable_concern.rb +24 -19
- data/app/controllers/concerns/lookbook/with_panels_concern.rb +30 -0
- data/app/controllers/concerns/lookbook/with_preview_controller_concern.rb +4 -3
- data/app/controllers/lookbook/application_controller.rb +9 -11
- data/app/controllers/lookbook/embeds_controller.rb +148 -0
- data/app/controllers/lookbook/inspector_controller.rb +3 -22
- data/app/controllers/lookbook/page_controller.rb +7 -6
- data/app/controllers/lookbook/pages_controller.rb +3 -4
- data/app/controllers/lookbook/preview_controller.rb +17 -0
- data/app/controllers/lookbook/previews_controller.rb +25 -7
- data/app/helpers/lookbook/application_helper.rb +3 -19
- data/app/views/layouts/lookbook/application.html.erb +85 -60
- data/app/views/layouts/lookbook/embed.html.erb +16 -0
- data/app/views/layouts/lookbook/shell.html.erb +1 -1
- data/app/views/layouts/lookbook/skeleton.html.erb +13 -8
- data/app/views/lookbook/embeds/show.html.erb +12 -0
- data/app/views/lookbook/inspector/panels/_notes.html.erb +1 -1
- data/app/views/lookbook/inspector/panels/_output.html.erb +3 -3
- data/app/views/lookbook/inspector/panels/_source.html.erb +6 -6
- data/app/views/lookbook/inspector/show.html.erb +130 -123
- data/app/views/lookbook/pages/show.html.erb +81 -34
- data/app/views/lookbook/partials/_iframe_content_scripts.html.erb +1 -0
- data/app/views/lookbook/partials/_user_styles.html.erb +5 -0
- data/app/views/lookbook/{preview.html.erb → previews/group.html.erb} +7 -7
- data/app/views/lookbook/previews/preview.html.erb +5 -0
- data/app/views/lookbook/previews/show.html.erb +1 -0
- data/config/app.yml +31 -16
- data/config/panels.yml +23 -25
- data/config/routes.rb +4 -1
- data/config/tags.yml +6 -2
- data/lib/lookbook/cable/cable.rb +53 -0
- data/{app/channels/lookbook → lib/lookbook/cable}/connection.rb +0 -0
- data/{app/channels/lookbook → lib/lookbook/cable}/reload_channel.rb +0 -0
- data/lib/lookbook/engine.rb +109 -87
- data/lib/lookbook/entities/collections/entity_collection.rb +11 -6
- data/lib/lookbook/entities/collections/page_collection.rb +33 -8
- data/lib/lookbook/entities/collections/preview_collection.rb +42 -17
- data/lib/lookbook/entities/collections/render_target_collection.rb +4 -0
- data/lib/lookbook/entities/collections/scenario_collection.rb +4 -0
- data/lib/lookbook/entities/concerns/{annotatable.rb → annotatable_entity.rb} +7 -6
- data/lib/lookbook/entities/concerns/{inspectable.rb → inspectable_entity.rb} +2 -1
- data/lib/lookbook/entities/concerns/{locatable.rb → locatable_entity.rb} +8 -14
- data/lib/lookbook/entities/concerns/navigable_entity.rb +44 -0
- data/lib/lookbook/entities/entity.rb +7 -2
- data/lib/lookbook/entities/{page.rb → page_entity.rb} +10 -6
- data/lib/lookbook/entities/{page_section.rb → page_section_entity.rb} +1 -1
- data/lib/lookbook/entities/preview_entity.rb +99 -0
- data/lib/lookbook/entities/renderable_entity.rb +50 -0
- data/lib/lookbook/entities/rendered_scenario_entity.rb +53 -0
- data/lib/lookbook/entities/scenario_entity.rb +112 -0
- data/lib/lookbook/entities/scenario_group_entity.rb +53 -0
- data/lib/lookbook/error.rb +5 -5
- data/lib/lookbook/file_watcher.rb +19 -35
- data/lib/lookbook/helpers/class_names_helper.rb +28 -0
- data/lib/lookbook/helpers/page_helper.rb +18 -0
- data/{app/helpers/lookbook → lib/lookbook/helpers}/preview_helper.rb +3 -0
- data/lib/lookbook/helpers/ui_elements_helper.rb +115 -0
- data/lib/lookbook/preview.rb +79 -0
- data/lib/lookbook/preview_controller_actions.rb +50 -0
- data/lib/lookbook/preview_parser.rb +4 -2
- data/lib/lookbook/reloaders.rb +71 -0
- data/lib/lookbook/runtime_context.rb +49 -0
- data/lib/lookbook/services/data/resolvers/data_resolver.rb +4 -6
- data/lib/lookbook/services/entities/entity_tree_builder.rb +6 -6
- data/lib/lookbook/services/list_resolver.rb +35 -0
- data/lib/lookbook/services/markdown_renderer.rb +12 -2
- data/lib/lookbook/services/priority_prefix_parser.rb +16 -0
- data/lib/lookbook/services/urls/search_param_encoder.rb +16 -0
- data/lib/lookbook/services/urls/search_param_parser.rb +7 -6
- data/lib/lookbook/stores/config_store.rb +16 -16
- data/lib/lookbook/stores/input_store.rb +1 -3
- data/lib/lookbook/stores/panel_store.rb +28 -50
- data/lib/lookbook/support/deprecation.rb +5 -0
- data/lib/lookbook/support/errors/preview_template_error.rb +7 -0
- data/lib/lookbook/support/evented_file_update_checker.rb +69 -0
- data/lib/lookbook/support/null_websocket.rb +9 -0
- data/lib/lookbook/support/store.rb +9 -0
- data/lib/lookbook/support/tree_node.rb +7 -7
- data/lib/lookbook/support/utils/path_utils.rb +7 -1
- data/lib/lookbook/support/utils/utils.rb +8 -0
- data/lib/lookbook/tags/{position_tag.rb → priority_tag.rb} +4 -4
- data/lib/lookbook/tags/renders_tag.rb +4 -0
- data/lib/lookbook/tags/tag_provider.rb +3 -0
- data/lib/lookbook/tags/type_tag.rb +7 -0
- data/lib/lookbook/tags/yard_tag.rb +1 -2
- data/lib/lookbook/version.rb +1 -1
- data/lib/lookbook/websocket.rb +6 -53
- data/lib/lookbook.rb +179 -53
- data/public/lookbook-assets/css/lookbook.css +141 -83
- data/public/lookbook-assets/css/lookbook.css.map +1 -1
- data/public/lookbook-assets/css/themes/blue.css +7 -0
- data/public/lookbook-assets/css/themes/blue.css.map +1 -1
- data/public/lookbook-assets/css/themes/green.css +7 -0
- data/public/lookbook-assets/css/themes/green.css.map +1 -1
- data/public/lookbook-assets/css/themes/indigo.css +7 -0
- data/public/lookbook-assets/css/themes/indigo.css.map +1 -1
- data/public/lookbook-assets/css/themes/rose.css +7 -0
- data/public/lookbook-assets/css/themes/rose.css.map +1 -1
- data/public/lookbook-assets/css/themes/zinc.css +7 -0
- data/public/lookbook-assets/css/themes/zinc.css.map +1 -1
- data/public/lookbook-assets/img/lucide-sprite.svg +4960 -0
- data/public/lookbook-assets/js/embed.js +1363 -841
- data/public/lookbook-assets/js/embed.js.map +1 -1
- data/public/lookbook-assets/js/iframe.js +906 -0
- data/public/lookbook-assets/js/iframe.js.map +1 -0
- data/public/lookbook-assets/js/index.js +13567 -0
- data/public/lookbook-assets/js/index.js.map +1 -0
- data/public/lookbook-assets/js/lookbook-core.js +85 -0
- data/public/lookbook-assets/js/lookbook-core.js.map +1 -0
- data/public/lookbook-assets/js/lookbook.js +164 -12638
- data/public/lookbook-assets/js/lookbook.js.map +1 -1
- data/public/lookbook-assets/lookbook-esm.js +1427 -0
- data/public/lookbook-assets/lookbook-esm.js.map +1 -0
- data/public/lookbook-assets/lookbook-global.js +1427 -0
- data/public/lookbook-assets/lookbook-global.js.map +1 -0
- data/public/lookbook-assets/lookbook.js +1427 -0
- data/public/lookbook-assets/lookbook.js.map +1 -0
- metadata +80 -72
- data/app/components/lookbook/embed/component.js +0 -39
- data/app/helpers/lookbook/component_helper.rb +0 -84
- data/app/helpers/lookbook/output_helper.rb +0 -19
- data/app/helpers/lookbook/page_helper.rb +0 -34
- data/app/views/layouts/lookbook/inspector.html.erb +0 -7
- data/app/views/layouts/lookbook/page.html.erb +0 -53
- data/app/views/layouts/lookbook/standalone.html.erb +0 -5
- data/lib/lookbook/entities/collections/component_collection.rb +0 -4
- data/lib/lookbook/entities/collections/preview_example_collection.rb +0 -4
- data/lib/lookbook/entities/component.rb +0 -31
- data/lib/lookbook/entities/concerns/navigable.rb +0 -43
- data/lib/lookbook/entities/preview.rb +0 -87
- data/lib/lookbook/entities/preview_example.rb +0 -100
- data/lib/lookbook/entities/preview_group.rb +0 -48
- data/lib/lookbook/preview_actions.rb +0 -43
- data/lib/lookbook/process.rb +0 -21
- data/lib/lookbook/rendered_example.rb +0 -37
- data/lib/lookbook/services/position_prefix_parser.rb +0 -16
- data/lib/lookbook/services/urls/search_param_builder.rb +0 -13
- data/lib/lookbook/tags/component_tag.rb +0 -13
@@ -0,0 +1,49 @@
|
|
1
|
+
module Lookbook
|
2
|
+
class RuntimeContext
|
3
|
+
attr_reader :env
|
4
|
+
|
5
|
+
def initialize(env: Rails.env)
|
6
|
+
@env = env
|
7
|
+
end
|
8
|
+
|
9
|
+
def app_name
|
10
|
+
return @_app_name if @_app_name
|
11
|
+
|
12
|
+
app_class = Rails.application.class
|
13
|
+
name = app_class.respond_to?(:module_parent_name) ? app_class.module_parent_name : app_class.parent_name
|
14
|
+
@_app_name ||= name.underscore
|
15
|
+
end
|
16
|
+
|
17
|
+
def rails_older_than?(version)
|
18
|
+
Gem::Version.new(Rails.version) < Gem::Version.new(version)
|
19
|
+
end
|
20
|
+
|
21
|
+
def rails_newer_than?(version)
|
22
|
+
Gem::Version.new(Rails.version) >= Gem::Version.new(version)
|
23
|
+
end
|
24
|
+
|
25
|
+
def actioncable_installed?
|
26
|
+
gem_installed?("actioncable")
|
27
|
+
end
|
28
|
+
|
29
|
+
def listen_installed?
|
30
|
+
gem_installed?("listen")
|
31
|
+
end
|
32
|
+
|
33
|
+
def gem_installed?(name)
|
34
|
+
Gem.loaded_specs.has_key?(name)
|
35
|
+
end
|
36
|
+
|
37
|
+
def web?
|
38
|
+
!rake_task? && !Rails.const_defined?(:Console)
|
39
|
+
end
|
40
|
+
|
41
|
+
def rake_task?
|
42
|
+
if defined?(Rake) && Rake.respond_to?(:application)
|
43
|
+
File.basename($0) == "rake" || Rake.application.top_level_tasks.any?
|
44
|
+
else
|
45
|
+
false
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -5,10 +5,9 @@ module Lookbook
|
|
5
5
|
|
6
6
|
attr_reader :eval_context, :base_dir, :file, :fallback
|
7
7
|
|
8
|
-
def initialize(input, eval_context: nil,
|
8
|
+
def initialize(input, eval_context: nil, fail_silently: false, base_dir: Rails.root, file: nil, fallback: nil)
|
9
9
|
@input = input.to_s
|
10
10
|
@eval_context = eval_context
|
11
|
-
@permit_eval = permit_eval
|
12
11
|
@fail_silently = fail_silently
|
13
12
|
@fallback = fallback
|
14
13
|
@base_dir = base_dir.to_s
|
@@ -44,7 +43,9 @@ module Lookbook
|
|
44
43
|
def evaluate(input, fallback = @fallback)
|
45
44
|
if evaluatable?
|
46
45
|
begin
|
47
|
-
|
46
|
+
proc {
|
47
|
+
eval_context.instance_eval(input.to_s)
|
48
|
+
}.call
|
48
49
|
rescue => exception
|
49
50
|
raise_error "Could not evaluate statetment (#{exception.message})", exception
|
50
51
|
end
|
@@ -61,9 +62,6 @@ module Lookbook
|
|
61
62
|
private
|
62
63
|
|
63
64
|
def evaluatable?
|
64
|
-
if !@permit_eval
|
65
|
-
raise_error "Runtime evaluation is not permitted"
|
66
|
-
end
|
67
65
|
eval_context.present?
|
68
66
|
end
|
69
67
|
end
|
@@ -13,15 +13,15 @@ module Lookbook
|
|
13
13
|
current_node = root_node
|
14
14
|
path_segments = parse_segments(entity.logical_path)
|
15
15
|
path_segments.each.with_index(1) do |segment, i|
|
16
|
-
name,
|
16
|
+
name, priority_prefix = segment
|
17
17
|
content = entity if entity.depth == i # entities are always on the leaf nodes
|
18
18
|
|
19
|
-
current_node.add_child(name, content,
|
19
|
+
current_node.add_child(name, content, priority: priority_prefix) unless current_node.has_child?(name)
|
20
20
|
current_node = current_node.get_child(name)
|
21
21
|
|
22
22
|
if content && content.type == :preview
|
23
|
-
content.
|
24
|
-
current_node.add_child(
|
23
|
+
content.visible_scenarios.each do |scenario|
|
24
|
+
current_node.add_child(scenario.name, scenario)
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
@@ -32,8 +32,8 @@ module Lookbook
|
|
32
32
|
def parse_segments(path)
|
33
33
|
path.split("/").map do |segment|
|
34
34
|
unless segment.start_with?(".")
|
35
|
-
|
36
|
-
[name,
|
35
|
+
priority, name = PriorityPrefixParser.call(segment)
|
36
|
+
[name, priority || 10000]
|
37
37
|
end
|
38
38
|
end.compact
|
39
39
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Lookbook
|
2
|
+
class ListResolver < Service
|
3
|
+
attr_reader :item_set
|
4
|
+
|
5
|
+
def initialize(to_include = nil, item_set = nil)
|
6
|
+
@to_include = to_include
|
7
|
+
@item_set = Array(item_set).compact.uniq.map(&:to_s)
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(&resolver)
|
11
|
+
included = to_include.inject([]) do |result, name|
|
12
|
+
if name == "*"
|
13
|
+
result += item_set.select { |item| !result.include?(item) }
|
14
|
+
elsif item_set.include?(name)
|
15
|
+
result << name
|
16
|
+
end
|
17
|
+
result
|
18
|
+
end
|
19
|
+
|
20
|
+
resolved = resolver ? included.map { |item| resolver.call(item) } : included
|
21
|
+
resolved.compact
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_include
|
25
|
+
case @to_include
|
26
|
+
when true
|
27
|
+
["*"]
|
28
|
+
when false
|
29
|
+
[]
|
30
|
+
else
|
31
|
+
Array(@to_include).compact.uniq.map(&:to_s)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -6,7 +6,7 @@ module Lookbook
|
|
6
6
|
|
7
7
|
def initialize(text, opts = {})
|
8
8
|
@text = text
|
9
|
-
@opts = opts.to_h
|
9
|
+
@opts = Lookbook.config.markdown_options.merge(opts.to_h)
|
10
10
|
end
|
11
11
|
|
12
12
|
def call
|
@@ -18,7 +18,17 @@ module Lookbook
|
|
18
18
|
class LookbookMarkdownRenderer < Redcarpet::Render::HTML
|
19
19
|
def block_code(code, language = "ruby")
|
20
20
|
line_numbers = language.to_s.end_with? "-numbered"
|
21
|
-
ApplicationController.render(Lookbook::Code::Component.new(
|
21
|
+
ApplicationController.render(Lookbook::Code::Component.new(**{
|
22
|
+
source: code,
|
23
|
+
language: language.to_s.chomp("-numbered"),
|
24
|
+
line_numbers: line_numbers
|
25
|
+
}), layout: nil)
|
26
|
+
end
|
27
|
+
|
28
|
+
def postprocess(full_document)
|
29
|
+
full_document&.gsub!("<p><lookbook", "<lookbook")
|
30
|
+
full_document&.gsub!("</lookbook-embed></p>", "</lookbook-embed>")
|
31
|
+
full_document
|
22
32
|
end
|
23
33
|
end
|
24
34
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Lookbook
|
2
|
+
class PriorityPrefixParser < Service
|
3
|
+
PRIORITY_PREFIX_REGEX = /^(\d+?)[-_]/
|
4
|
+
|
5
|
+
attr_reader :input
|
6
|
+
|
7
|
+
def initialize(input)
|
8
|
+
@input = String(input)
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
matches = input.match(PRIORITY_PREFIX_REGEX)
|
13
|
+
matches ? [matches[1].to_i, input.gsub(PRIORITY_PREFIX_REGEX, "")] : [nil, input]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -1,15 +1,16 @@
|
|
1
|
+
require "cgi"
|
2
|
+
|
1
3
|
module Lookbook
|
2
4
|
class SearchParamParser < Service
|
3
|
-
attr_reader :
|
5
|
+
attr_reader :str
|
4
6
|
|
5
|
-
def initialize(
|
6
|
-
@
|
7
|
+
def initialize(str)
|
8
|
+
@str = str.to_s.strip
|
7
9
|
end
|
8
10
|
|
9
11
|
def call
|
10
|
-
|
11
|
-
|
12
|
-
pairs.to_h.symbolize_keys
|
12
|
+
json = CGI.unescape(str)
|
13
|
+
JsonParser.call(json)
|
13
14
|
end
|
14
15
|
end
|
15
16
|
end
|
@@ -1,4 +1,18 @@
|
|
1
1
|
module Lookbook
|
2
|
+
# Configuration store for Lookbook.
|
3
|
+
#
|
4
|
+
# Config option values can be get/set using hash property access syntax
|
5
|
+
# or dot-notation syntax.
|
6
|
+
#
|
7
|
+
# @example :ruby
|
8
|
+
# # Lookbook config access in Rails config files:
|
9
|
+
# config.lookbook.ui_theme = :zinc
|
10
|
+
#
|
11
|
+
# # Lookbook config access everywhere else:
|
12
|
+
# Lookbook.config.ui_theme = :zinc
|
13
|
+
#
|
14
|
+
# @ignore methods
|
15
|
+
# @api public
|
2
16
|
class ConfigStore
|
3
17
|
CONFIG_FILE = "config/app.yml"
|
4
18
|
|
@@ -25,14 +39,8 @@ module Lookbook
|
|
25
39
|
store[:preview_paths].push(*paths.to_a)
|
26
40
|
end
|
27
41
|
|
28
|
-
def
|
29
|
-
|
30
|
-
store[:preview_display_options]
|
31
|
-
end
|
32
|
-
|
33
|
-
def preview_display_params=(options)
|
34
|
-
Lookbook.logger.warn "The `preview_display_params` config option has been renamed to `preview_display_options` and will be removed in v2.0"
|
35
|
-
store[:preview_display_options] = options.to_h
|
42
|
+
def component_paths=(paths = nil)
|
43
|
+
store[:component_paths].push(*paths.to_a)
|
36
44
|
end
|
37
45
|
|
38
46
|
def listen_extensions=(extensions = nil)
|
@@ -64,14 +72,6 @@ module Lookbook
|
|
64
72
|
end
|
65
73
|
end
|
66
74
|
|
67
|
-
def runtime_parsing=(value)
|
68
|
-
Lookbook.logger.warn "The `runtime_parsing` config option has been deprecated and will be removed in v2.0"
|
69
|
-
end
|
70
|
-
|
71
|
-
def preview_srcdoc=(enable)
|
72
|
-
Lookbook.logger.warn "The `preview_srcdoc` config option is deprecated and will be removed in v2.0"
|
73
|
-
end
|
74
|
-
|
75
75
|
def self.init_from_config(env: Rails.env)
|
76
76
|
new(default_config(env: env))
|
77
77
|
end
|
@@ -3,7 +3,7 @@ module Lookbook
|
|
3
3
|
CONFIG_FILE = "config/panels.yml"
|
4
4
|
|
5
5
|
DEFAULTS = {
|
6
|
-
label: lambda { |data| data.name.titleize },
|
6
|
+
label: lambda { |data| data.name.to_s.titleize },
|
7
7
|
hotkey: nil,
|
8
8
|
disabled: false,
|
9
9
|
show: true,
|
@@ -19,65 +19,53 @@ module Lookbook
|
|
19
19
|
load_config(config)
|
20
20
|
end
|
21
21
|
|
22
|
-
def add_panel(name,
|
22
|
+
def add_panel(name, *args)
|
23
23
|
if get_panel(name)
|
24
24
|
raise ConfigError.new("panel with name '#{name}' already exists", scope: "panels.config")
|
25
25
|
else
|
26
|
-
|
27
|
-
insert_at_position(group_name, panel.position, panel)
|
26
|
+
store[Utils.symbolize_name(name)] = build_config(name, *args)
|
28
27
|
end
|
29
28
|
end
|
30
29
|
|
31
30
|
def update_panel(name, opts = {})
|
32
31
|
panel = get_panel(name)
|
33
32
|
if panel.present?
|
34
|
-
panel.merge!(opts.except(:name
|
35
|
-
if opts.key?(:position)
|
36
|
-
remove_panel(name)
|
37
|
-
insert_at_position(panel.group, opts[:position], panel)
|
38
|
-
end
|
33
|
+
panel.merge!(opts.except(:name))
|
39
34
|
else
|
40
35
|
not_found!(name)
|
41
36
|
end
|
42
37
|
end
|
43
38
|
|
44
39
|
def remove_panel(name)
|
45
|
-
store.
|
46
|
-
return true unless panels.reject! { |p| p.name == name.to_sym }.nil?
|
47
|
-
end
|
48
|
-
not_found!(name)
|
40
|
+
store.delete(Utils.symbolize_name(name)) { |name| not_found!(name) }
|
49
41
|
end
|
50
42
|
|
51
43
|
def load_config(config)
|
52
|
-
config.to_h.each
|
53
|
-
panels.each do |opts|
|
54
|
-
add_panel(opts[:name], group_name, opts.except(:name))
|
55
|
-
end
|
56
|
-
end
|
44
|
+
config.to_h.each { |name, opts| add_panel(name, opts) }
|
57
45
|
end
|
58
46
|
|
59
|
-
def get_panel(name
|
60
|
-
panels
|
47
|
+
def get_panel(name)
|
48
|
+
panels.find { |panel| panel.name == Utils.symbolize_name(name) }
|
61
49
|
end
|
62
50
|
|
63
|
-
def
|
64
|
-
panels(
|
51
|
+
def get_panels(*names)
|
52
|
+
ListResolver.call(names.flatten, panels.map(&:name)) { |name| get_panel(name) }
|
65
53
|
end
|
66
54
|
|
67
|
-
def
|
68
|
-
store
|
55
|
+
def panels
|
56
|
+
store.map { |name, panel| panel }
|
69
57
|
end
|
70
58
|
|
71
|
-
def
|
72
|
-
|
73
|
-
result.push(*group_panels) if group_name.nil? || name == group_name.to_sym
|
74
|
-
end
|
59
|
+
def names
|
60
|
+
panels.map(&:name)
|
75
61
|
end
|
76
62
|
|
63
|
+
alias_method :all, :panels
|
64
|
+
|
77
65
|
def self.resolve_config(opts, data)
|
78
66
|
if opts[:name].present?
|
79
67
|
data = data.is_a?(Store) ? data : Store.new(data)
|
80
|
-
data.name = opts[:name]
|
68
|
+
data.name = Utils.symbolize_name(opts[:name])
|
81
69
|
resolved = opts.transform_values do |value|
|
82
70
|
value.respond_to?(:call) ? value.call(data) : value
|
83
71
|
end
|
@@ -93,10 +81,14 @@ module Lookbook
|
|
93
81
|
|
94
82
|
def self.default_config
|
95
83
|
config = ConfigLoader.call(CONFIG_FILE)
|
96
|
-
config.
|
97
|
-
|
98
|
-
|
99
|
-
|
84
|
+
config.to_h.transform_values! do |opts|
|
85
|
+
opts.transform_values! do |value|
|
86
|
+
if value.is_a?(String) && value.start_with?("->")
|
87
|
+
proc {
|
88
|
+
eval(value) # standard:disable Security/Eval
|
89
|
+
}.call
|
90
|
+
else
|
91
|
+
value
|
100
92
|
end
|
101
93
|
end
|
102
94
|
end
|
@@ -104,21 +96,8 @@ module Lookbook
|
|
104
96
|
|
105
97
|
protected
|
106
98
|
|
107
|
-
def
|
108
|
-
|
109
|
-
index = insert_index(position, group_panels.count)
|
110
|
-
group_panels.insert(index, opts.except!(:position))
|
111
|
-
end
|
112
|
-
|
113
|
-
def insert_index(position, items_count)
|
114
|
-
index = (position == 0) ? 1 : (position || 0).to_int
|
115
|
-
last_position = items_count + 1
|
116
|
-
index = last_position if index > last_position
|
117
|
-
index - 1
|
118
|
-
end
|
119
|
-
|
120
|
-
def build_config(name, group_name, *args)
|
121
|
-
opts = if args.many? && args.last.is_a?(Hash)
|
99
|
+
def build_config(name, *args)
|
100
|
+
opts = if args.many? && args.first.is_a?(String) && args.last.is_a?(Hash)
|
122
101
|
args.last.merge({partial: args.first})
|
123
102
|
elsif args.any?
|
124
103
|
args.first.is_a?(String) ? {partial: args.first} : args.first
|
@@ -126,8 +105,7 @@ module Lookbook
|
|
126
105
|
{}
|
127
106
|
end
|
128
107
|
if opts[:partial].present?
|
129
|
-
opts[:name] = name
|
130
|
-
opts[:group] = group_name.to_sym
|
108
|
+
opts[:name] = Utils.symbolize_name(name)
|
131
109
|
Store.new(DEFAULTS.merge(opts))
|
132
110
|
else
|
133
111
|
raise ConfigError.new("panels must define a partial path", scope: "panels.config")
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require "active_support/evented_file_update_checker"
|
2
|
+
|
3
|
+
module Lookbook
|
4
|
+
require "listen" unless Engine.runtime_context.rails_newer_than?("6.1.0")
|
5
|
+
|
6
|
+
class EventedFileUpdateChecker < ActiveSupport::EventedFileUpdateChecker
|
7
|
+
if Engine.runtime_context.rails_newer_than?("6.1.0")
|
8
|
+
|
9
|
+
def initialize(files, dirs = {}, &block)
|
10
|
+
super
|
11
|
+
@core = Core.new(files, dirs)
|
12
|
+
end
|
13
|
+
|
14
|
+
class Core < ActiveSupport::EventedFileUpdateChecker::Core
|
15
|
+
def changed(modified, added, removed)
|
16
|
+
super
|
17
|
+
Engine.files_changed(modified, added, removed) if @updated
|
18
|
+
end
|
19
|
+
|
20
|
+
# Patched to handle regex-style
|
21
|
+
# extension matchers like `.html.*`
|
22
|
+
def watching?(file)
|
23
|
+
return true if super
|
24
|
+
|
25
|
+
file = Pathname(file)
|
26
|
+
name_parts = file.basename.to_s.split(".")
|
27
|
+
ext = "." + name_parts.drop(1).join(".").to_s
|
28
|
+
|
29
|
+
file.dirname.ascend do |dir|
|
30
|
+
matching = @dirs.fetch(dir, []).map { |m| Regexp.new(m) }
|
31
|
+
if matching.empty? || matching.find { |m| m.match?(ext) }
|
32
|
+
break true
|
33
|
+
elsif dir == @common_path || dir.root?
|
34
|
+
break false
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
else
|
41
|
+
|
42
|
+
# Patched to handle regex-style
|
43
|
+
# extension matchers like `.html.*`
|
44
|
+
def watching?(file)
|
45
|
+
return true if super
|
46
|
+
|
47
|
+
file = Pathname(file)
|
48
|
+
name_parts = file.basename.to_s.split(".")
|
49
|
+
ext = "." + name_parts.drop(1).join(".").to_s
|
50
|
+
|
51
|
+
file.dirname.ascend do |dir|
|
52
|
+
matching = @dirs.fetch(dir, []).map { |m| Regexp.new(m) }
|
53
|
+
if matching.empty? || matching.find { |m| m.match?(ext) }
|
54
|
+
break true
|
55
|
+
elsif dir == @lcsp || dir.root?
|
56
|
+
break false
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def changed(modified, added, removed)
|
64
|
+
super
|
65
|
+
Engine.files_changed(modified, added, removed) if updated?
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -1,4 +1,13 @@
|
|
1
1
|
module Lookbook
|
2
|
+
# Generic hash-like key/value store.
|
3
|
+
#
|
4
|
+
# Properties can be get/set using hash access syntax (`data[:key]`)
|
5
|
+
# or dot-notation syntax (`data.key`).
|
6
|
+
#
|
7
|
+
# Based on [ActiveSupport::OrderedOptions](https://api.rubyonrails.org/classes/ActiveSupport/OrderedOptions.html)
|
8
|
+
#
|
9
|
+
# @ignore methods
|
10
|
+
# @api public
|
2
11
|
class Store < ActiveSupport::OrderedOptions
|
3
12
|
def initialize(initial_data = nil, opts = {})
|
4
13
|
@recursive = opts[:recursive] || false
|
@@ -8,10 +8,10 @@ module Lookbook
|
|
8
8
|
attr_accessor :path, :content
|
9
9
|
attr_reader :children
|
10
10
|
|
11
|
-
def initialize(path = nil, content = nil,
|
11
|
+
def initialize(path = nil, content = nil, priority: 10000)
|
12
12
|
@path = path.to_s
|
13
13
|
@content = content
|
14
|
-
@
|
14
|
+
@priority = priority
|
15
15
|
@children = []
|
16
16
|
end
|
17
17
|
|
@@ -27,8 +27,8 @@ module Lookbook
|
|
27
27
|
content_value(:label, name.titleize)
|
28
28
|
end
|
29
29
|
|
30
|
-
def
|
31
|
-
content_value(:
|
30
|
+
def priority
|
31
|
+
content_value(:priority, @priority)
|
32
32
|
end
|
33
33
|
|
34
34
|
def type
|
@@ -39,8 +39,8 @@ module Lookbook
|
|
39
39
|
path.split("/").size
|
40
40
|
end
|
41
41
|
|
42
|
-
def add_child(name, content = nil,
|
43
|
-
children << TreeNode.new("#{path}/#{name}", content,
|
42
|
+
def add_child(name, content = nil, priority: 10000)
|
43
|
+
children << TreeNode.new("#{path}/#{name}", content, priority: priority)
|
44
44
|
end
|
45
45
|
|
46
46
|
def has_child?(name)
|
@@ -69,7 +69,7 @@ module Lookbook
|
|
69
69
|
if content?
|
70
70
|
content <=> (other.content? ? other.content : other)
|
71
71
|
else
|
72
|
-
[
|
72
|
+
[priority, label] <=> [other.priority, other.label]
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
@@ -15,7 +15,7 @@ module Lookbook
|
|
15
15
|
|
16
16
|
segments = [*directory_path&.split("/"), file_name].compact
|
17
17
|
stripped_segments = segments.map! do |segment|
|
18
|
-
|
18
|
+
PriorityPrefixParser.call(segment).last.tr("-", "_")
|
19
19
|
end
|
20
20
|
|
21
21
|
to_path(stripped_segments)
|
@@ -41,6 +41,12 @@ module Lookbook
|
|
41
41
|
def strip_slashes(path)
|
42
42
|
path.to_s.gsub(/\A\/|\/\z/, "")
|
43
43
|
end
|
44
|
+
|
45
|
+
def determine_full_path(rel_path, search_dirs = [])
|
46
|
+
base_path = search_dirs.detect { |p| Dir["#{p}/#{rel_path}"].first }
|
47
|
+
path = Dir["#{base_path}/#{rel_path}"].first
|
48
|
+
Pathname(path) if path
|
49
|
+
end
|
44
50
|
end
|
45
51
|
end
|
46
52
|
end
|
@@ -7,10 +7,18 @@ module Lookbook
|
|
7
7
|
PathUtils.strip_slashes(id_str).tr("/", "-").gsub("--", "-")
|
8
8
|
end
|
9
9
|
|
10
|
+
def temp_id(prefix: nil)
|
11
|
+
[prefix, (Time.now.to_f * 1000).to_i + rand(0..100)].compact.join("-")
|
12
|
+
end
|
13
|
+
|
10
14
|
def name(str)
|
11
15
|
str.to_s.parameterize.tr("-", "_")
|
12
16
|
end
|
13
17
|
|
18
|
+
def symbolize_name(str)
|
19
|
+
name(str).to_sym
|
20
|
+
end
|
21
|
+
|
14
22
|
def value_or_fallback(value, fallback = nil, &block)
|
15
23
|
if value.nil?
|
16
24
|
fallback_block = block || proc { fallback }
|
@@ -1,13 +1,13 @@
|
|
1
1
|
module Lookbook
|
2
|
-
class
|
3
|
-
|
2
|
+
class PriorityTag < YardTag
|
3
|
+
DEFAULT_PRIORITY = 100000
|
4
4
|
|
5
5
|
def value
|
6
6
|
if text.present?
|
7
7
|
int = text.to_i
|
8
|
-
(int == 0) ?
|
8
|
+
(int == 0) ? DEFAULT_PRIORITY : int
|
9
9
|
else
|
10
|
-
|
10
|
+
DEFAULT_PRIORITY
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
@@ -7,6 +7,9 @@ module Lookbook
|
|
7
7
|
raise NameError.new "'custom' is a reserved tag name and cannot be used"
|
8
8
|
end
|
9
9
|
|
10
|
+
# Handle aliasing of removed `@component` tags
|
11
|
+
tag_name = "renders" if tag_name == "component"
|
12
|
+
|
10
13
|
begin
|
11
14
|
tag_class = "Lookbook::#{tag_name.camelize}Tag".constantize
|
12
15
|
tag_class.new(text)
|