lookbook 2.0.0.beta.0 → 2.0.0.beta.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 01c53cc76e29d3d9862a67b29bbabd927c623003bc55355415775c778ec0c99a
4
- data.tar.gz: e8bf4e7538bf3224e70a00458cddea148c594cf4a61287dce978c15793873dfe
3
+ metadata.gz: a6a6aedff44436d4f892bc5b0fc28f596d0cd14f4578af150ea004997f1aa01c
4
+ data.tar.gz: 548938fd0815d99535f3c70831ad9b5a554c23dd8dd6f6d9896538150b1a79ad
5
5
  SHA512:
6
- metadata.gz: 7d2049f0d6b79e2994596a3cbe76e14e247ae75f15f137b0ccd8ed6863dc71637145765beb7c2b826d84f2b350af2e88d72e746667b809f82626e7a70aa4d03f
7
- data.tar.gz: afc5b06b19975253e8f9125723fc1e11d3857ae53af9f5831b9b4c59f1c79fa5d620ffdeed3177a30175c9ad98e92b19b5ba4a37508c0940520ac63ac13fa7bf
6
+ metadata.gz: a3ff63b130c8a92fc6a0f84296d3d56529941a21957eb1ec056d31121ef3eddef308a5397c032d77bf630b9d465085a3dd5f9dd81381abc2fdf88905bfb24ab2
7
+ data.tar.gz: 8fd98d1823d8a9f5b00d690c73416f98993d8dacf6d8af92935e85891a1c9c06452f82cef88e57c48148bc4329104d2f7583a683ae4e7a5dfb58735d337c1fab
data/README.md CHANGED
@@ -27,7 +27,7 @@ For the current stable release see the [main branch](https://github.com/ViewComp
27
27
 
28
28
  ## Development
29
29
 
30
- 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.
30
+ 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 its UI.
31
31
 
32
32
  This repository contains:
33
33
 
@@ -57,7 +57,7 @@
57
57
  x-ref="viewportWrapper">
58
58
  <%= lookbook_render :viewport,
59
59
  iframe_id: "#{id}-viewport",
60
- src: helpers.lookbook_preview_path(target.path, params.merge(lookbook_embed: true)),
60
+ src: helpers.lookbook_preview_path(target.path, request.query_parameters.merge(lookbook_timestamp: Time.now, lookbook_embed: true)),
61
61
  alpine_data: "store",
62
62
  resize_height: false,
63
63
  class: "mb-[-2px] transition-[height] duration-150",
@@ -1,7 +1,10 @@
1
1
  <%= render_component_tag class:"p-3 w-[320px]" do %>
2
2
  <h4 class="text-[11px] uppercase tracking-wider mb-2 font-bold">Preview embed code</h4>
3
3
 
4
- <p class="text-xs text-gray-600 mb-3">This code can be used to embed this preview in Lookbook pages or on external sites.</p>
4
+ <p class="text-xs text-gray-600 mb-3">
5
+ This code can be used to embed this preview in
6
+ Lookbook pages<% unless policy == "SAMEORIGIN" %> or on external sites<% end %>.
7
+ </p>
5
8
 
6
9
  <div class="border-t border-lookbook-dropdown-divider pt-3 pb-3">
7
10
  <%= code :html do %><%= embed_code %><% end %>
@@ -1,11 +1,12 @@
1
1
  module Lookbook
2
2
  class EmbedCodeDropdown::Component < Lookbook::BaseComponent
3
- attr_reader :preview, :pages, :params, :target
3
+ attr_reader :preview, :pages, :params, :target, :policy
4
4
 
5
- def initialize(preview:, target:, pages:, params:, **html_attrs)
5
+ def initialize(preview:, target:, pages:, params:, policy:, **html_attrs)
6
6
  @preview = preview
7
7
  @target = target
8
8
  @pages = pages
9
+ @policy = policy
9
10
  @params = params.deep_symbolize_keys
10
11
  super(**html_attrs)
11
12
  end
@@ -1,6 +1,6 @@
1
1
  <%= render_component_tag :header do %>
2
2
  <%= lookbook_render :toolbar, class: "!bg-lookbook-header-bg !text-lookbook-header-text !border-lookbook-header-border" do |toolbar| %>
3
- <% toolbar.with_section class: "mt-[-2px]", padded: true do %>
3
+ <% toolbar.with_section padded: true do %>
4
4
  <% if branding.present? %>
5
5
  <a
6
6
  <% if landing_path %>href="<%= landing_path %>"<% end %>
@@ -42,14 +42,15 @@ module Lookbook
42
42
  display_params = SearchParamParser.call(params[:_display])
43
43
  display_params.each do |name, value|
44
44
  if @dynamic_display_options.key?(name)
45
- cookies["lookbook-display-#{name}"] = value
45
+ cookies["lookbook-display-#{name}"] = value.is_a?(Array) ? value[1] : value
46
46
  end
47
47
  end
48
48
  end
49
49
 
50
50
  @dynamic_display_options.each do |name, opts|
51
51
  choices = opts.is_a?(Hash) ? opts[:choices].to_a : opts
52
- @static_display_options[name] ||= cookies.fetch("lookbook-display-#{name}", choices.first)
52
+ value = choices.first.is_a?(Array) ? choices.first[1] : choices.first
53
+ @static_display_options[name] ||= cookies.fetch("lookbook-display-#{name}", value)
53
54
  end
54
55
 
55
56
  unless params[:_display]
@@ -5,6 +5,8 @@ module Lookbook
5
5
 
6
6
  layout false
7
7
 
8
+ before_action :permit_framing, only: [:show]
9
+
8
10
  def self.controller_path
9
11
  "lookbook/previews"
10
12
  end
@@ -17,10 +19,15 @@ module Lookbook
17
19
  {
18
20
  name: preview.name,
19
21
  scenarios: preview.scenarios.map { |scenario|
20
- {
21
- inspect_path: scenario.url_path,
22
- name: scenario.name
23
- }
22
+ case scenario
23
+ when Lookbook::ScenarioEntity
24
+ scenario_json(scenario)
25
+ when Lookbook::ScenarioGroupEntity
26
+ {
27
+ name: scenario.name,
28
+ examples: scenario.scenarios.map { |s| scenario_json(s) }
29
+ }
30
+ end
24
31
  }
25
32
  }
26
33
  end
@@ -33,7 +40,7 @@ module Lookbook
33
40
  if @target
34
41
  begin
35
42
  opts = {layout: @preview.layout}
36
- if params[:lookbook_embed] == "true"
43
+ if embedded?
37
44
  opts[:append_html] = render_to_string("lookbook/partials/_iframe_content_scripts", layout: nil)
38
45
  end
39
46
  @preview_html = preview_controller.process(:render_in_layout_to_string, "lookbook/previews/group", inspector_data, **opts)
@@ -46,5 +53,24 @@ module Lookbook
46
53
  show_404
47
54
  end
48
55
  end
56
+
57
+ private
58
+
59
+ def embedded?
60
+ params[:lookbook_embed] == "true"
61
+ end
62
+
63
+ def scenario_json(scenario)
64
+ {
65
+ name: scenario.name,
66
+ inspect_path: scenario.url_path,
67
+ preview_path: scenario.preview_path
68
+ }
69
+ end
70
+
71
+ def permit_framing
72
+ headers["X-Frame-Options"] = Lookbook.config.preview_embeds.policy if embedded?
73
+ headers["X-Frame-Options"] = "SAMEORIGIN" if headers["X-Frame-Options"] == "DENY"
74
+ end
49
75
  end
50
76
  end
@@ -11,7 +11,7 @@
11
11
  <%= render "lookbook/partials/user_styles" %>
12
12
 
13
13
  <%= lookbook_render :header, id: "app-header", debug_menu: @config.debug_menu do |header| %>
14
- <% header.branding { @config.project_name } %>
14
+ <% header.with_branding { @config.project_name } %>
15
15
  <% end %>
16
16
 
17
17
  <% if @previews.any? || @pages.any? %>
@@ -29,7 +29,7 @@
29
29
  "@click.outside": "closeMobileSidebar",
30
30
  cloak: true do %>
31
31
 
32
- <% cache do %>
32
+ <% cache @engine.last_changed do %>
33
33
 
34
34
  <%= lookbook_render :split_layout,
35
35
  alpine_data: "$store.layout.#{@pages.any? && @previews.any? ? "sidebar" : "singleSectionSidebar"}",
@@ -53,7 +53,7 @@
53
53
  <% end %>
54
54
  <% end %>
55
55
  <% end %>
56
- <% nav.filter store: "$store.nav.previews.filter", placeholder: "Filter previews by name&hellip;" %>
56
+ <% nav.with_filter store: "$store.nav.previews.filter", placeholder: "Filter previews by name&hellip;" %>
57
57
  <% end %>
58
58
  <% end %>
59
59
  <% end %>
@@ -33,13 +33,16 @@
33
33
 
34
34
  <% toolbar.with_section divide: :left, class: "flex-none relative z-10" do %>
35
35
  <%= lookbook_render :button_group do |group| %>
36
- <%= group.with_button id: "embed-generator-dropdown-button", icon: :code_2, tooltip: "Get embed code" do |button| %>
37
- <% button.with_dropdown.with_content(lookbook_render :embed_code_dropdown,
38
- pages: @pages,
39
- preview: @preview,
40
- target: @target,
41
- params: request.query_parameters
42
- ) %>
36
+ <% if @engine.preview_embeds_allowed? %>
37
+ <%= group.with_button id: "embed-generator-dropdown-button", icon: :code_2, tooltip: "Get embed code" do |button| %>
38
+ <% button.with_dropdown.with_content(lookbook_render :embed_code_dropdown,
39
+ pages: @pages,
40
+ preview: @preview,
41
+ target: @target,
42
+ params: request.query_parameters,
43
+ policy: @config.preview_embeds.policy
44
+ ) %>
45
+ <% end %>
43
46
  <% end %>
44
47
  <% group.with_button id: "copy-preview-url-button",
45
48
  icon: :link,
@@ -2,7 +2,7 @@
2
2
  <%# Render a group of scenarios %>
3
3
  <% scenarios.each do |scenario| %>
4
4
  <div style="margin-bottom: 30px !important; display: block !important;">
5
- <h6 style="all: unset; display: block; color: #999; font-family: sans-serif; font-size: 14px; margin-top: 0; margin-bottom: 10px;">
5
+ <h6 style="all: unset; display: block; color: #555; font-family: sans-serif; font-size: 14px; margin-top: 0; margin-bottom: 10px;">
6
6
  <%= scenario.label %>
7
7
  </h6>
8
8
  <%= scenario.output %>
data/config/app.yml CHANGED
@@ -9,7 +9,8 @@ shared:
9
9
  main_panels: [preview, output]
10
10
  drawer_panels: [source, notes, params, "*"]
11
11
  preview_embeds:
12
- policy: "SAMEORIGIN"
12
+ enabled: true
13
+ policy: SAMEORIGIN
13
14
  panels: false
14
15
  actions: []
15
16
  scenarios: []
data/config/routes.rb CHANGED
@@ -13,6 +13,8 @@ Lookbook::Engine.routes.draw do
13
13
 
14
14
  get "/inspect/*path", to: "inspector#show", as: :lookbook_inspect
15
15
 
16
- get "/embed", to: "embeds#lookup", as: :lookbook_embed_lookup
17
- get "/embed/*path", to: "embeds#show", as: :lookbook_embed
16
+ if Lookbook::Engine.preview_embeds_allowed?
17
+ get "/embed", to: "embeds#lookup", as: :lookbook_embed_lookup
18
+ get "/embed/*path", to: "embeds#show", as: :lookbook_embed
19
+ end
18
20
  end
@@ -82,6 +82,10 @@ module Lookbook
82
82
  reloading? && runtime_context.web? && FileWatcher.evented?
83
83
  end
84
84
 
85
+ def preview_embeds_allowed?
86
+ opts.preview_embeds.enabled == true && opts.preview_embeds.policy != "DENY"
87
+ end
88
+
85
89
  def websocket
86
90
  @_websocket ||= auto_refresh? ? Websocket.new(mount_path, logger: Lookbook.logger) : NullWebsocket.new
87
91
  end
@@ -150,7 +154,7 @@ module Lookbook
150
154
  def preview_watch_paths
151
155
  return @_preview_watch_paths if @_preview_watch_paths
152
156
 
153
- paths = [*opts.preview_paths, opts.components_path, *opts.listen_paths, *view_paths].uniq
157
+ paths = [*opts.preview_paths, *opts.component_paths, *opts.listen_paths, *view_paths].uniq
154
158
  @_preview_watch_paths ||= PathUtils.normalize_paths(paths)
155
159
  end
156
160
 
@@ -173,11 +177,13 @@ module Lookbook
173
177
  changed_files = [*changes[:added], *changes[:modified]] if changes
174
178
  parser.parse(changed_files) do |code_objects|
175
179
  previews.load(code_objects.all(:class), changes)
180
+ mark_changed
176
181
  end
177
182
  end
178
183
 
179
184
  def load_pages(changes = nil)
180
185
  pages.load(Engine.page_paths, changes)
186
+ mark_changed
181
187
  end
182
188
 
183
189
  def notify_clients(changes = nil)
@@ -192,6 +198,15 @@ module Lookbook
192
198
  reloaders.register_changes(changes)
193
199
  notify_clients(changes)
194
200
  end
201
+
202
+ def mark_changed
203
+ @_last_changed = (Time.now.to_f * 1000).to_i
204
+ end
205
+
206
+ def last_changed
207
+ mark_changed unless @_last_changed
208
+ @_last_changed
209
+ end
195
210
  end
196
211
 
197
212
  at_exit do
@@ -61,6 +61,10 @@ module Lookbook
61
61
  lookbook_inspect_path(lookup_path)
62
62
  end
63
63
 
64
+ def preview_path
65
+ lookbook_preview_path(lookup_path)
66
+ end
67
+
64
68
  def type
65
69
  :scenario
66
70
  end
@@ -24,7 +24,7 @@ module Lookbook
24
24
  end
25
25
 
26
26
  def render_targets
27
- @_render_targets ||= RenderTargetCollection.new(scenarios.flat_map(&:render_targets).uniq(&:path))
27
+ @_render_targets ||= RenderTargetCollection.new(scenarios.flat_map(&:render_targets).uniq(&:lookup_path))
28
28
  end
29
29
 
30
30
  def search_terms
@@ -43,6 +43,10 @@ module Lookbook
43
43
  lookbook_inspect_path(lookup_path)
44
44
  end
45
45
 
46
+ def preview_path
47
+ lookbook_preview_path(lookup_path)
48
+ end
49
+
46
50
  def type
47
51
  :group
48
52
  end
@@ -10,5 +10,9 @@ module Lookbook
10
10
  def lookbook_data(key, fallback = nil)
11
11
  Lookbook.data.fetch(key.to_sym, fallback)
12
12
  end
13
+
14
+ def url_for(*args)
15
+ main_app.url_for(*args)
16
+ end
13
17
  end
14
18
  end
@@ -5,7 +5,6 @@ module Lookbook
5
5
  included do
6
6
  helper PreviewHelper
7
7
  prepend_view_path Engine.root.join("app/views")
8
- before_action :permit_embeds
9
8
 
10
9
  def render_scenario_to_string(preview, scenario_name)
11
10
  prepend_application_view_paths
@@ -41,10 +40,6 @@ module Lookbook
41
40
  disable = Lookbook.config.preview_disable_action_view_annotations
42
41
  ActionViewAnnotationsHandler.call(disable_annotations: disable, &block)
43
42
  end
44
-
45
- def permit_embeds
46
- headers["X-Frame-Options"] = Lookbook.config.preview_embeds.policy
47
- end
48
43
  end
49
44
  end
50
45
  end
@@ -1,3 +1,3 @@
1
1
  module Lookbook
2
- VERSION = "2.0.0.beta.0"
2
+ VERSION = "2.0.0.beta.2"
3
3
  end