lookbook 1.3.4 → 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 +1 -1
- data/app/assets/lookbook/css/themes/indigo.css +1 -1
- data/app/assets/lookbook/css/themes/rose.css +1 -1
- data/app/assets/lookbook/css/themes/zinc.css +1 -1
- data/app/components/lookbook/code/component.rb +2 -4
- 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/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 +1 -1
- 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_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/support/store.rb +0 -33
- 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/source_tag.rb +7 -0
- data/lib/lookbook/tags/yard_tag.rb +35 -7
- data/lib/lookbook/version.rb +1 -1
- data/lib/lookbook.rb +11 -7
- data/public/lookbook-assets/css/lookbook.css +33 -21
- data/public/lookbook-assets/css/lookbook.css.map +1 -1
- data/public/lookbook-assets/js/lookbook.js +64 -63
- data/public/lookbook-assets/js/lookbook.js.map +1 -1
- metadata +35 -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
@@ -21,9 +21,8 @@
|
|
21
21
|
<% layout.pane class: "overflow-hidden" do %>
|
22
22
|
<%= lookbook_render :nav,
|
23
23
|
id: "previews-nav",
|
24
|
-
|
25
|
-
alpine_data: "$store.nav.previews"
|
26
|
-
collapse_singles: true do |nav| %>
|
24
|
+
tree: @previews.to_tree,
|
25
|
+
alpine_data: "$store.nav.previews" do |nav| %>
|
27
26
|
<%= nav.toolbar do |toolbar| %>
|
28
27
|
<% toolbar.section padded: true do %>
|
29
28
|
<h4 class="pt-1">Previews</h4>
|
@@ -45,7 +44,7 @@
|
|
45
44
|
<% layout.pane class: "overflow-hidden" do %>
|
46
45
|
<%= lookbook_render :nav,
|
47
46
|
id: "pages-nav",
|
48
|
-
|
47
|
+
tree: @pages.to_tree,
|
49
48
|
alpine_data: "$store.nav.pages" do |nav| %>
|
50
49
|
<%= nav.toolbar do |toolbar| %>
|
51
50
|
<% toolbar.section padded: true do %>
|
@@ -16,7 +16,7 @@
|
|
16
16
|
size: :lg,
|
17
17
|
icon: :chevron_left,
|
18
18
|
tooltip: "Previous page",
|
19
|
-
href: lookbook_page_path(@previous_page.
|
19
|
+
href: lookbook_page_path(@previous_page.path),
|
20
20
|
class: "pr-0.5 bg-transparent" %>
|
21
21
|
<% else %>
|
22
22
|
<%= lookbook_render :button,
|
@@ -31,7 +31,7 @@
|
|
31
31
|
size: :lg,
|
32
32
|
icon: :chevron_right,
|
33
33
|
tooltip: "Next page",
|
34
|
-
href: lookbook_page_path(@next_page.
|
34
|
+
href: lookbook_page_path(@next_page.path),
|
35
35
|
class: "pl-0.5 bg-transparent" %>
|
36
36
|
<% else %>
|
37
37
|
<%= lookbook_render :button,
|
@@ -13,8 +13,8 @@
|
|
13
13
|
</style>
|
14
14
|
<% end %>
|
15
15
|
|
16
|
-
<%= lookbook_render :header, id: "app-header", debug_menu: config.debug_menu do |header| %>
|
17
|
-
<% header.branding { config.project_name } %>
|
16
|
+
<%= lookbook_render :header, id: "app-header", debug_menu: @config.debug_menu do |header| %>
|
17
|
+
<% header.branding { @config.project_name } %>
|
18
18
|
<% end %>
|
19
19
|
|
20
20
|
<%= content_for?(:shell) ? yield(:shell) : yield %>
|
@@ -6,7 +6,7 @@
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
|
7
7
|
|
8
8
|
<link href="<%= asset_path("/css/lookbook.css") %>" rel="stylesheet">
|
9
|
-
<link href="<%= asset_path("/css/themes/#{config.ui_theme}.css") %>" rel="stylesheet">
|
9
|
+
<link href="<%= asset_path("/css/themes/#{@config.ui_theme}.css") %>" rel="stylesheet">
|
10
10
|
|
11
11
|
<%- if @theme_overrides.present? %>
|
12
12
|
<style media="all">
|
@@ -14,7 +14,7 @@
|
|
14
14
|
</style>
|
15
15
|
<% end %>
|
16
16
|
|
17
|
-
<% if config.ui_favicon == true %>
|
17
|
+
<% if @config.ui_favicon == true %>
|
18
18
|
<link
|
19
19
|
rel="icon"
|
20
20
|
href="data:image/svg+xml,%3Csvg width='96' height='84' viewBox='0 0 96 84' xmlns='http://www.w3.org/2000/svg'%3E%3Cdefs%3E%3CclipPath id='a'%3E%3Cpath d='M96 0v84H0V0h96Z'/%3E%3C/clipPath%3E%3CclipPath id='b'%3E%3Cpath d='M71.897 0a1.5 1.5 0 0 1 1.31.769l22.605 40.5a1.5 1.5 0 0 1 0 1.462l-22.605 40.5a1.5 1.5 0 0 1-1.31.769H49.481a1 1 0 0 1-.873-1.487L70.812 42.73a1.5 1.5 0 0 0 0-1.462L48.608 1.487A1 1 0 0 1 49.481 0ZM24.655.564l22.72 40.705a1.5 1.5 0 0 1 0 1.462l-22.72 40.705a1 1 0 0 1-1.746 0L.19 42.73a1.5 1.5 0 0 1 0-1.462L22.91.564a1 1 0 0 1 1.746 0Z'/%3E%3C/clipPath%3E%3C/defs%3E%3Cg clip-path='url(%23a)'%3E%3Cg clip-path='url(%23b)'%3E%3Cpath fill='<%= url_encode theme.favicon_dark_mode %>' d='M0 0h96v84H0V0z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E"
|
@@ -26,10 +26,10 @@
|
|
26
26
|
<% end %>
|
27
27
|
|
28
28
|
<script>
|
29
|
-
window.LOG_LEVEL = <%= config.log_level %>;
|
30
|
-
window.APP_NAME = "<%=
|
31
|
-
<% if
|
32
|
-
window.SOCKET_PATH = "<%=
|
29
|
+
window.LOG_LEVEL = <%= @config.log_level %>;
|
30
|
+
window.APP_NAME = "<%= @engine.app_name %>";
|
31
|
+
<% if @engine.websocket.mounted? %>
|
32
|
+
window.SOCKET_PATH = "<%= @engine.websocket.full_mount_path %>";
|
33
33
|
<% end %>
|
34
34
|
</script>
|
35
35
|
|
@@ -38,7 +38,7 @@
|
|
38
38
|
<script src="<%= asset_path("/js/embed.js") %>" defer></script>
|
39
39
|
<% end %>
|
40
40
|
|
41
|
-
<title><%= [@title, config.project_name || "Lookbook"].compact.join(" :: ") %></title>
|
41
|
+
<title><%= [@title, @config.project_name || "Lookbook"].compact.join(" :: ") %></title>
|
42
42
|
</head>
|
43
43
|
<body>
|
44
44
|
<%= yield :body %>
|
@@ -1,6 +1,6 @@
|
|
1
1
|
<div id="landing" class="flex flex-col items-center justify-center h-full w-full">
|
2
2
|
<div class="text-center" id="landing-<%= @previews.any? ? "with" : "no" %>-content">
|
3
|
-
<% if config.project_name.downcase == "lookbook" %>
|
3
|
+
<% if @config.project_name.downcase == "lookbook" %>
|
4
4
|
<div class="flex justify-center pb-4">
|
5
5
|
<svg class="flex-none mx-auto w-[140px]" viewBox="0 0 275 36">
|
6
6
|
<g fill-rule="nonzero" fill="none">
|
@@ -9,9 +9,9 @@
|
|
9
9
|
</g>
|
10
10
|
</svg>
|
11
11
|
</div>
|
12
|
-
<% elsif config.project_name != false %>
|
12
|
+
<% elsif @config.project_name != false %>
|
13
13
|
<h5 class="text-base text-lookbook-blank-slate-title truncate uppercase font-black tracking-wide mb-2">
|
14
|
-
<%= config.project_name %>
|
14
|
+
<%= @config.project_name %>
|
15
15
|
</h5>
|
16
16
|
<% end %>
|
17
17
|
<div class="opacity-60">
|
@@ -1,11 +1,11 @@
|
|
1
1
|
<% if @params.none? %>
|
2
|
-
<div class="p-4 w-full h-full bg-lookbook-prose-bg">
|
2
|
+
<div class="p-4 w-full h-full bg-lookbook-prose-bg" id="params-editor-blank-slate">
|
3
3
|
<%= lookbook_render :prose do %>
|
4
4
|
<em class='opacity-50'>No params configured.</em>
|
5
5
|
<% end %>
|
6
6
|
</div>
|
7
7
|
<% else %>
|
8
|
-
<div class="p-4 w-full h-full overflow-x-hidden">
|
8
|
+
<div class="p-4 w-full h-full overflow-x-hidden" id="params-editor-<%= @target.id %>">
|
9
9
|
<%= lookbook_render "params/editor" do |editor| %>
|
10
10
|
<% @params.each do |param| %>
|
11
11
|
<% editor.field param: param %>
|
@@ -0,0 +1,41 @@
|
|
1
|
+
shared:
|
2
|
+
definitions:
|
3
|
+
- name: ruby
|
4
|
+
ext: .rb
|
5
|
+
label: Ruby
|
6
|
+
comment: "# %s"
|
7
|
+
|
8
|
+
- name: html
|
9
|
+
ext: .html
|
10
|
+
label: HTML
|
11
|
+
comment: "<!-- %s -->"
|
12
|
+
|
13
|
+
- name: erb
|
14
|
+
ext: .erb
|
15
|
+
label: ERB
|
16
|
+
comment: "<%%# %s %%>"
|
17
|
+
|
18
|
+
- name: haml
|
19
|
+
ext: .haml
|
20
|
+
label: Haml
|
21
|
+
comment: "<!-- %s -->"
|
22
|
+
|
23
|
+
- name: slim
|
24
|
+
ext: .slim
|
25
|
+
label: Slim
|
26
|
+
comment: "<!-- %s -->"
|
27
|
+
|
28
|
+
- name: tsx
|
29
|
+
ext: .tsx
|
30
|
+
label: TypeScript
|
31
|
+
comment: "// %s"
|
32
|
+
|
33
|
+
- name: js
|
34
|
+
ext: .js
|
35
|
+
label: JavasScript
|
36
|
+
comment: "// %s"
|
37
|
+
|
38
|
+
- name: css
|
39
|
+
ext: .css
|
40
|
+
label: CSS
|
41
|
+
comment: "/* %s */"
|
data/config/panels.yml
CHANGED
data/config/tags.yml
CHANGED
data/lib/lookbook/engine.rb
CHANGED
@@ -42,15 +42,16 @@ module Lookbook
|
|
42
42
|
|
43
43
|
initializer "lookbook.file_watcher.pages" do
|
44
44
|
file_watcher.watch(opts.page_paths, opts.page_extensions) do |changes|
|
45
|
-
|
45
|
+
Engine.pages.load(Engine.page_paths)
|
46
|
+
Engine.websocket.broadcast(:reload)
|
46
47
|
run_hooks(:after_change, changes)
|
47
48
|
end
|
48
49
|
end
|
49
50
|
|
50
|
-
initializer "lookbook.parser.
|
51
|
-
parser.after_parse do |
|
52
|
-
|
53
|
-
|
51
|
+
initializer "lookbook.parser.previews_load_callback" do
|
52
|
+
parser.after_parse do |code_objects|
|
53
|
+
Engine.previews.load(code_objects.all(:class))
|
54
|
+
Engine.websocket.broadcast(:reload)
|
54
55
|
end
|
55
56
|
end
|
56
57
|
|
@@ -74,6 +75,7 @@ module Lookbook
|
|
74
75
|
end
|
75
76
|
|
76
77
|
config.after_initialize do
|
78
|
+
Engine.pages.load(Engine.page_paths)
|
77
79
|
parser.parse { run_hooks(:after_initialize) }
|
78
80
|
end
|
79
81
|
|
@@ -82,71 +84,91 @@ module Lookbook
|
|
82
84
|
end
|
83
85
|
|
84
86
|
def run_hooks(event_name, *args)
|
85
|
-
|
87
|
+
Engine.hooks.for_event(event_name).each do |hook|
|
86
88
|
hook.call(Lookbook, *args)
|
87
89
|
end
|
88
90
|
end
|
89
91
|
|
90
92
|
def parser
|
91
|
-
@
|
93
|
+
@_parser ||= PreviewParser.new(opts.preview_paths, Engine.tags)
|
92
94
|
end
|
93
95
|
|
94
96
|
def file_watcher
|
95
|
-
@
|
97
|
+
@_file_watcher ||= FileWatcher.new(force_polling: opts.listen_use_polling)
|
96
98
|
end
|
97
99
|
|
98
100
|
def process
|
99
|
-
@
|
101
|
+
@_process ||= Process.new(env: Rails.env)
|
100
102
|
end
|
101
103
|
|
102
104
|
def listen?
|
103
105
|
opts.listen && process.supports_listening?
|
104
106
|
end
|
105
107
|
|
106
|
-
|
107
|
-
|
108
|
-
|
108
|
+
class << self
|
109
|
+
def mount_path
|
110
|
+
routes.find_script_name({})
|
111
|
+
end
|
109
112
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
+
def mounted?
|
114
|
+
mount_path.present?
|
115
|
+
end
|
113
116
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
117
|
+
def app_name
|
118
|
+
name = if Rails.application.class.respond_to?(:module_parent_name)
|
119
|
+
Rails.application.class.module_parent_name
|
120
|
+
else
|
121
|
+
Rails.application.class.parent_name
|
122
|
+
end
|
123
|
+
name.underscore
|
119
124
|
end
|
120
|
-
name.underscore
|
121
|
-
end
|
122
125
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
126
|
+
def websocket
|
127
|
+
if mounted?
|
128
|
+
use_websocket = opts.auto_refresh && opts.listen && process.supports_listening?
|
129
|
+
@websocket ||= use_websocket ? Websocket.new(mount_path, logger: Lookbook.logger) : Websocket.noop
|
130
|
+
else
|
131
|
+
Websocket.noop
|
132
|
+
end
|
129
133
|
end
|
130
|
-
end
|
131
134
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
+
def panels
|
136
|
+
@_panels ||= PanelStore.init_from_config
|
137
|
+
end
|
135
138
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
+
def inputs
|
140
|
+
@_inputs ||= InputStore.init_from_config
|
141
|
+
end
|
139
142
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
+
def tags
|
144
|
+
@_tags ||= TagStore.init_from_config
|
145
|
+
end
|
143
146
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
+
def hooks
|
148
|
+
@_hooks ||= HookStore.init_from_config
|
149
|
+
end
|
150
|
+
|
151
|
+
def component_paths
|
152
|
+
@_component_paths ||= Array(PathUtils.to_absolute(opts.components_path))
|
153
|
+
end
|
154
|
+
|
155
|
+
def page_paths
|
156
|
+
@_page_paths ||= PathUtils.normalize_paths(opts.page_paths)
|
157
|
+
end
|
158
|
+
|
159
|
+
def preview_paths
|
160
|
+
@_preview_paths ||= PathUtils.normalize_paths(opts.preview_paths)
|
161
|
+
end
|
162
|
+
|
163
|
+
def pages
|
164
|
+
@_pages ||= PageCollection.new
|
165
|
+
end
|
166
|
+
|
167
|
+
def previews
|
168
|
+
@_previews ||= PreviewCollection.new
|
169
|
+
end
|
147
170
|
|
148
|
-
|
149
|
-
@preview_controller
|
171
|
+
attr_reader :preview_controller
|
150
172
|
end
|
151
173
|
|
152
174
|
at_exit do
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Lookbook
|
2
|
+
module HierarchicalCollection
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
def entities
|
7
|
+
@_cache[:entities] ||= collect_ordered_entities(to_tree(include_hidden: true))
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_tree(include_hidden: false)
|
11
|
+
@_cache[include_hidden ? :tree_with_hidden : :tree] ||= EntityTreeBuilder.call(@entities, include_hidden: include_hidden)
|
12
|
+
end
|
13
|
+
|
14
|
+
protected
|
15
|
+
|
16
|
+
def collect_ordered_entities(start_node)
|
17
|
+
start_node.inject([]) do |entities, node|
|
18
|
+
entities.append(node.content? ? node.content : collect_ordered_entities(node))
|
19
|
+
end.flatten
|
20
|
+
end
|
21
|
+
|
22
|
+
def sort_entities
|
23
|
+
@entities.sort_by! { |entity| [entity.depth, entity.position, entity.label] }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Lookbook
|
2
|
+
class EntityCollection
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
delegate_missing_to :entities
|
6
|
+
|
7
|
+
attr_reader :entities
|
8
|
+
|
9
|
+
def initialize(entities = nil)
|
10
|
+
@_cache = {}
|
11
|
+
@entities = []
|
12
|
+
add(entities)
|
13
|
+
end
|
14
|
+
|
15
|
+
def add(entities = nil)
|
16
|
+
Array(entities).each do |entity|
|
17
|
+
unless find_by_path(entity.path)
|
18
|
+
clear_cache
|
19
|
+
@entities.push(entity)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
sort_entities
|
23
|
+
end
|
24
|
+
|
25
|
+
def find_by_id(id)
|
26
|
+
id = Utils.id(id)
|
27
|
+
find { |entity| entity.id == id }
|
28
|
+
end
|
29
|
+
|
30
|
+
def find_by_path(path)
|
31
|
+
find { |entity| entity.path.to_s == path.to_s }
|
32
|
+
end
|
33
|
+
|
34
|
+
def next(entity)
|
35
|
+
index = find_index { |i| i.path == entity.path }
|
36
|
+
entities[index + 1] unless index.nil?
|
37
|
+
end
|
38
|
+
|
39
|
+
def previous(entity)
|
40
|
+
index = find_index { |i| i.path == entity.path }
|
41
|
+
entities[index - 1] if !index.nil? && index > 0
|
42
|
+
end
|
43
|
+
|
44
|
+
def each(&block)
|
45
|
+
if block
|
46
|
+
entities.each { |entity| yield entity }
|
47
|
+
else
|
48
|
+
to_enum(:each)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def flat_map(...)
|
53
|
+
map(...).map(&:to_a).flatten
|
54
|
+
end
|
55
|
+
|
56
|
+
protected
|
57
|
+
|
58
|
+
def sort_entities
|
59
|
+
@entities.sort_by! { |entity| [entity.label] }
|
60
|
+
end
|
61
|
+
|
62
|
+
def clear_cache
|
63
|
+
@_cache = {}
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Lookbook
|
2
|
+
class PageCollection < EntityCollection
|
3
|
+
include HierarchicalCollection
|
4
|
+
|
5
|
+
def load(page_paths)
|
6
|
+
@entities = []
|
7
|
+
clear_cache
|
8
|
+
|
9
|
+
file_paths = page_paths.flat_map do |dir|
|
10
|
+
PathUtils.normalize_paths(Dir["#{dir}/**/*.html.*", "#{dir}/**/*.md.*"].sort)
|
11
|
+
end
|
12
|
+
|
13
|
+
entities = file_paths.map { |path| PageCollection.entity(path) }
|
14
|
+
pages, sections = entities.partition { |page| page.type == :page }
|
15
|
+
|
16
|
+
page_dict = pages.index_by(&:lookup_path)
|
17
|
+
sections.each do |section|
|
18
|
+
parent = page_dict[section.lookup_path]
|
19
|
+
section.parent = parent
|
20
|
+
parent.add_section(section)
|
21
|
+
end
|
22
|
+
|
23
|
+
add(pages)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.entity(file_path)
|
27
|
+
File.basename(file_path).match?(%r{\[(.*?\w+)\]}) ? PageSection.new(file_path) : Page.new(file_path)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Lookbook
|
2
|
+
class PreviewCollection < EntityCollection
|
3
|
+
include HierarchicalCollection
|
4
|
+
|
5
|
+
def find_example_by_path(lookup_path)
|
6
|
+
examples.find_by_path(lookup_path)
|
7
|
+
end
|
8
|
+
|
9
|
+
def find_by_preview_class(klass)
|
10
|
+
find { |preview| preview.preview_class.name == klass.to_s }
|
11
|
+
end
|
12
|
+
|
13
|
+
def load(code_objects)
|
14
|
+
@entities = []
|
15
|
+
clear_cache
|
16
|
+
|
17
|
+
previews = Array(code_objects).map { |obj| PreviewCollection.preview_from_code_object(obj) }.compact
|
18
|
+
add(previews)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.preview_from_code_object(code_object)
|
22
|
+
klass = code_object.path.constantize
|
23
|
+
Preview.new(code_object) if klass.ancestors.include?(ViewComponent::Preview)
|
24
|
+
rescue => exception
|
25
|
+
Lookbook.logger.error LookbookError.new(exception)
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
def examples
|
32
|
+
@_cache[:examples] ||= PreviewExampleCollection.new(flat_map(&:examples))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -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
|