lookbook 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +47 -14
- data/app/components/lookbook/button/component.html.erb +2 -1
- data/app/components/lookbook/button/component.js +9 -0
- data/app/components/lookbook/code/component.html.erb +1 -1
- data/app/components/lookbook/inspector_panel/component.rb +3 -5
- data/app/components/lookbook/nav/item/component.html.erb +1 -1
- data/app/components/lookbook/params/editor/component.rb +3 -10
- data/app/components/lookbook/params/field/component.html.erb +8 -8
- data/app/components/lookbook/params/field/component.rb +21 -72
- data/app/controllers/concerns/lookbook/targetable_concern.rb +156 -0
- data/app/controllers/concerns/lookbook/with_preview_controller_concern.rb +13 -0
- data/app/controllers/lookbook/application_controller.rb +13 -3
- data/app/controllers/lookbook/inspector_controller.rb +45 -0
- data/app/controllers/lookbook/page_controller.rb +11 -7
- data/app/controllers/lookbook/previews_controller.rb +4 -210
- data/app/helpers/lookbook/output_helper.rb +5 -5
- data/app/views/layouts/lookbook/skeleton.html.erb +3 -3
- data/app/views/lookbook/index.html.erb +12 -1
- data/app/views/lookbook/{previews → inspector}/inputs/_color.html.erb +0 -0
- data/app/views/lookbook/{previews → inspector}/inputs/_range.html.erb +0 -0
- data/app/views/lookbook/{previews → inspector}/inputs/_select.html.erb +0 -0
- data/app/views/lookbook/{previews → inspector}/inputs/_text.html.erb +0 -0
- data/app/views/lookbook/{previews → inspector}/inputs/_textarea.html.erb +0 -0
- data/app/views/lookbook/{previews → inspector}/inputs/_toggle.html.erb +3 -3
- data/app/views/lookbook/{previews → inspector}/panels/_content.html.erb +0 -0
- data/app/views/lookbook/{previews → inspector}/panels/_notes.html.erb +0 -0
- data/app/views/lookbook/{previews → inspector}/panels/_output.html.erb +0 -0
- data/app/views/lookbook/{previews → inspector}/panels/_params.html.erb +4 -4
- data/app/views/lookbook/{previews → inspector}/panels/_preview.html.erb +0 -0
- data/app/views/lookbook/{previews → inspector}/panels/_source.html.erb +0 -0
- data/app/views/lookbook/{previews → inspector}/show.html.erb +4 -1
- data/config/app.yml +8 -1
- data/config/inputs.yml +12 -12
- data/config/panels.yml +5 -5
- data/config/routes.rb +5 -5
- data/config/tags.yml +4 -1
- data/lib/lookbook/engine.rb +101 -150
- data/lib/lookbook/file_watcher.rb +47 -0
- data/lib/lookbook/page.rb +15 -16
- data/lib/lookbook/param.rb +99 -0
- data/lib/lookbook/preview.rb +8 -1
- data/lib/lookbook/{preview_controller.rb → preview_actions.rb} +14 -3
- data/lib/lookbook/preview_example.rb +1 -1
- data/lib/lookbook/preview_group.rb +0 -4
- data/lib/lookbook/preview_parser.rb +53 -0
- data/lib/lookbook/process.rb +21 -0
- data/lib/lookbook/services/code/code_beautifier.rb +21 -0
- data/lib/lookbook/services/code/code_highlighter.rb +69 -0
- data/lib/lookbook/services/data/parsers/data_parser.rb +22 -0
- data/lib/lookbook/services/data/parsers/json_parser.rb +7 -0
- data/lib/lookbook/services/data/parsers/yaml_parser.rb +7 -0
- data/lib/lookbook/services/data/resolvers/data_resolver.rb +70 -0
- data/lib/lookbook/services/data/resolvers/eval_resolver.rb +10 -0
- data/lib/lookbook/services/data/resolvers/file_resolver.rb +28 -0
- data/lib/lookbook/services/data/resolvers/method_resolver.rb +10 -0
- data/lib/lookbook/services/data/resolvers/yaml_resolver.rb +18 -0
- data/lib/lookbook/services/markdown_renderer.rb +29 -0
- data/lib/lookbook/services/string_value_caster.rb +60 -0
- data/lib/lookbook/services/tags/tag_options_parser.rb +62 -0
- data/lib/lookbook/services/templates/action_view_annotations_handler.rb +21 -0
- data/lib/lookbook/services/templates/action_view_annotations_stripper.rb +15 -0
- data/lib/lookbook/services/templates/frontmatter_extractor.rb +28 -0
- data/lib/lookbook/services/templates/styles_extractor.rb +38 -0
- data/lib/lookbook/services/{search_param_builder.rb → urls/search_param_builder.rb} +1 -1
- data/lib/lookbook/services/{search_param_parser.rb → urls/search_param_parser.rb} +1 -1
- data/lib/lookbook/source_inspector.rb +26 -45
- data/lib/lookbook/stores/config_store.rb +7 -8
- data/lib/lookbook/stores/input_store.rb +7 -3
- data/lib/lookbook/stores/tag_store.rb +3 -5
- data/lib/lookbook/support/null_object.rb +10 -0
- data/lib/lookbook/support/service.rb +2 -2
- data/lib/lookbook/support/store.rb +1 -1
- data/lib/lookbook/support/utils/attribute_utils.rb +6 -1
- data/lib/lookbook/support/utils/path_utils.rb +6 -3
- data/lib/lookbook/tags/component_tag.rb +7 -0
- data/lib/lookbook/tags/custom_tag.rb +59 -0
- data/lib/lookbook/tags/display_tag.rb +15 -0
- data/lib/lookbook/tags/hidden_tag.rb +13 -0
- data/lib/lookbook/tags/id_tag.rb +7 -0
- data/lib/lookbook/tags/label_tag.rb +4 -0
- data/lib/lookbook/tags/logical_path.rb +4 -0
- data/lib/lookbook/tags/param_tag.rb +61 -0
- data/lib/lookbook/tags/position_tag.rb +16 -0
- data/lib/lookbook/tags/tag_provider.rb +18 -0
- data/lib/lookbook/tags/yard_tag.rb +62 -0
- data/lib/lookbook/utils.rb +0 -40
- data/lib/lookbook/version.rb +1 -1
- data/lib/lookbook/websocket.rb +60 -0
- data/lib/lookbook.rb +2 -1
- data/public/lookbook-assets/css/lookbook.css +30 -77
- data/public/lookbook-assets/css/lookbook.css.map +1 -1
- data/public/lookbook-assets/js/lookbook.js +15 -2
- data/public/lookbook-assets/js/lookbook.js.map +1 -1
- metadata +55 -26
- data/lib/lookbook/code_formatter.rb +0 -68
- data/lib/lookbook/markdown.rb +0 -22
- data/lib/lookbook/params.rb +0 -157
- data/lib/lookbook/parser.rb +0 -42
- data/lib/lookbook/tag.rb +0 -122
- data/lib/lookbook/tag_options.rb +0 -111
- data/lib/lookbook/tags.rb +0 -17
- data/lib/lookbook/template_parser.rb +0 -72
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d6235a52e2104d528b7c3d4a56fee91f3db334ef9ce3d9da43cc11e50792cf77
|
4
|
+
data.tar.gz: 5bd16de7e7dbe99e7552efb07d719230bd1c108d13340d4fcb790dd8e034ef1e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 990f07de7b0ab03d9e9577d3c84768542ebc2af7e5d587fc85f95532ade53f88abc34b2f371a776a0f48b2a3c0db5a1be606e6a42653f57e92ae19e6735ac81c
|
7
|
+
data.tar.gz: a2e17e85420de7603fdd3277eebd473b3bcff413f9d8507b38600290d6d35c081a034c4f70c14d8e3be9075b6b22caade8d2d6610ab3d6a2fd5e863bf1555bc8
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -1,30 +1,42 @@
|
|
1
|
-
# Lookbook
|
2
|
-
|
3
|
-
<div>
|
4
|
-
<a href="https://rubygems.org/gems/lookbook"><img src="https://img.shields.io/gem/v/lookbook" alt="Gem version"></a>
|
5
|
-
<a href="https://github.com/allmarkedup/lookbook/actions/workflows/ci.yml"><img src="https://github.com/allmarkedup/lookbook/actions/workflows/ci.yml/badge.svg?branch=main" alt="CI status"></a>
|
6
|
-
</div>
|
7
1
|
<br>
|
2
|
+
<img src=".github/assets/lookbook_logo.svg" width="180">
|
8
3
|
|
9
4
|
A tool to help browse, develop, test & document [ViewComponents](https://viewcomponent.org/) in Ruby on Rails apps.
|
10
5
|
|
6
|
+
[![Gem version](https://img.shields.io/gem/v/lookbook)](https://rubygems.org/gems/lookbook)
|
7
|
+
[![CI status](https://github.com/allmarkedup/lookbook/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/allmarkedup/lookbook/actions/workflows/ci.yml)
|
8
|
+
<br>
|
9
|
+
|
11
10
|
## Documentation
|
12
11
|
|
13
|
-
**Lookbook
|
12
|
+
✨ **Lookbook guide and API docs**: [lookbook.build](https://lookbook.build)
|
14
13
|
|
15
|
-
> _Looking for
|
14
|
+
> _Looking for pre-v1.0 documentation? [Head over here](https://github.com/allmarkedup/lookbook/tree/0.9.x)._
|
16
15
|
|
17
16
|
|
18
17
|
## Demo
|
19
18
|
|
20
|
-
**Online Demo
|
19
|
+
✨ **Online Demo**: [lookbook-demo-app.herokuapp.com/lookbook](https://lookbook-demo-app.herokuapp.com/lookbook)
|
20
|
+
|
21
|
+
✨ **Demo repo**: [github.com/allmarkedup/lookbook-demo](https://github.com/allmarkedup/lookbook-demo)
|
21
22
|
|
22
23
|
[![Lookbook UI](.github/assets/lookbook_screenshot_v1.0_beta.png)](https://lookbook-demo-app.herokuapp.com/lookbook/)
|
23
24
|
|
24
25
|
|
25
26
|
## Development
|
26
27
|
|
27
|
-
Lookbook
|
28
|
+
Lookbook is implemented as an isolated [Rails Engine](https://guides.rubyonrails.org/engines.html) and uses [ViewComponent](https://viewcomponent.org), [Tailwind](https://tailwindcss.com/) and [Alpine](https://alpinejs.dev/) for it's UI.
|
29
|
+
|
30
|
+
This repository contains:
|
31
|
+
|
32
|
+
* The Lookbook source code ([`/app`](https://github.com/allmarkedup/lookbook/tree/main/app), [`/lib`](https://github.com/allmarkedup/lookbook/tree/main/lib), [`/config`](https://github.com/allmarkedup/lookbook/tree/main/config), etc)
|
33
|
+
* A '[workbench](#workbench)' app used for Lookbook component development ([`/workbench`](https://github.com/allmarkedup/lookbook/tree/main/workbench)).
|
34
|
+
* The Lookbook [documentation site](#docs-site) source code and content ([`/docs`](https://github.com/allmarkedup/lookbook/tree/main/docs)).
|
35
|
+
* A [test suite](#testing) with a 'runable' dummy app ([`/spec`](https://github.com/allmarkedup/lookbook/tree/main/spec)).
|
36
|
+
|
37
|
+
### Workbench
|
38
|
+
|
39
|
+
To preview the Lookbook components within a Lookbook instance you can run the included `workbench` app:
|
28
40
|
|
29
41
|
1. Clone this repo
|
30
42
|
2. Install dependencies: `bundle install & npm install`
|
@@ -33,21 +45,42 @@ Lookbook's UI is itself built using ViewComponents. To preview these components
|
|
33
45
|
|
34
46
|
The `workbench` app will be started in development mode and any changes to Lookbook's views or assets will immediately be reflected in the UI.
|
35
47
|
|
36
|
-
###
|
48
|
+
### Documentation site
|
37
49
|
|
38
50
|
The [Lookbook docs site](https://lookbook.build) is built using [Bridgetown](https://www.bridgetownrb.com/) and the source files can be found in the `./docs` directory.
|
39
51
|
|
40
|
-
To
|
52
|
+
To preview changes locally you can run a development version of the docs site:
|
53
|
+
|
54
|
+
1. Clone this repo
|
55
|
+
2. Install dependencies: `bundle install`
|
56
|
+
3. Start the app: `bin/docs`
|
57
|
+
4. Visit http://localhost:4000
|
41
58
|
|
42
59
|
### Testing
|
43
60
|
|
44
|
-
Lookbook uses RSpec for testing.
|
61
|
+
Lookbook uses [RSpec](https://relishapp.com/rspec) for testing.
|
45
62
|
|
46
63
|
Tests can be run using the `rake spec` or `bundle exec rspec` commands.
|
47
64
|
|
48
65
|
The dummy app that the tests are being run against can be viewed by running the `bin/dummy` command and then browsing to http://localhost:9292/lookbook
|
49
66
|
|
50
67
|
|
68
|
+
## Contributing
|
69
|
+
|
70
|
+
Lookbook is an un-funded open source project and contributions of all types and sizes are most welcome!
|
71
|
+
|
72
|
+
Please take the time to read over the [Contributing](./CONTRIBUTING.md) guide before making your first contribution and if anything isn't clear then [start a discussion](https://github.com/allmarkedup/lookbook/discussions) and we will do our best to help you out.
|
73
|
+
|
74
|
+
## Contributors
|
75
|
+
|
76
|
+
Lookbook was created by [Mark Perkins](https://github.com/allmarkedup) and continues to grow
|
77
|
+
& improve thanks to the ideas, suggestions and hard work of all of [these excellent humans](https://github.com/allmarkedup/lookbook/graphs/contributors):
|
78
|
+
<br>
|
79
|
+
<br>
|
80
|
+
<a href="https://github.com/allmarkedup/lookbook/graphs/contributors">
|
81
|
+
<img src="https://contrib.rocks/image?repo=allmarkedup/lookbook&columns=14" width="800" />
|
82
|
+
</a>
|
83
|
+
|
51
84
|
## License
|
52
85
|
|
53
|
-
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
86
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
@@ -8,7 +8,8 @@
|
|
8
8
|
}
|
9
9
|
],
|
10
10
|
disabled: @disabled,
|
11
|
-
"@keydown.esc.stop": "hideDropdown"
|
11
|
+
"@keydown.esc.stop": "hideDropdown",
|
12
|
+
"@navigation:complete.window": "updateDropdown" do %>
|
12
13
|
<span x-ref="icon">
|
13
14
|
<%= icon || lookbook_render(:icon, name: @icon, size: icon_size, ":class": "{'animate-spin': _spinning}") %>
|
14
15
|
</span>
|
@@ -38,6 +38,15 @@ export default function buttonComponent() {
|
|
38
38
|
}
|
39
39
|
},
|
40
40
|
|
41
|
+
updateDropdown() {
|
42
|
+
if (dropdown) {
|
43
|
+
dropdown.hide();
|
44
|
+
this.$nextTick(() => {
|
45
|
+
dropdown.setContent(this.$refs.dropdown.innerHTML);
|
46
|
+
});
|
47
|
+
}
|
48
|
+
},
|
49
|
+
|
41
50
|
startSpin() {
|
42
51
|
this._spinning = true;
|
43
52
|
},
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require "css_parser"
|
2
|
-
|
3
1
|
module Lookbook
|
4
2
|
class InspectorPanel::Component < Lookbook::BaseComponent
|
5
3
|
attr_reader :panel_styles, :panel_html
|
@@ -14,9 +12,9 @@ module Lookbook
|
|
14
12
|
end
|
15
13
|
|
16
14
|
def before_render
|
17
|
-
|
18
|
-
@panel_styles =
|
19
|
-
@panel_html =
|
15
|
+
styles, html = StylesExtractor.call(content)
|
16
|
+
@panel_styles = styles.map { |s| "##{id} #{s}" }.join("\n")
|
17
|
+
@panel_html = html.html_safe
|
20
18
|
end
|
21
19
|
end
|
22
20
|
end
|
@@ -6,7 +6,7 @@
|
|
6
6
|
"entity-type": item.type
|
7
7
|
},
|
8
8
|
cloak: true do %>
|
9
|
-
<%= lookbook_tag href.present? ? :a : :
|
9
|
+
<%= lookbook_tag href.present? ? :a : :button,
|
10
10
|
href: href,
|
11
11
|
class: "flex items-center py-1 select-none cursor-pointer text-lookbook-nav-text hover:bg-lookbook-nav-item-hover transition",
|
12
12
|
style: "padding-left: #{left_pad}px",
|
@@ -1,20 +1,13 @@
|
|
1
1
|
module Lookbook
|
2
2
|
module Params
|
3
3
|
class Editor::Component < Lookbook::BaseComponent
|
4
|
-
renders_many :fields, ->(
|
4
|
+
renders_many :fields, ->(**attrs) do
|
5
5
|
@field_count += 1
|
6
|
-
|
7
|
-
input_config = @inputs[input.tr("-", "_").to_sym]
|
8
|
-
Lookbook::Params::Field::Component.new(input: input,
|
9
|
-
description: description,
|
10
|
-
index: @field_count,
|
11
|
-
config: input_config, **attrs)
|
6
|
+
Lookbook::Params::Field::Component.new(**attrs, index: @field_count)
|
12
7
|
end
|
13
8
|
|
14
|
-
def initialize(
|
15
|
-
@inputs = inputs.to_h
|
9
|
+
def initialize(**html_attrs)
|
16
10
|
@field_count = -1
|
17
|
-
@descriptions = false
|
18
11
|
@@input_styles = {}
|
19
12
|
super(**html_attrs)
|
20
13
|
end
|
@@ -1,27 +1,27 @@
|
|
1
1
|
<%= render_component_tag :tr, "@keydown.stop": true do %>
|
2
2
|
<td class="param-label">
|
3
|
-
<label for="param-<%=
|
4
|
-
<span class="mr-0.5"><%==
|
5
|
-
<% if hint? %>
|
3
|
+
<label for="param-<%= param.name %>">
|
4
|
+
<span class="mr-0.5"><%== param.label %></span>
|
5
|
+
<% if param.hint.present? %>
|
6
6
|
<span x-data="tooltipComponent" class="inline-block cursor-help relative top-[2px]">
|
7
7
|
<%= icon :help_circle, size: 3.5, class: "opacity-40 hover:opacity-100 transition" %>
|
8
8
|
<div class="hidden" x-ref="tooltip">
|
9
|
-
<%=
|
9
|
+
<%= param.hint %>
|
10
10
|
</div>
|
11
11
|
</span>
|
12
12
|
<% end %>
|
13
13
|
</label>
|
14
14
|
</td>
|
15
|
-
<td class="param-description <%= "param-description-empty" unless description
|
16
|
-
<% if description
|
17
|
-
<p class="opacity-70"><%=
|
15
|
+
<td class="param-description <%= "param-description-empty" unless param.description %>">
|
16
|
+
<% if param.description %>
|
17
|
+
<p class="opacity-70"><%= param.description %></p>
|
18
18
|
<% else %>
|
19
19
|
<p class="italic opacity-40">—</p>
|
20
20
|
<% end %>
|
21
21
|
</td>
|
22
22
|
<td class="param-input">
|
23
23
|
<div class="param-input-wrapper">
|
24
|
-
<%=
|
24
|
+
<%= rendered_input %>
|
25
25
|
</div>
|
26
26
|
</td>
|
27
27
|
<% end %>
|
@@ -1,92 +1,41 @@
|
|
1
1
|
module Lookbook
|
2
2
|
module Params
|
3
3
|
class Field::Component < Lookbook::BaseComponent
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
@
|
8
|
-
@hint = hint
|
9
|
-
@description = description
|
10
|
-
@value = value
|
4
|
+
attr_reader :param, :rendered_input
|
5
|
+
|
6
|
+
def initialize(param:, index:, **html_attrs)
|
7
|
+
@param = param
|
11
8
|
@index = index
|
12
|
-
@input_options = input_options
|
13
|
-
@value_default = value_default
|
14
|
-
@value_type = value_type
|
15
|
-
@config = config || {}
|
16
9
|
@rendered_input = nil
|
17
10
|
super(**html_attrs)
|
18
11
|
end
|
19
12
|
|
20
|
-
def hint?
|
21
|
-
@hint.present?
|
22
|
-
end
|
23
|
-
|
24
|
-
def description?
|
25
|
-
@description.present?
|
26
|
-
end
|
27
|
-
|
28
|
-
def input
|
29
|
-
@rendered_input
|
30
|
-
end
|
31
|
-
|
32
13
|
def before_render
|
33
|
-
|
34
|
-
Editor::Component.add_styles(
|
14
|
+
styles, html = StylesExtractor.call(render_input)
|
15
|
+
Editor::Component.add_styles(param.input, styles)
|
35
16
|
|
17
|
+
escaped_value = json_escape(param.value.to_json)
|
36
18
|
wrapper_attrs = {
|
37
|
-
data: {"param-input":
|
38
|
-
"x-data": "paramsInputComponent({name: '#{
|
19
|
+
data: {"param-input": param.input},
|
20
|
+
"x-data": "paramsInputComponent({name: '#{param.name}', value: #{escaped_value}})"
|
39
21
|
}
|
40
|
-
|
41
|
-
@rendered_input = tag.div(**wrapper_attrs) do
|
42
|
-
tpl.content
|
43
|
-
end
|
22
|
+
@rendered_input = tag.div(**wrapper_attrs) { html.html_safe }
|
44
23
|
end
|
45
24
|
|
46
25
|
protected
|
47
26
|
|
48
|
-
def input_error(error)
|
49
|
-
tag.div error, class: "p-2 text-red-500 italic"
|
50
|
-
end
|
51
|
-
|
52
|
-
def value
|
53
|
-
val = @value.presence || @value_default
|
54
|
-
@value_type.downcase == "boolean" ? val == "true" || val == true : val
|
55
|
-
end
|
56
|
-
|
57
|
-
def escaped_value
|
58
|
-
json_escape(value.to_json)
|
59
|
-
end
|
60
|
-
|
61
|
-
def input_options
|
62
|
-
config_options = @config.fetch(:opts, {})
|
63
|
-
opts = config_options.merge(@input_options).symbolize_keys
|
64
|
-
opts[:id] = "param-#{@name}"
|
65
|
-
opts
|
66
|
-
end
|
67
|
-
|
68
|
-
def render_props
|
69
|
-
{
|
70
|
-
name: @name,
|
71
|
-
input: @input_name,
|
72
|
-
value: value,
|
73
|
-
value_type: @value_type,
|
74
|
-
value_default: @value_default,
|
75
|
-
input_options: input_options.except(:choices),
|
76
|
-
choices: input_options[:choices]
|
77
|
-
}
|
78
|
-
end
|
79
|
-
|
80
27
|
def render_input
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
28
|
+
input_options = param.input_options.to_h
|
29
|
+
input_options[:id] = "param-#{param.name}"
|
30
|
+
|
31
|
+
render(param.input_partial,
|
32
|
+
name: param.name,
|
33
|
+
input: param.input,
|
34
|
+
value: param.value,
|
35
|
+
value_type: param.value_type,
|
36
|
+
value_default: param.value_default,
|
37
|
+
input_options: input_options.except(:choices),
|
38
|
+
choices: input_options[:choices])
|
90
39
|
end
|
91
40
|
|
92
41
|
def alpine_component
|
@@ -0,0 +1,156 @@
|
|
1
|
+
module Lookbook
|
2
|
+
module TargetableConcern
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
before_action :lookup_entities, only: [:show]
|
7
|
+
before_action :set_title
|
8
|
+
before_action :set_display_options
|
9
|
+
before_action :set_params
|
10
|
+
end
|
11
|
+
|
12
|
+
def set_title
|
13
|
+
@title = @target.present? ? [@target&.label, @preview&.label].compact.join(" :: ") : "Not found"
|
14
|
+
end
|
15
|
+
|
16
|
+
def lookup_entities
|
17
|
+
@target = Lookbook.previews.find_example(params[:path])
|
18
|
+
if @target.present?
|
19
|
+
@preview = @target.preview
|
20
|
+
if params[:path] == @preview&.lookup_path
|
21
|
+
redirect_to lookbook_inspect_path "#{params[:path]}/#{@preview.default_example.name}"
|
22
|
+
end
|
23
|
+
else
|
24
|
+
@preview = Lookbook.previews.find(params[:path])
|
25
|
+
if @preview.present?
|
26
|
+
first_example = @preview.examples.first
|
27
|
+
redirect_to lookbook_inspect_path(first_example.lookup_path) if first_example
|
28
|
+
else
|
29
|
+
@preview = Lookbook.previews.find(path_segments.slice(0, path_segments.size - 1).join("/"))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def set_display_options
|
35
|
+
@dynamic_display_options = []
|
36
|
+
@static_display_options = []
|
37
|
+
|
38
|
+
if @target.present?
|
39
|
+
opts = @target.display_options
|
40
|
+
@dynamic_display_options = opts.select { _2.is_a?(Array) || _2.is_a?(Hash) }
|
41
|
+
@static_display_options = opts.except(*@dynamic_display_options.keys)
|
42
|
+
|
43
|
+
if params[:_display]
|
44
|
+
display_params = SearchParamParser.call(params[:_display])
|
45
|
+
display_params.each do |name, value|
|
46
|
+
if @dynamic_display_options.key?(name)
|
47
|
+
cookies["lookbook-display-#{name}"] = value
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
@dynamic_display_options.each do |name, opts|
|
53
|
+
choices = opts.is_a?(Hash) ? opts[:choices].to_a : opts
|
54
|
+
@static_display_options[name] ||= cookies.fetch("lookbook-display-#{name}", choices.first)
|
55
|
+
end
|
56
|
+
|
57
|
+
unless params[:_display]
|
58
|
+
display_params = @dynamic_display_options.map do |name, opts|
|
59
|
+
[name, @static_display_options[name]]
|
60
|
+
end.to_h
|
61
|
+
request.query_parameters[:_display] = SearchParamBuilder.call(display_params)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def set_params
|
67
|
+
@params = []
|
68
|
+
|
69
|
+
if @target
|
70
|
+
@params = @target.tags("param").map do |param_tag|
|
71
|
+
Param.from_tag(
|
72
|
+
param_tag,
|
73
|
+
value: preview_controller.params[param_tag.name]
|
74
|
+
)
|
75
|
+
end
|
76
|
+
|
77
|
+
# cast known param values to correct type
|
78
|
+
@params.each do |param|
|
79
|
+
if preview_controller.params.key?(param.name)
|
80
|
+
preview_controller.params[param.name] = param.cast_value
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# set display and data params for use in preview layouts
|
85
|
+
preview_controller.params[:lookbook] = {
|
86
|
+
display: @static_display_options,
|
87
|
+
data: Lookbook.data
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
91
|
+
preview_controller.params.permit!
|
92
|
+
@preview_params = preview_controller.params.to_h.select do |key, value|
|
93
|
+
!!@params.find { |param_tag| param_tag.name == key.to_s }
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def inspector_data
|
98
|
+
return @inspector_data if @inspector_data.present?
|
99
|
+
|
100
|
+
context_data = {
|
101
|
+
preview_params: @preview_params,
|
102
|
+
path: params[:path]
|
103
|
+
}
|
104
|
+
|
105
|
+
preview = @preview
|
106
|
+
target_examples = @target.type == :group ? @target.examples : [@target]
|
107
|
+
|
108
|
+
examples = target_examples.map do |example|
|
109
|
+
render_args = @preview.render_args(example.name, params: preview_controller.params)
|
110
|
+
has_template = render_args[:template] != "view_components/preview"
|
111
|
+
output = preview_controller.process(:render_example_to_string, @preview, example.name)
|
112
|
+
source = has_template ? example.template_source(render_args[:template]) : example.method_source
|
113
|
+
source_lang = has_template ? example.template_lang(render_args[:template]) : example.lang
|
114
|
+
|
115
|
+
example.define_singleton_method(:output, proc { output })
|
116
|
+
example.define_singleton_method(:source, proc { source })
|
117
|
+
example.define_singleton_method(:source_lang, proc { source_lang })
|
118
|
+
example
|
119
|
+
end
|
120
|
+
|
121
|
+
target = @target.type == :group ? @target : examples.find { |e| e.lookup_path == @target.lookup_path }
|
122
|
+
|
123
|
+
params_ref = @params
|
124
|
+
preview.define_singleton_method(:params, proc { params_ref })
|
125
|
+
|
126
|
+
@inspector_data ||= Lookbook::Store.new({
|
127
|
+
context: context_data,
|
128
|
+
preview: preview,
|
129
|
+
examples: examples,
|
130
|
+
example: examples.first,
|
131
|
+
target: target,
|
132
|
+
data: Lookbook.data,
|
133
|
+
app: Lookbook
|
134
|
+
})
|
135
|
+
end
|
136
|
+
|
137
|
+
def show_404(layout: nil)
|
138
|
+
locals = if @preview
|
139
|
+
{
|
140
|
+
message: "Example not found",
|
141
|
+
description: "The '#{@preview.label}' preview does not have an example named '#{path_segments.last}'."
|
142
|
+
}
|
143
|
+
else
|
144
|
+
{
|
145
|
+
message: "Not found",
|
146
|
+
description: "Looked for '#{params[:path]}'.<br>The preview may have been renamed or deleted."
|
147
|
+
}
|
148
|
+
end
|
149
|
+
render_in_layout "lookbook/404", layout: layout, **locals
|
150
|
+
end
|
151
|
+
|
152
|
+
def path_segments
|
153
|
+
params[:path].split("/")
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Lookbook
|
2
|
+
module WithPreviewControllerConcern
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
def preview_controller
|
6
|
+
return @preview_controller if @preview_controller
|
7
|
+
controller = Lookbook::Engine.preview_controller.new
|
8
|
+
controller.request = request
|
9
|
+
controller.response = response
|
10
|
+
@preview_controller ||= controller
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -1,8 +1,6 @@
|
|
1
1
|
module Lookbook
|
2
2
|
class ApplicationController < ActionController::Base
|
3
|
-
if respond_to?(:content_security_policy)
|
4
|
-
content_security_policy false, if: -> { Rails.env.development? }
|
5
|
-
end
|
3
|
+
content_security_policy(false) if respond_to?(:content_security_policy)
|
6
4
|
|
7
5
|
protect_from_forgery with: :exception
|
8
6
|
|
@@ -45,5 +43,17 @@ module Lookbook
|
|
45
43
|
@error = locals[:error]
|
46
44
|
render path, layout: layout.presence || (params[:lookbook_embed] ? "lookbook/basic" : "lookbook/application"), locals: locals
|
47
45
|
end
|
46
|
+
|
47
|
+
def prettify_error(exception)
|
48
|
+
error_params = {}
|
49
|
+
if exception.is_a?(ViewComponent::PreviewTemplateError)
|
50
|
+
error_params = {
|
51
|
+
file_path: @preview&.full_path,
|
52
|
+
line_number: 0,
|
53
|
+
source_code: @target&.source
|
54
|
+
}
|
55
|
+
end
|
56
|
+
Lookbook::Error.new(exception, **error_params)
|
57
|
+
end
|
48
58
|
end
|
49
59
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Lookbook
|
2
|
+
class InspectorController < ApplicationController
|
3
|
+
include TargetableConcern
|
4
|
+
include WithPreviewControllerConcern
|
5
|
+
|
6
|
+
layout "lookbook/inspector"
|
7
|
+
helper Lookbook::PreviewHelper
|
8
|
+
|
9
|
+
def self.controller_path
|
10
|
+
"lookbook/inspector"
|
11
|
+
end
|
12
|
+
|
13
|
+
def show
|
14
|
+
if @target
|
15
|
+
begin
|
16
|
+
@main_panels = main_panels
|
17
|
+
@drawer_panels = drawer_panels
|
18
|
+
rescue => exception
|
19
|
+
render_in_layout "lookbook/error", layout: "lookbook/inspector", error: prettify_error(exception)
|
20
|
+
end
|
21
|
+
else
|
22
|
+
show_404
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def show_legacy
|
27
|
+
Lookbook.logger.warn("Legacy URL path detected. These paths are deprecated and will be removed in a future version")
|
28
|
+
redirect_to lookbook_inspect_path params[:path]
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def main_panels
|
34
|
+
Engine.panels.in_group(:main).map do |config|
|
35
|
+
PanelStore.resolve_config(config, inspector_data)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def drawer_panels
|
40
|
+
Engine.panels.in_group(:drawer).map do |config|
|
41
|
+
PanelStore.resolve_config(config, inspector_data)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -13,13 +13,17 @@ module Lookbook
|
|
13
13
|
@pages = Lookbook.pages
|
14
14
|
@next_page = @pages.find_next(@page)
|
15
15
|
@previous_page = @pages.find_previous(@page)
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
16
|
+
|
17
|
+
content = ActionViewAnnotationsHandler.call(disable_annotations: true) do
|
18
|
+
render_to_string inline: @page.content, locals: {
|
19
|
+
page: @page,
|
20
|
+
next_page: @next_page,
|
21
|
+
previous_page: @previous_page,
|
22
|
+
pages: @pages
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
@page.markdown? ? MarkdownRenderer.call(content, Lookbook.config.markdown_options) : content
|
23
27
|
end
|
24
28
|
end
|
25
29
|
end
|