lookbook 1.3.3 → 1.4.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 -11
- data/app/assets/lookbook/css/themes/blue.css +1 -1
- data/app/assets/lookbook/css/themes/green.css +66 -0
- data/app/assets/lookbook/css/themes/indigo.css +1 -1
- data/app/assets/lookbook/css/themes/rose.css +66 -0
- data/app/assets/lookbook/css/themes/zinc.css +1 -1
- data/app/components/lookbook/base_component.rb +2 -2
- data/app/components/lookbook/code/component.rb +2 -2
- data/app/components/lookbook/header/component.html.erb +1 -1
- data/app/components/lookbook/inspector_panel/component.rb +1 -1
- data/app/components/lookbook/nav/component.rb +8 -15
- data/app/components/lookbook/nav/directory/component.html.erb +26 -0
- data/app/components/lookbook/nav/directory/component.rb +4 -0
- data/app/components/lookbook/nav/{item → entity}/component.html.erb +5 -7
- data/app/components/lookbook/nav/entity/component.rb +49 -0
- data/app/components/lookbook/nav/item/component.css +15 -0
- data/app/components/lookbook/nav/item/component.js +4 -0
- data/app/components/lookbook/nav/item/component.rb +13 -56
- data/app/components/lookbook/tag_component.rb +1 -1
- data/app/components/lookbook/viewport/component.rb +1 -1
- data/app/controllers/concerns/lookbook/targetable_concern.rb +13 -38
- data/app/controllers/lookbook/application_controller.rb +9 -7
- data/app/controllers/lookbook/page_controller.rb +2 -2
- data/app/controllers/lookbook/pages_controller.rb +9 -15
- data/app/helpers/lookbook/application_helper.rb +2 -2
- data/app/helpers/lookbook/page_helper.rb +7 -4
- data/app/views/layouts/lookbook/application.html.erb +3 -4
- data/app/views/layouts/lookbook/page.html.erb +2 -2
- data/app/views/layouts/lookbook/shell.html.erb +2 -2
- data/app/views/layouts/lookbook/skeleton.html.erb +7 -7
- data/app/views/lookbook/index.html.erb +3 -3
- data/app/views/lookbook/inspector/panels/_params.html.erb +2 -2
- data/config/languages.yml +41 -0
- data/config/panels.yml +1 -1
- data/config/tags.yml +4 -0
- data/lib/lookbook/engine.rb +65 -43
- data/lib/lookbook/entities/collections/component_collection.rb +4 -0
- data/lib/lookbook/entities/collections/concerns/hierarchical_collection.rb +27 -0
- data/lib/lookbook/entities/collections/entity_collection.rb +66 -0
- data/lib/lookbook/entities/collections/page_collection.rb +30 -0
- data/lib/lookbook/entities/collections/preview_collection.rb +35 -0
- data/lib/lookbook/entities/collections/preview_example_collection.rb +9 -0
- data/lib/lookbook/entities/component.rb +31 -0
- data/lib/lookbook/entities/concerns/annotatable.rb +58 -0
- data/lib/lookbook/entities/concerns/inspectable.rb +44 -0
- data/lib/lookbook/entities/concerns/locatable.rb +73 -0
- data/lib/lookbook/entities/concerns/navigable.rb +27 -0
- data/lib/lookbook/entities/entity.rb +48 -0
- data/lib/lookbook/entities/page.rb +80 -0
- data/lib/lookbook/entities/page_section.rb +43 -0
- data/lib/lookbook/entities/preview.rb +87 -0
- data/lib/lookbook/entities/preview_example.rb +91 -0
- data/lib/lookbook/entities/preview_group.rb +48 -0
- data/lib/lookbook/file_watcher.rb +1 -1
- data/lib/lookbook/lang.rb +12 -35
- data/lib/lookbook/param.rb +2 -2
- data/lib/lookbook/preview_parser.rb +1 -1
- data/lib/lookbook/rendered_example.rb +37 -0
- data/lib/lookbook/services/code/code_beautifier.rb +1 -1
- data/lib/lookbook/services/code/code_highlighter.rb +1 -1
- data/lib/lookbook/services/code/code_indenter.rb +14 -0
- data/lib/lookbook/services/data/resolvers/data_resolver.rb +2 -2
- data/lib/lookbook/services/data/resolvers/method_resolver.rb +1 -1
- data/lib/lookbook/services/entities/entity_tree_builder.rb +45 -0
- data/lib/lookbook/services/position_prefix_parser.rb +16 -0
- data/lib/lookbook/stores/config_store.rb +1 -1
- data/lib/lookbook/stores/panel_store.rb +2 -2
- data/lib/lookbook/support/store.rb +1 -34
- data/lib/lookbook/support/tree_node.rb +83 -0
- data/lib/lookbook/support/utils/path_utils.rb +26 -2
- data/lib/lookbook/support/utils/utils.rb +24 -0
- data/lib/lookbook/tags/component_tag.rb +6 -0
- data/lib/lookbook/tags/custom_tag.rb +2 -0
- data/lib/lookbook/tags/id_tag.rb +1 -1
- data/lib/lookbook/tags/logical_path_tag.rb +3 -0
- data/lib/lookbook/tags/param_tag.rb +2 -0
- data/lib/lookbook/tags/position_tag.rb +1 -1
- data/lib/lookbook/tags/source_tag.rb +7 -0
- data/lib/lookbook/tags/yard_tag.rb +35 -7
- data/lib/lookbook/theme.rb +8 -0
- data/lib/lookbook/version.rb +1 -1
- data/lib/lookbook.rb +11 -7
- data/public/lookbook-assets/css/lookbook.css +55 -125
- data/public/lookbook-assets/css/lookbook.css.map +1 -1
- data/public/lookbook-assets/css/themes/blue.css.map +1 -1
- data/public/lookbook-assets/css/themes/green.css +68 -0
- data/public/lookbook-assets/css/themes/green.css.map +1 -0
- data/public/lookbook-assets/css/themes/indigo.css.map +1 -1
- data/public/lookbook-assets/css/themes/rose.css +68 -0
- data/public/lookbook-assets/css/themes/rose.css.map +1 -0
- data/public/lookbook-assets/css/themes/zinc.css.map +1 -1
- data/public/lookbook-assets/js/embed.js +9 -0
- data/public/lookbook-assets/js/embed.js.map +1 -1
- data/public/lookbook-assets/js/lookbook.js +288 -565
- data/public/lookbook-assets/js/lookbook.js.map +1 -1
- metadata +41 -18
- data/lib/lookbook/collection.rb +0 -161
- data/lib/lookbook/component.rb +0 -34
- data/lib/lookbook/entity.rb +0 -47
- data/lib/lookbook/page.rb +0 -194
- data/lib/lookbook/page_collection.rb +0 -19
- data/lib/lookbook/page_section.rb +0 -29
- data/lib/lookbook/preview.rb +0 -181
- data/lib/lookbook/preview_collection.rb +0 -23
- data/lib/lookbook/preview_example.rb +0 -93
- data/lib/lookbook/preview_group.rb +0 -58
- data/lib/lookbook/source_inspector.rb +0 -76
- data/lib/lookbook/support/utils/attribute_utils.rb +0 -14
- data/lib/lookbook/utils.rb +0 -65
@@ -0,0 +1,31 @@
|
|
1
|
+
module Lookbook
|
2
|
+
class Component < Entity
|
3
|
+
include Locatable
|
4
|
+
|
5
|
+
attr_reader :component_class
|
6
|
+
|
7
|
+
def initialize(component_class)
|
8
|
+
@component_class = component_class
|
9
|
+
@file_path = "#{Engine.component_paths.first}/#{name.underscore}.rb"
|
10
|
+
@base_directories = Engine.component_paths
|
11
|
+
@lookup_path = PathUtils.to_lookup_path(relative_file_path)
|
12
|
+
end
|
13
|
+
|
14
|
+
def name
|
15
|
+
component_class.name
|
16
|
+
end
|
17
|
+
|
18
|
+
def template_file_path
|
19
|
+
Dir.glob("#{directory_path}/#{file_name(true)}.*.erb").first
|
20
|
+
end
|
21
|
+
|
22
|
+
def inline?
|
23
|
+
template_file_path.present?
|
24
|
+
end
|
25
|
+
|
26
|
+
def template_path
|
27
|
+
Lookbook.logger.warn "The `template_path` method has been deprecated - use `template_file_path` instead. `template_file_path` will be removed in v2.0"
|
28
|
+
template_file_path
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Lookbook
|
2
|
+
module Annotatable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
delegate :has_tag?, to: :code_object
|
7
|
+
|
8
|
+
def notes
|
9
|
+
code_object.docstring.to_s.strip
|
10
|
+
end
|
11
|
+
|
12
|
+
def tags(name = nil)
|
13
|
+
code_object.tags(name)
|
14
|
+
end
|
15
|
+
|
16
|
+
def tag(name = nil)
|
17
|
+
tags(name).first
|
18
|
+
end
|
19
|
+
|
20
|
+
protected
|
21
|
+
|
22
|
+
attr_reader :code_object
|
23
|
+
|
24
|
+
def fetch_config(key, fallback = nil, &block)
|
25
|
+
value = case key.to_sym
|
26
|
+
when :components
|
27
|
+
components_config
|
28
|
+
when :display_options
|
29
|
+
display_options_config
|
30
|
+
else
|
31
|
+
tag(key).value if has_tag?(key)
|
32
|
+
end
|
33
|
+
|
34
|
+
Utils.value_or_fallback(value, fallback, &block)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def components_config
|
40
|
+
return unless has_tag?(:component)
|
41
|
+
|
42
|
+
Array(tags(:component)).map(&:value).compact
|
43
|
+
end
|
44
|
+
|
45
|
+
def display_options_config
|
46
|
+
return unless has_tag?(:display)
|
47
|
+
|
48
|
+
# Dynamic params set at the entity level are
|
49
|
+
# not (yet?) supported so filter them out.
|
50
|
+
display_tags = tags(:display).select do |tag|
|
51
|
+
!tag.value.is_a?(Hash) && !tag.value.is_a?(Array)
|
52
|
+
end
|
53
|
+
|
54
|
+
display_tags.map { |tag| [tag.key.to_sym, tag.value] }.to_h
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Lookbook
|
2
|
+
module Inspectable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
def source
|
7
|
+
source_code = if custom_source?
|
8
|
+
File.read(source_file_path)
|
9
|
+
else
|
10
|
+
src = CodeIndenter.call(code_object.source)
|
11
|
+
begin
|
12
|
+
send(:format_source, src)
|
13
|
+
rescue NoMethodError
|
14
|
+
src
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
source_code.strip_heredoc.strip
|
19
|
+
end
|
20
|
+
|
21
|
+
def source_lang
|
22
|
+
custom_source? ? Lang.guess(source_file_path, :ruby) : Lang.find(:ruby)
|
23
|
+
end
|
24
|
+
|
25
|
+
def custom_source?
|
26
|
+
source_file_path.present?
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
attr_reader :code_object
|
32
|
+
|
33
|
+
def source_file_path
|
34
|
+
@_source_path ||= if code_object.has_tag?(:source)
|
35
|
+
source_path = code_object.tag(:source).value
|
36
|
+
unless source_path.present? && File.exist?(source_path)
|
37
|
+
raise LookbookError, "Could not find source file '#{source_path}'"
|
38
|
+
end
|
39
|
+
source_path
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Lookbook
|
2
|
+
module Locatable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
attr_reader :file_path, :base_directories
|
7
|
+
|
8
|
+
def file_name(strip_ext = false)
|
9
|
+
basename = file_pathname.basename
|
10
|
+
(strip_ext ? basename.to_s.split(".").first : basename).to_s
|
11
|
+
end
|
12
|
+
|
13
|
+
def file_name_base
|
14
|
+
@_file_name_slug ||= file_name(true).gsub(/(_component_preview|component_preview|preview)$/, "")
|
15
|
+
end
|
16
|
+
|
17
|
+
def file_extension
|
18
|
+
@_file_extension ||= file_pathname.extname
|
19
|
+
end
|
20
|
+
|
21
|
+
def directory_path
|
22
|
+
@_directory_path ||= Pathname(file_pathname.dirname)
|
23
|
+
end
|
24
|
+
|
25
|
+
def relative_file_path
|
26
|
+
@_relative_file_path ||= file_pathname.relative_path_from(base_directory)
|
27
|
+
end
|
28
|
+
|
29
|
+
def relative_directory_path
|
30
|
+
@_relative_directory_path ||= directory_path.relative_path_from(base_directory)
|
31
|
+
end
|
32
|
+
|
33
|
+
def last_modified
|
34
|
+
@_last_modified ||= File.mtime(file_path)
|
35
|
+
end
|
36
|
+
|
37
|
+
def logical_path
|
38
|
+
return @_logical_path if @_logical_path
|
39
|
+
|
40
|
+
directory = fetch_config(:logical_path) { relative_directory_path.to_s }
|
41
|
+
@_logical_path ||= PathUtils.to_path(directory, file_name_base)
|
42
|
+
end
|
43
|
+
|
44
|
+
def full_path
|
45
|
+
Lookbook.logger.warn "The `full_path` method has been deprecated - use `file_path` instead. `full_path` will be removed in v2.0"
|
46
|
+
file_path
|
47
|
+
end
|
48
|
+
|
49
|
+
def rel_path
|
50
|
+
Lookbook.logger.warn "The `rel_path` method has been deprecated - use `relative_file_path` instead. `rel_path` will be removed in v2.0"
|
51
|
+
relative_file_path
|
52
|
+
end
|
53
|
+
|
54
|
+
def dir_path
|
55
|
+
Lookbook.logger.warn "The `dir_path` method has been deprecated - use `directory_path` instead. `dir_path` will be removed in v2.0"
|
56
|
+
directory_path
|
57
|
+
end
|
58
|
+
|
59
|
+
protected
|
60
|
+
|
61
|
+
def file_pathname
|
62
|
+
Pathname(file_path)
|
63
|
+
end
|
64
|
+
|
65
|
+
def base_directory
|
66
|
+
return @_base_directory if @_base_directory
|
67
|
+
|
68
|
+
directories = [Rails.root, *Array(base_directories)].map(&:to_s).sort_by(&:length).reverse
|
69
|
+
@_base_directory ||= directories.first { |dir| file_path.start_with?(dir) }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Lookbook
|
2
|
+
module Navigable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
def hidden?
|
7
|
+
fetch_config(:hidden, false)
|
8
|
+
end
|
9
|
+
|
10
|
+
def visible?
|
11
|
+
!hidden?
|
12
|
+
end
|
13
|
+
|
14
|
+
def position
|
15
|
+
if @position_prefixes && respond_to?(:file_name)
|
16
|
+
PositionPrefixParser.call(file_name).first || 10000
|
17
|
+
else
|
18
|
+
fetch_config(:position, 10000)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def depth
|
23
|
+
path.split("/").size
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Lookbook
|
2
|
+
class Entity
|
3
|
+
include Lookbook::Engine.routes.url_helpers
|
4
|
+
|
5
|
+
def initialize(lookup_path = nil)
|
6
|
+
@lookup_path = lookup_path
|
7
|
+
end
|
8
|
+
|
9
|
+
def id
|
10
|
+
Utils.id(fetch_config(:id) { lookup_path.tr("/", "-") })
|
11
|
+
end
|
12
|
+
|
13
|
+
def name
|
14
|
+
@_name ||= Utils.name(File.basename(@lookup_path))
|
15
|
+
end
|
16
|
+
|
17
|
+
def label
|
18
|
+
@_label ||= fetch_config(:label) { name.titleize }
|
19
|
+
end
|
20
|
+
|
21
|
+
def lookup_path
|
22
|
+
return @_lookup_path if @_lookup_path
|
23
|
+
|
24
|
+
directory = fetch_config(:logical_path) do
|
25
|
+
dir = File.dirname(@lookup_path)
|
26
|
+
dir if !dir.start_with?(".")
|
27
|
+
end
|
28
|
+
@_lookup_path ||= PathUtils.strip_slashes(PathUtils.to_path(directory, name))
|
29
|
+
end
|
30
|
+
|
31
|
+
def url_path
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
|
35
|
+
def type
|
36
|
+
@_type ||= self.class.name.demodulize.underscore.downcase.to_sym
|
37
|
+
end
|
38
|
+
|
39
|
+
alias_method :path, :lookup_path
|
40
|
+
alias_method :logical_path, :lookup_path
|
41
|
+
|
42
|
+
protected
|
43
|
+
|
44
|
+
def fetch_config(key, fallback = nil, &block)
|
45
|
+
Utils.value_or_fallback(nil, fallback, &block)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Lookbook
|
2
|
+
class Page < Entity
|
3
|
+
include Locatable
|
4
|
+
include Navigable
|
5
|
+
|
6
|
+
attr_reader :content, :sections
|
7
|
+
|
8
|
+
def initialize(file_path)
|
9
|
+
@file_path = Pathname(file_path)
|
10
|
+
@base_directories = Engine.page_paths
|
11
|
+
@lookup_path = PathUtils.to_lookup_path(relative_file_path)
|
12
|
+
@frontmatter, @content = FrontmatterExtractor.call(file_contents)
|
13
|
+
@position_prefixes = true
|
14
|
+
@sections = []
|
15
|
+
end
|
16
|
+
|
17
|
+
def title
|
18
|
+
@_title ||= fetch_config(:title, label)
|
19
|
+
end
|
20
|
+
|
21
|
+
def landing?
|
22
|
+
@_landing ||= fetch_config(:landing, false)
|
23
|
+
end
|
24
|
+
|
25
|
+
def markdown?
|
26
|
+
@_markdown ||= fetch_config(:markdown) { file_path.to_s.match?(/(.*)\.md\.(.*)$/) }
|
27
|
+
end
|
28
|
+
|
29
|
+
def header?
|
30
|
+
@_header ||= fetch_config(:header, true)
|
31
|
+
end
|
32
|
+
|
33
|
+
def footer?
|
34
|
+
@_footer ||= fetch_config(:footer, true)
|
35
|
+
end
|
36
|
+
|
37
|
+
def data
|
38
|
+
return @_data if @_data
|
39
|
+
|
40
|
+
config_data = fetch_config(:data, {})
|
41
|
+
@_data ||= config_data.is_a?(Hash) ? Store.new(config_data) : config_data
|
42
|
+
end
|
43
|
+
|
44
|
+
def search_terms
|
45
|
+
label
|
46
|
+
end
|
47
|
+
|
48
|
+
def url_path
|
49
|
+
lookbook_page_path(path)
|
50
|
+
end
|
51
|
+
|
52
|
+
def add_section(section)
|
53
|
+
@sections << section
|
54
|
+
@sections.sort_by! { |section| [section.position, section.label] }
|
55
|
+
end
|
56
|
+
|
57
|
+
def method_missing(method_name, *args, &block)
|
58
|
+
method_name.to_s.end_with?("=") ? super : frontmatter.fetch(method_name, nil)
|
59
|
+
end
|
60
|
+
|
61
|
+
def respond_to_missing?(method_name, include_private = false)
|
62
|
+
frontmatter.key?(method_name) || super
|
63
|
+
end
|
64
|
+
|
65
|
+
protected
|
66
|
+
|
67
|
+
def fetch_config(key, fallback = nil, &block)
|
68
|
+
value = frontmatter[key]
|
69
|
+
Utils.value_or_fallback(value, fallback, &block)
|
70
|
+
end
|
71
|
+
|
72
|
+
def file_contents
|
73
|
+
@_file_contents ||= File.read(file_path)
|
74
|
+
end
|
75
|
+
|
76
|
+
def frontmatter
|
77
|
+
@_merged_frontmatter ||= Lookbook.config.page_options.deep_merge(@frontmatter.to_h).deep_symbolize_keys
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Lookbook
|
2
|
+
class PageSection < Page
|
3
|
+
attr_accessor :parent
|
4
|
+
|
5
|
+
def initialize(file_path)
|
6
|
+
@file_path = Pathname(file_path)
|
7
|
+
@parent = nil
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
def name
|
12
|
+
Utils.name(name_parts[:name])
|
13
|
+
end
|
14
|
+
|
15
|
+
def lookup_path
|
16
|
+
directory = if relative_directory_path.present? && !relative_directory_path.to_s.start_with?(".")
|
17
|
+
relative_directory_path
|
18
|
+
end
|
19
|
+
|
20
|
+
path = PathUtils.to_path(directory, name_parts[:parent_name])
|
21
|
+
PathUtils.to_lookup_path(path)
|
22
|
+
end
|
23
|
+
|
24
|
+
def landing?
|
25
|
+
false
|
26
|
+
end
|
27
|
+
|
28
|
+
def url_path
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
|
32
|
+
alias_method :page, :parent
|
33
|
+
|
34
|
+
protected
|
35
|
+
|
36
|
+
def name_parts
|
37
|
+
return @_name_parts if @_name_parts
|
38
|
+
|
39
|
+
matches = file_name(true).match(/(?<parent_name>.*)\[(?<name>.*)\]/)
|
40
|
+
@_name_parts ||= {name: matches[:name], parent_name: matches[:parent_name]}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Lookbook
|
2
|
+
class Preview < Entity
|
3
|
+
include Annotatable
|
4
|
+
include Locatable
|
5
|
+
include Navigable
|
6
|
+
|
7
|
+
delegate :render_args, to: :preview_class
|
8
|
+
|
9
|
+
attr_reader :preview_class
|
10
|
+
|
11
|
+
def initialize(code_object)
|
12
|
+
@code_object = code_object
|
13
|
+
@preview_class = code_object.path.constantize
|
14
|
+
@file_path = Pathname(code_object.file)
|
15
|
+
@base_directories = Engine.preview_paths
|
16
|
+
|
17
|
+
cleaned_path = relative_file_path.to_s
|
18
|
+
.gsub(/\/(component_preview|preview)(\..*)$/, "")
|
19
|
+
.gsub(/_component_preview(\..*)$/, "")
|
20
|
+
|
21
|
+
@lookup_path = PathUtils.to_lookup_path(cleaned_path)
|
22
|
+
end
|
23
|
+
|
24
|
+
def examples
|
25
|
+
@_examples ||= PreviewExampleCollection.new(load_examples)
|
26
|
+
end
|
27
|
+
|
28
|
+
def example(example_name)
|
29
|
+
examples.find { |m| m.name == example_name.to_s }
|
30
|
+
end
|
31
|
+
|
32
|
+
def visible_examples
|
33
|
+
@_visible_examples ||= PreviewExampleCollection.new(examples.select(&:visible?))
|
34
|
+
end
|
35
|
+
|
36
|
+
def default_example
|
37
|
+
visible_examples.first
|
38
|
+
end
|
39
|
+
|
40
|
+
def components
|
41
|
+
@_components ||= ComponentCollection.new(examples.flat_map(&:components).uniq(&:path))
|
42
|
+
end
|
43
|
+
|
44
|
+
def component
|
45
|
+
components.first
|
46
|
+
end
|
47
|
+
|
48
|
+
def display_options
|
49
|
+
global_options = Lookbook.config.preview_display_options
|
50
|
+
global_options.deep_merge(fetch_config(:display_options, {}))
|
51
|
+
end
|
52
|
+
|
53
|
+
def layout
|
54
|
+
preview_class.instance_variable_get(:@layout)
|
55
|
+
end
|
56
|
+
|
57
|
+
def url_path
|
58
|
+
lookbook_inspect_path(path)
|
59
|
+
end
|
60
|
+
|
61
|
+
def preview_class_name
|
62
|
+
preview_class.name
|
63
|
+
end
|
64
|
+
|
65
|
+
def guess_components
|
66
|
+
[preview_class.name.chomp("Preview").constantize]
|
67
|
+
rescue
|
68
|
+
[]
|
69
|
+
end
|
70
|
+
|
71
|
+
protected
|
72
|
+
|
73
|
+
def load_examples
|
74
|
+
return example_entities unless code_object.groups.any?
|
75
|
+
|
76
|
+
example_entities.group_by(&:group).flat_map do |group_name, grouped_examples|
|
77
|
+
group_name.nil? ? grouped_examples : PreviewGroup.new(group_name.presence || label.pluralize, grouped_examples, self)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def example_entities
|
82
|
+
public_methods = preview_class.public_instance_methods(false)
|
83
|
+
method_objects = code_object.meths.select { |m| public_methods.include?(m.name) }
|
84
|
+
method_objects.map { |code_object| PreviewExample.new(code_object, self) }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module Lookbook
|
2
|
+
class PreviewExample < Entity
|
3
|
+
include Inspectable
|
4
|
+
include Annotatable
|
5
|
+
include Navigable
|
6
|
+
|
7
|
+
delegate :group, to: :code_object
|
8
|
+
|
9
|
+
attr_reader :preview
|
10
|
+
|
11
|
+
def initialize(code_object, preview)
|
12
|
+
@code_object = code_object
|
13
|
+
@preview = preview
|
14
|
+
@lookup_path = "#{parent.lookup_path}/#{name}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def id
|
18
|
+
@_id ||= Utils.id(fetch_config(:id) { "#{parent.id}-#{code_object.name}" })
|
19
|
+
end
|
20
|
+
|
21
|
+
def name
|
22
|
+
@_name ||= Utils.name(code_object.name)
|
23
|
+
end
|
24
|
+
|
25
|
+
def display_options
|
26
|
+
parent.display_options.merge(fetch_config(:display_options, {}))
|
27
|
+
end
|
28
|
+
|
29
|
+
def components
|
30
|
+
@_components ||= ComponentCollection.new(load_components)
|
31
|
+
end
|
32
|
+
|
33
|
+
def component
|
34
|
+
components.first
|
35
|
+
end
|
36
|
+
|
37
|
+
def examples
|
38
|
+
[self]
|
39
|
+
end
|
40
|
+
|
41
|
+
def template_source(template_path)
|
42
|
+
source_path = template_file_path(template_path)
|
43
|
+
source_path ? File.read(source_path) : nil
|
44
|
+
end
|
45
|
+
|
46
|
+
def template_lang(template_path)
|
47
|
+
path = template_file_path(template_path)
|
48
|
+
Lookbook::Lang.guess(path) || Lookbook::Lang.find(:html)
|
49
|
+
end
|
50
|
+
|
51
|
+
def search_terms
|
52
|
+
[parent.label, label]
|
53
|
+
end
|
54
|
+
|
55
|
+
def url_path
|
56
|
+
lookbook_inspect_path(path)
|
57
|
+
end
|
58
|
+
|
59
|
+
def type
|
60
|
+
:example
|
61
|
+
end
|
62
|
+
|
63
|
+
alias_method :parent, :preview
|
64
|
+
alias_method :lang, :source_lang
|
65
|
+
|
66
|
+
protected
|
67
|
+
|
68
|
+
def format_source(source)
|
69
|
+
source.sub(/^def \w+\s?(\([^)]+\))?/m, "").split("\n")[0..-2].join("\n")
|
70
|
+
end
|
71
|
+
|
72
|
+
def template_file_path(template_path)
|
73
|
+
return full_template_path(template_path) if respond_to?(:full_template_path, true)
|
74
|
+
|
75
|
+
template_path = template_path.to_s.sub(/\..*$/, "")
|
76
|
+
base_path = Engine.preview_paths.detect do |p|
|
77
|
+
Dir["#{p}/#{template_path}.html.*"].first
|
78
|
+
end
|
79
|
+
path = Dir["#{base_path}/#{template_path}.html.*"].first
|
80
|
+
Pathname(path) if path
|
81
|
+
end
|
82
|
+
|
83
|
+
def load_components
|
84
|
+
component_classes = [*fetch_config(:components, []), *preview.send(:fetch_config, :components, [])]
|
85
|
+
component_classes = preview.guess_components if component_classes.empty?
|
86
|
+
|
87
|
+
components = component_classes.map { |klass| Component.new(klass) }
|
88
|
+
components.uniq(&:path)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Lookbook
|
2
|
+
class PreviewGroup < Entity
|
3
|
+
include Navigable
|
4
|
+
|
5
|
+
attr_reader :examples, :preview
|
6
|
+
|
7
|
+
def initialize(name, examples, preview)
|
8
|
+
@name = Utils.name(name)
|
9
|
+
@examples = PreviewExampleCollection.new(examples)
|
10
|
+
@preview = preview
|
11
|
+
@lookup_path = "#{parent.lookup_path}/#{@name}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def display_options
|
15
|
+
merged = {}
|
16
|
+
examples.to_a.reverse.map do |example|
|
17
|
+
merged.merge!(example.display_options)
|
18
|
+
end
|
19
|
+
merged
|
20
|
+
end
|
21
|
+
|
22
|
+
def components
|
23
|
+
@_components ||= ComponentCollection.new(examples.flat_map(&:components).uniq(&:path))
|
24
|
+
end
|
25
|
+
|
26
|
+
def search_terms
|
27
|
+
[parent.label, label]
|
28
|
+
end
|
29
|
+
|
30
|
+
def tags(tag_name = nil)
|
31
|
+
examples.flat_map { |example| example.tags(tag_name) }
|
32
|
+
end
|
33
|
+
|
34
|
+
def tag(tag_name = nil)
|
35
|
+
tags(tag_name).first
|
36
|
+
end
|
37
|
+
|
38
|
+
def url_path
|
39
|
+
lookbook_inspect_path(path)
|
40
|
+
end
|
41
|
+
|
42
|
+
def type
|
43
|
+
:group
|
44
|
+
end
|
45
|
+
|
46
|
+
alias_method :parent, :preview
|
47
|
+
end
|
48
|
+
end
|
data/lib/lookbook/lang.rb
CHANGED
@@ -1,46 +1,23 @@
|
|
1
1
|
module Lookbook
|
2
2
|
module Lang
|
3
3
|
class << self
|
4
|
-
|
5
|
-
|
6
|
-
name: "ruby",
|
7
|
-
ext: ".rb",
|
8
|
-
label: "Ruby",
|
9
|
-
comment: "# %s"
|
10
|
-
},
|
11
|
-
{
|
12
|
-
name: "html",
|
13
|
-
ext: ".html",
|
14
|
-
label: "HTML",
|
15
|
-
comment: "<!-- %s -->"
|
16
|
-
},
|
17
|
-
{
|
18
|
-
name: "erb",
|
19
|
-
ext: ".erb",
|
20
|
-
label: "ERB",
|
21
|
-
comment: "<%%# %s %%>"
|
22
|
-
},
|
23
|
-
{
|
24
|
-
name: "haml",
|
25
|
-
ext: ".haml",
|
26
|
-
label: "Haml",
|
27
|
-
comment: "<!-- %s -->"
|
28
|
-
},
|
29
|
-
{
|
30
|
-
name: "slim",
|
31
|
-
ext: ".slim",
|
32
|
-
label: "Slim",
|
33
|
-
comment: "<!-- %s -->"
|
34
|
-
}
|
35
|
-
]
|
4
|
+
CONFIG_FILE = "config/languages.yml"
|
5
|
+
LANGUAGES = [] # retained for backwards compatability
|
36
6
|
|
37
7
|
def find(name)
|
38
|
-
|
8
|
+
languages.find { |l| l[:name] == name.to_s }
|
39
9
|
end
|
40
10
|
|
41
|
-
def guess(path)
|
11
|
+
def guess(path, fallback_name = nil)
|
42
12
|
ext = File.extname(path)
|
43
|
-
|
13
|
+
lang = languages.find { |l| l[:ext] == ext }
|
14
|
+
lang || (find(fallback_name) if fallback_name)
|
15
|
+
end
|
16
|
+
|
17
|
+
protected
|
18
|
+
|
19
|
+
def languages
|
20
|
+
@_languages ||= [*ConfigLoader.call(CONFIG_FILE).definitions, *LANGUAGES]
|
44
21
|
end
|
45
22
|
end
|
46
23
|
end
|