lookbook 1.2.1 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +47 -14
- 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 +7 -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
|
+
[](https://rubygems.org/gems/lookbook)
|
|
7
|
+
[](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
|
[](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).
|
|
@@ -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
|