lookbook 0.5.0.beta.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7838a877b435b1952e1eed9163cad4f21fa44b2578d9114430bfc1d262b15c23
4
- data.tar.gz: 4f8512d21d07f2b93164706569f0a28483f6b43e60446f19857411b4e66ac6ee
3
+ metadata.gz: 0bf7750f26cce0e0b6517443da61e75a2d954b50c4882637a21fdac8b7d9c520
4
+ data.tar.gz: bb81e6a5cbb6db75b62591d6c233c1f1831db92e04045eafd372ae60264cc9fc
5
5
  SHA512:
6
- metadata.gz: bf6f6045ce9ea8d5bca9932bfb3538e0e5c307b856cdbc0a209520be5112bed281f623cc879af59e51216f1d284aa2de08ed6ef1b483f794ea74c434a150bb13
7
- data.tar.gz: 4b2d545082ea784bc1122a51c947b0d5391cc829e895adfe224107591acdb68fabb23e8d21fe8be1f1d6acf405e774130dad1e1ba9676470a5bea9240f82cd34
6
+ metadata.gz: a569c06a48d6b30b8f328f25ad1eecfa474427d61dbf5a91395c780593329bb4424fdec52cb71d332dd229edc3d2031d9a9af84e864a4e906dcfcd7d387ea953
7
+ data.tar.gz: 1316810b7e32c5fda3ebd96b0d23566654f0a274fdaa730ae0ac50d5eaa03d0ed093ab412f504b1b0176cb37ecb26258d27f4aac081b6bce13bc754b6555c62d
data/README.md CHANGED
@@ -28,7 +28,7 @@ Lookbook uses [RDoc/Yard-style comment tags](#annotating-preview-files) to exten
28
28
  - Auto-updating UI when component or preview files are updated _(Rails v6.0+ only)_
29
29
  - Use comment tag annotations for granular customisation of the preview experience
30
30
  - Fully compatible with standard the ViewComponent preview system
31
- - [**Experimental**] In-browser live editable preview parameters (similar to Storybook Controls/Knobs)
31
+ - In-browser live-editable preview parameters (similar to basic Storybook Controls/Knobs)
32
32
 
33
33
  ## Lookbook demo
34
34
 
@@ -63,10 +63,16 @@ end
63
63
 
64
64
  The `at` property determines the root URL that the Lookbook UI will be served at.
65
65
 
66
- > If you would like to expose the Lookbook UI in production as well as in development, just remove the `if Rails.env.development?` condition from around the mount statement.
67
-
68
66
  Then you can start your app as normal and navigate to `http://localhost:3000/lookbook` (or whatever mount path you specified) to view your component previews in the Lookbook UI.
69
67
 
68
+ #### Mounting in Production
69
+
70
+ If you would like to expose the Lookbook UI in production as well as in development
71
+
72
+ 1. Remove the `if Rails.env.development?` condition from around the mount statement in `routes.rb`
73
+ 2. Add `config.view_component.show_previews = true` to `config/environments/production.rb`
74
+
75
+
70
76
  ## Usage
71
77
 
72
78
  You don't need to do anything special to see your ViewComponent previews and examples in Lookbook - just create them as normal and they'll automatically appear in the Lookbook UI. Preview templates, custom layouts and even bespoke [preview controllers](https://viewcomponent.org/guide/previews.html#configuring-preview-controller) should all work as you would expect.
@@ -96,7 +102,7 @@ class ButtonComponentPreview < ViewComponent::Preview
96
102
  # Button with icon
97
103
  # ----------------
98
104
  # This example uses dynamic preview parameters
99
- # which can be edited live in the Lookbook UI
105
+ # which can be edited live in the Lookbook UI
100
106
  #
101
107
  # @param text
102
108
  # @param icon select [heart, cog, alert]
@@ -161,7 +167,7 @@ The following Lookbook-specific tags are available for use:
161
167
  * [`@display`](#display-tag)
162
168
  * [`@!group ... @!endgroup`](#group-tag)
163
169
  * [`@hidden`](#hidden-tag)
164
- * [`@param`](#param-tag) [⚠️ **experimental!** - requires [feature opt-in](#experimental-features) ⚠️]
170
+ * [`@param`](#param-tag)
165
171
 
166
172
  <h3 id="label-tag">🏷 @label</h3>
167
173
 
@@ -311,9 +317,7 @@ class FooComponentPreview < ViewComponent::Preview
311
317
  end
312
318
  ```
313
319
 
314
- <h3 id="param-tag"> 🚧 @param (experimental)</h3>
315
-
316
- > ⚠️ This feature is currently flagged as an **experimental** feature which requires [feature opt-in](#experimental-features) to use. Its API and implementation may change in the future.
320
+ <h3 id="param-tag">@param</h3>
317
321
 
318
322
  The `@param` tag provides the ability to specify **editable preview parameters** which can be changed in the Lookbook UI in order to customise the rendered output on the fly, much like the [Controls (knobs) addon](https://storybook.js.org/addons/@storybook/addon-controls) for Storybook.
319
323
 
@@ -326,7 +330,7 @@ The `@param` tag takes the following format:
326
330
  ```
327
331
 
328
332
  - `<name>` - name of the dynamic preview param
329
- - `<input_type>` - input field type to generate in the UI
333
+ - `<input_type>` - input field type to generate in the UI
330
334
  - `<opts?>` - YAML-encoded field options, used for some field types
331
335
 
332
336
  #### Input types
@@ -357,7 +361,7 @@ The following **input field types** are available for use:
357
361
  @param <name> select <options>
358
362
  ```
359
363
 
360
- `<options>` should be a [YAML array](https://yaml.org/YAML_for_ruby.html#simple_inline_array) of options which must be formatted in the same style as the input for Rails' [`options_for_select`](https://apidock.com/rails/v6.0.0/ActionView/Helpers/FormOptionsHelper/options_for_select) helper:
364
+ `<options>` should be a [YAML array](https://yaml.org/YAML_for_ruby.html#simple_inline_array) of options which must be formatted in the same style as the input for Rails' [`options_for_select`](https://apidock.com/rails/v6.0.0/ActionView/Helpers/FormOptionsHelper/options_for_select) helper:
361
365
 
362
366
  ```ruby
363
367
  # Basic options:
@@ -437,7 +441,7 @@ The following structured types are also available but should be considered **exp
437
441
 
438
442
  ```ruby
439
443
  class ButtonComponentPreview < ViewComponent::Preview
440
-
444
+
441
445
  # The params defined below will be editable in the UI:
442
446
  #
443
447
  # @param content text
@@ -496,6 +500,17 @@ If you wish to add additional paths to listen for changes in, you can use the `l
496
500
  config.lookbook.listen_paths << Rails.root.join('app/other/directory')
497
501
  ```
498
502
 
503
+ ### Custom favicon
504
+
505
+ If you want to change the favicon used by the Lookbook UI, you can provide a path to your own (or a data-uri string) using the `ui_favicon` option:
506
+
507
+ ```ruby
508
+ config.lookbook.ui_favicon = "/path/to/my/favicon.png"
509
+ ```
510
+
511
+ > To disable the favicon entirely, set the value to `false`.
512
+
513
+
499
514
  <h3 id="experimental-features">Experimental features opt-in</h3>
500
515
 
501
516
  Some features may occasionally be released behind a 'experimental' feature flag while they are being tested and refined, to allow people to try them out and provide feedback.
@@ -510,10 +525,6 @@ To opt into individual experimental features, include the name of the feature in
510
525
  config.lookbook.experimental_features = ["feature_name"]
511
526
  ```
512
527
 
513
- The current experimental features that can be opted into are:
514
-
515
- - `params`: Live-editable, dynamic preview parameters ([read more](#param-tag)). Include `"params"` in the `experimental_features` config option to opt in.
516
-
517
528
  #### Opting into all experimental features (not recommended!)
518
529
 
519
530
  If you want to live life on the bleeding-edge you can opt-in to all current **and future** experimental features (usual caveats apply):
@@ -529,9 +540,10 @@ Lookbook provides a few keyboard shortcuts to help you quickly move around the U
529
540
 
530
541
  - `f` - move focus to the nav filter box
531
542
  - `Esc` [when focus is in nav filter box] - Clear contents if text is present, or return focus to the UI if the box is already empty
532
- - `s` - Switch to Source tab in the inspector
533
- - `o` - Switch to Output tab in the inspector
534
- - `n` - Switch to Notes tab in the inspector
543
+ - `s` - Switch to Source tab in the drawer
544
+ - `n` - Switch to Notes tab in the drawer
545
+ - `v` - Switch to the rendered preview
546
+ - `o` - Switch to the code preview
535
547
  - `r` - Refresh the preview (useful if using something like Faker to generate randomised data for the preview)
536
548
  - `w` - Open the standalone rendered preview in a new window
537
549
 
@@ -1,7 +1,9 @@
1
- export default function copy(id) {
1
+ export default function copy() {
2
2
  return {
3
3
  get content() {
4
- const target = document.getElementById(id);
4
+ const target = document.getElementById(
5
+ this.$root.getAttribute("data-target")
6
+ );
5
7
  return (target ? target.innerHTML : "").trim();
6
8
  },
7
9
  done: false,
@@ -32,15 +32,23 @@ export default function inspector() {
32
32
  get drawerHidden() {
33
33
  return this.$store.inspector.drawer.hidden;
34
34
  },
35
- isActivePanel(panel) {
36
- return this.$store.inspector.drawer.active == panel;
35
+ get maxDrawerHeight() {
36
+ return Math.round(this.height * 0.7);
37
37
  },
38
- switchPanel(panel) {
39
- this.$store.inspector.drawer.active = panel;
38
+ get maxDrawerWidth() {
39
+ return Math.round(this.width * 0.7);
40
40
  },
41
- toggleView() {
42
- this.$store.inspector.preview.view =
43
- this.view === "html" ? "preview" : "html";
41
+ isActiveDrawerPanel(panel) {
42
+ return this.$store.inspector.drawer.panel === panel;
43
+ },
44
+ switchDrawerPanel(panel) {
45
+ this.$store.inspector.drawer.panel = panel;
46
+ },
47
+ isActivePreviewPanel(panel) {
48
+ return this.$store.inspector.preview.panel === panel;
49
+ },
50
+ switchPreviewPanel(panel) {
51
+ this.$store.inspector.preview.panel = panel;
44
52
  },
45
53
  toggleOrientation() {
46
54
  this.$store.inspector.drawer.orientation =
@@ -9,12 +9,13 @@ export default {
9
9
  drawer: {
10
10
  orientation: "horizontal",
11
11
  defaultPanel: "source",
12
- defaultHeight: 200,
12
+ defaultHeight: 300,
13
13
  defaultWidth: 500,
14
14
  minWidth: 350,
15
+ minHeight: 200,
15
16
  },
16
17
  preview: {
17
- view: "preview",
18
+ defaultPanel: "preview",
18
19
  },
19
20
  },
20
21
  };
@@ -6,16 +6,17 @@ export default function createInspectorStore(Alpine) {
6
6
  drawer: {
7
7
  hidden: Alpine.$persist(false).as("drawer-hidden"),
8
8
  orientation: Alpine.$persist(drawer.orientation).as("drawer-orientation"),
9
- active: Alpine.$persist(drawer.defaultPanel).as("drawer-active"),
9
+ panel: Alpine.$persist(drawer.defaultPanel).as("drawer-panel"),
10
10
  height: Alpine.$persist(drawer.defaultHeight).as("drawer-height"),
11
11
  width: Alpine.$persist(drawer.defaultWidth).as("drawer-width"),
12
12
  minWidth: drawer.minWidth,
13
+ minHeight: drawer.minHeight,
13
14
  visibleTabCount: Infinity,
14
15
  },
15
16
  preview: {
16
17
  width: Alpine.$persist("100%").as("preview-width"),
17
18
  height: Alpine.$persist("100%").as("preview-height"),
18
- view: Alpine.$persist(preview.view).as("preview-view"),
19
+ panel: Alpine.$persist(preview.defaultPanel).as("preview-panel"),
19
20
  lastWidth: null,
20
21
  lastHeight: null,
21
22
  resizing: false,
@@ -27,10 +27,8 @@ module Lookbook
27
27
  begin
28
28
  set_params
29
29
  @examples = examples_data
30
- @preview_srcdoc = if Lookbook.config.preview_srcdoc
31
- render_examples(examples_data).gsub("\"", "&quot;")
32
- end
33
- @panels = panels.filter { |name, panel| panel[:show] }
30
+ @drawer_panels = drawer_panels.filter { |name, panel| panel[:show] }
31
+ @preview_panels = preview_panels.filter { |name, panel| panel[:show] }
34
32
  rescue *EXCEPTIONS
35
33
  render "error"
36
34
  end
@@ -119,23 +117,37 @@ module Lookbook
119
117
  @nav
120
118
  end
121
119
 
122
- def panels
120
+ def preview_panels
123
121
  {
124
- source: {
125
- label: "Source",
126
- template: "lookbook/panels/source",
127
- hotkey: "s",
122
+ preview: {
123
+ label: "Preview",
124
+ template: "lookbook/panels/preview",
125
+ srcdoc: Lookbook.config.preview_srcdoc ? render_examples(examples_data).gsub("\"", "&quot;") : nil,
126
+ hotkey: "v",
128
127
  show: true,
129
128
  disabled: false,
130
- copy: true
129
+ copy: false
131
130
  },
132
131
  output: {
133
- label: "Output",
132
+ label: "HTML",
134
133
  template: "lookbook/panels/output",
135
134
  hotkey: "o",
136
135
  show: true,
137
136
  disabled: false,
138
137
  copy: true
138
+ }
139
+ }
140
+ end
141
+
142
+ def drawer_panels
143
+ {
144
+ source: {
145
+ label: "Source",
146
+ template: "lookbook/panels/source",
147
+ hotkey: "s",
148
+ show: true,
149
+ disabled: false,
150
+ copy: true
139
151
  },
140
152
  notes: {
141
153
  label: "Notes",
@@ -6,7 +6,9 @@
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="/lookbook-assets/css/app.css?v=<%= Lookbook::VERSION %>" rel="stylesheet">
9
- <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>👀</text></svg>">
9
+ <% if config.ui_favicon != false %>
10
+ <link rel="icon" href="<%= config.ui_favicon || "data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>👀</text></svg>" %>">
11
+ <% end %>
10
12
 
11
13
  <% if config.auto_refresh %>
12
14
  <script>
@@ -1,10 +1,10 @@
1
1
  <div id="drawer" class="bg-white w-full h-full flex flex-col min-w-0">
2
- <div class="px-4 border-b border-gray-200 select-none flex-none" x-show="!drawerHidden">
3
- <div class="-mb-px flex cursor-auto relative">
2
+ <div class="pl-4 border-b border-gray-300 select-none flex-none" x-show="!drawerHidden">
3
+ <div class="flex cursor-auto relative">
4
4
  <div
5
5
  id="inspector-tabs-<%= example.id %>"
6
6
  x-data="tabs"
7
- class="min-w-0"
7
+ class="min-w-0 -mb-px"
8
8
  x-effect="$store.inspector.drawer.visibleTabCount = visibleTabCount"
9
9
  >
10
10
  <nav x-ref="tabs" class="flex h-10 space-x-8 flex-grow pr-8">
@@ -14,11 +14,11 @@
14
14
  href="#inspector-panel-<%= key %>"
15
15
  class="whitespace-nowrap pt-2.5 pb-1.5 px-1 border-b-2 cursor-pointer <%= "!text-gray-300" if props[:disabled] %>"
16
16
  :class="{
17
- 'border-indigo-400': isActivePanel('<%= key %>'),
18
- 'border-transparent text-gray-500 hover:text-gray-700': !isActivePanel('<%= key %>'),
17
+ 'border-indigo-400': isActiveDrawerPanel('<%= key %>'),
18
+ 'border-transparent text-gray-500 hover:text-gray-700': !isActiveDrawerPanel('<%= key %>'),
19
19
  'invisible': (<%= i %> > visibleTabCount)
20
20
  }"
21
- @click.stop.prevent="switchPanel('<%= key %>')"
21
+ @click.stop.prevent="switchDrawerPanel('<%= key %>')"
22
22
  <% if props[:hotkey] %>data-hotkey="<%= props[:hotkey] %>"<% end %>
23
23
  >
24
24
  <%== props[:label] %>
@@ -41,14 +41,13 @@
41
41
  <template id="inspector-dropdown-tab-<%= key %>-<%= example.id %>" x-if="<%= i %> > $store.inspector.drawer.visibleTabCount">
42
42
  <div :class="{'border-t border-gray-300': (<%= i %> > $store.inspector.drawer.visibleTabCount + 1)}">
43
43
  <a
44
-
45
44
  href="#inspector-panel-<%= key %>"
46
45
  class="block whitespace-nowrap py-2 px-4 border-l-2 cursor-pointer <%= "!text-gray-300" if props[:disabled] %>"
47
46
  :class="{
48
- 'border-indigo-400': $store.inspector.drawer.active === '<%= key %>',
49
- 'border-transparent text-gray-500 hover:text-gray-700': $store.inspector.drawer.active !== '<%= key %>',
47
+ 'border-indigo-400': $store.inspector.drawer.panel === '<%= key %>',
48
+ 'border-transparent text-gray-500 hover:text-gray-700': $store.inspector.drawer.panel !== '<%= key %>',
50
49
  }"
51
- @click.stop.prevent=" hideDropdown(); switchPanel('<%= key %>')"
50
+ @click.stop.prevent=" hideDropdown(); switchDrawerPanel('<%= key %>')"
52
51
  >
53
52
  <%== props[:label] %>
54
53
  </a>
@@ -58,31 +57,35 @@
58
57
  </div>
59
58
  </nav>
60
59
  </div>
61
- <div class="flex items-center ml-auto pl-8 space-x-3">
62
- <% panels.each do |key, props| %>
63
- <div
64
- ref="<%= "inspector-panel-#{example.id}-#{key}-copy" %>"
65
- class="flex items-center"
66
- :class="{'pointer-events-none opacity-30': <%= !props[:copy].present? %>}"
67
- x-show="isActivePanel('<%= key %>')"
68
- >
69
- <button
70
- class="text-gray-400 transition"
71
- x-data="copy('<%= "inspector-panel-#{example.id}-#{key}-clipboard" %>')"
72
- x-tooltip.theme.lookbook="done ? 'copied!' : 'copy to clipboard'"
73
- @click="save"
74
- :class="{
75
- '!text-green-600 hover:text-green-600': done,
76
- 'hover:text-indigo-500': !done}"
60
+ <div class="flex items-center bg-white border-l border-gray-200 ml-auto space-x-3 px-3">
61
+ <div>
62
+ <% panels.each do |key, props| %>
63
+ <div
64
+ ref="<%= "inspector-panel-#{example.id}-#{key}-copy" %>"
65
+ class="flex items-center"
66
+ :class="{'pointer-events-none opacity-30': <%= !props[:copy].present? %>}"
67
+ x-show="isActiveDrawerPanel('<%= key %>')"
77
68
  x-cloak
78
- <% unless props[:copy].present? %>disabled<% end %>
79
69
  >
80
- <%= icon "${done ? 'check' : 'clipboard'}", size: 4 %>
81
- </button>
82
- </div>
83
- <% end %>
70
+ <button
71
+ data-target="<%= "inspector-panel-#{example.id}-#{key}-clipboard" %>"
72
+ class="text-gray-400 transition"
73
+ x-data="copy"
74
+ x-tooltip.theme.lookbook="done ? 'copied!' : 'copy to clipboard'"
75
+ @click="save"
76
+ :class="{
77
+ '!text-green-600 hover:text-green-600': done,
78
+ 'hover:text-indigo-500': !done}"
79
+ x-cloak
80
+ <% unless props[:copy].present? %>disabled<% end %>
81
+ >
82
+ <%= icon "${done ? 'check' : 'clipboard'}", size: 4 %>
83
+ </button>
84
+ </div>
85
+ <% end %>
86
+ </div>
84
87
  <button
85
- x-tooltip.theme.lookbook="`switch orientation`"
88
+ x-tooltip.theme.lookbook="`${horizontal ? 'pin drawer on right' : 'pin drawer on bottom'}`"
86
89
  @click="toggleOrientation"
87
90
  :class="{'pointer-events-none opacity-30': !canBeVertical}"
88
91
  >
@@ -91,10 +94,10 @@
91
94
  class: "scale-[-1] text-gray-400 hover:text-indigo-800" %>
92
95
  </button>
93
96
  <button
94
- x-tooltip.theme.lookbook="`close drawer`"
97
+ x-tooltip.theme.lookbook="`hide drawer`"
95
98
  @click="toggleDrawer"
96
99
  >
97
- <%= icon "x",
100
+ <%= icon "x-circle",
98
101
  size: 4,
99
102
  class: "text-gray-400 hover:text-indigo-800" %>
100
103
  </button>
@@ -105,7 +108,7 @@
105
108
  <% panels.each do |key, props| %>
106
109
  <div
107
110
  class="h-full w-full absolute inset-0"
108
- x-show="$store.inspector.drawer.active === '<%= key %>'"
111
+ x-show="isActiveDrawerPanel('<%= key %>')"
109
112
  x-cloak
110
113
  >
111
114
  <div id="inspector-panel-<%= example.id %>-<%= key %>" class="h-full">
@@ -1,5 +1,5 @@
1
- <header class="py-2 px-4 w-full flex-none bg-white border-b border-gray-300 flex items-center h-10 select-none min-w-0">
2
- <button class="flex-none mr-3" x-show="!$store.layout.desktop" @click="$store.sidebar.toggle">
1
+ <header class="pl-4 w-full flex-none bg-white border-b border-gray-300 flex items-center h-10 select-none min-w-0">
2
+ <button class="flex-none mr-6" x-show="!$store.layout.desktop" @click="$store.sidebar.toggle">
3
3
  <svg class="feather w-5 h-5 hover:text-indigo-500 transition">
4
4
  <use xlink:href="/lookbook-assets/feather-sprite.svg#menu" />
5
5
  </svg>
@@ -6,6 +6,8 @@
6
6
  <% end %>
7
7
  <% end %>
8
8
  <% else %>
9
- <% example = examples.first %>
10
- <%= component "nav_item", item: example, depth: example.hierarchy_depth, label: node.label, display: :node %>
9
+ <% if examples.any? %>
10
+ <% example = examples.first %>
11
+ <%= component "nav_item", item: example, depth: example.hierarchy_depth, label: node.label, display: :node %>
12
+ <% end %>
11
13
  <% end %>
@@ -1,52 +1,71 @@
1
- <div id="preview" class="h-auto min-h-0 w-full checked-bg">
2
- <div
3
- class="mx-auto h-full w-full"
4
- :style="`max-width: ${maxWidth}; max-height: ${maxHeight};`"
5
- x-data="previewWindow"
6
- >
7
- <div class="grid bg-white relative grid-cols-[1fr_17px] grid-rows-[1fr_17px] -inset-px" style="width: calc(100% + 2px); height: calc(100% + 2px)">
8
-
9
- <iframe seamless
10
- class="h-full w-full border border-gray-300"
11
- :class="{ 'pointer-events-none': $store.layout.reflowing }"
12
- src="<%= lookbook.preview_path(request.query_parameters) %>"
13
- <% if config.preview_srcdoc %>srcdoc="<%== srcdoc %>"<% end %>
14
- frameborder="0"
15
- x-data="sizes"
16
- x-effect="preview.width = width; preview.height = height;"
17
- ></iframe>
18
-
1
+ <div id="preview" class="grid grid-rows-[40px_1fr]">
2
+ <%= component "header" do %>
3
+ <div
4
+ id="preview-tabs-<%= @example.id %>" class="min-w-0 -mb-px">
5
+ <nav class="flex h-10 space-x-8 flex-grow pr-8">
6
+ <% panels.each do |key, props| %>
7
+ <a
8
+ id="preview-tab-<%= key %>-<%= @example.id %>"
9
+ href="#preview-panel-<%= key %>"
10
+ class="whitespace-nowrap pt-2.5 pb-1.5 px-1 border-b-2 cursor-pointer"
11
+ :class="{
12
+ 'border-indigo-400': isActivePreviewPanel('<%= key %>'),
13
+ 'border-transparent text-gray-500 hover:text-gray-700': !isActivePreviewPanel('<%= key %>'),
14
+ }"
15
+ @click.stop.prevent="switchPreviewPanel('<%= key %>')"
16
+ <% if props[:hotkey] %>data-hotkey="<%= props[:hotkey] %>"<% end %>
17
+ >
18
+ <%== props[:label] %>
19
+ </a>
20
+ <% end %>
21
+ </nav>
22
+ </div>
23
+ <div class="flex items-stretch h-full ml-auto space-x-3">
19
24
  <div
20
- class="resize-handle border-r border-t cursor-[col-resize]"
21
- @pointerdown="onResizeWidthStart"
22
- @dblclick="toggleFullWidth"
23
- >
24
- <svg class="h-4 w-4 pointer-events-none" fill="currentColor" viewBox="0 0 24 24">
25
- <path d="M8 5h2v14H8zM14 5h2v14h-2z"></path>
26
- </svg>
25
+ class="flex items-center text-xs font-monospace text-gray-700 space-x-1 opacity-50 hover:opacity-100 transition"
26
+ :class="{'opacity-100': $store.inspector.preview.resizing}"
27
+ x-show="isActivePreviewPanel('preview')">
28
+ <span x-text="`${preview.width}px`"></span>
29
+ <span class="text-gray-500">x</span>
30
+ <span x-text="`${preview.height}px`"></span>
27
31
  </div>
28
-
29
- <div
30
- class="resize-handle border-b border-l cursor-[col-resize]"
31
- @pointerdown="onResizeHeightStart"
32
- @dblclick="toggleFullHeight"
33
- >
34
- <svg class="h-4 w-4 pointer-events-none rotate-90" fill="currentColor" viewBox="0 0 24 24" >
35
- <path d="M8 5h2v14H8zM14 5h2v14h-2z"></path>
36
- </svg>
32
+ <div class="flex items-center bg-white border-l border-gray-200 space-x-3 text-gray-400 divide-x divide-gray-300 px-3">
33
+ <div class="flex items-center space-x-3">
34
+ <button
35
+ x-tooltip.theme.lookbook="`Refresh preview`"
36
+ @click.prevent.stop="refresh"
37
+ data-hotkey="r"
38
+ >
39
+ <%= icon "refresh-cw", size: 4, class: "hover:text-indigo-800" %>
40
+ </button>
41
+ <a
42
+ href="<%= preview_path %>"
43
+ target="_blank"
44
+ x-tooltip.theme.lookbook="`Open in new window`"
45
+ data-hotkey="w"
46
+ >
47
+ <%= icon "external-link", size: 4, class: "hover:text-indigo-800" %>
48
+ </a>
49
+ <button
50
+ x-tooltip.theme.lookbook="`${drawerHidden ? 'show' : 'hide'} drawer`"
51
+ @click="toggleDrawer"
52
+ x-show="drawerHidden"
53
+ data-hotkey="i"
54
+ >
55
+ <%= icon "${horizontal ? 'credit-card' : 'sidebar'}", size: 4, class: "hover:text-indigo-800 scale-[-1]" %>
56
+ </button>
57
+ </div>
58
+
37
59
  </div>
38
-
39
- <div
40
- class="resize-handle border-r border-b cursor-[nwse-resize]"
41
- @pointerdown="onResizeStart"
42
- @dblclick="toggleFullSize"
43
- >
44
- <svg class="h-3.5 w-3.5 pointer-events-none rotate-45 relative -top-px -left-px" fill="currentColor" viewBox="0 0 24 24" >
45
- <path d="M8 5h2v14H8zM14 5h2v14h-2z"></path>
46
- </svg>
47
- </div>
48
-
49
60
  </div>
50
-
61
+ <% end %>
62
+ <div class="bg-white relative flex-grow">
63
+ <% panels.each do |key, props| %>
64
+ <div class="h-full w-full absolute inset-0" x-show="isActivePreviewPanel('<%= key %>')" x-cloak>
65
+ <div id="preview-panel-<%= example.id %>-<%= key %>" class="h-full">
66
+ <%= render props[:template], key: key, examples: examples, **props %>
67
+ </div>
68
+ </div>
69
+ <% end %>
51
70
  </div>
52
71
  </div>
@@ -1,4 +1,4 @@
1
- <div class="p-4 h-full bg-gray-50 overflow-auto" data-morph-strategy="replace">
1
+ <div class="p-4 h-full bg-white overflow-auto" data-morph-strategy="replace">
2
2
  <%= component "code", wrap: "vertical" do -%>
3
3
  <% if examples.many? %>
4
4
  <% examples.each do |example| -%>
@@ -0,0 +1,52 @@
1
+ <div id="preview-window" class="h-full min-h-0 w-full checked-bg">
2
+ <div
3
+ class="mx-auto h-full w-full"
4
+ :style="`max-width: ${maxWidth}; max-height: ${maxHeight};`"
5
+ x-data="previewWindow"
6
+ >
7
+ <div class="grid bg-white relative grid-cols-[1fr_17px] grid-rows-[1fr_17px] -inset-px" style="width: calc(100% + 2px); height: calc(100% + 2px)">
8
+
9
+ <iframe seamless
10
+ class="h-full w-full border border-gray-300"
11
+ :class="{ 'pointer-events-none': $store.layout.reflowing }"
12
+ src="<%= lookbook.preview_path(request.query_parameters) %>"
13
+ <% if config.preview_srcdoc %>srcdoc="<%== srcdoc %>"<% end %>
14
+ frameborder="0"
15
+ x-data="sizes"
16
+ x-effect="preview.width = width; preview.height = height;"
17
+ ></iframe>
18
+
19
+ <div
20
+ class="resize-handle border-r border-t cursor-[col-resize]"
21
+ @pointerdown="onResizeWidthStart"
22
+ @dblclick="toggleFullWidth"
23
+ >
24
+ <svg class="h-4 w-4 pointer-events-none" fill="currentColor" viewBox="0 0 24 24">
25
+ <path d="M8 5h2v14H8zM14 5h2v14h-2z"></path>
26
+ </svg>
27
+ </div>
28
+
29
+ <div
30
+ class="resize-handle border-b border-l cursor-[col-resize]"
31
+ @pointerdown="onResizeHeightStart"
32
+ @dblclick="toggleFullHeight"
33
+ >
34
+ <svg class="h-4 w-4 pointer-events-none rotate-90" fill="currentColor" viewBox="0 0 24 24" >
35
+ <path d="M8 5h2v14H8zM14 5h2v14h-2z"></path>
36
+ </svg>
37
+ </div>
38
+
39
+ <div
40
+ class="resize-handle border-r border-b cursor-[nwse-resize]"
41
+ @pointerdown="onResizeStart"
42
+ @dblclick="toggleFullSize"
43
+ >
44
+ <svg class="h-3.5 w-3.5 pointer-events-none rotate-45 relative -top-px -left-px" fill="currentColor" viewBox="0 0 24 24" >
45
+ <path d="M8 5h2v14H8zM14 5h2v14h-2z"></path>
46
+ </svg>
47
+ </div>
48
+
49
+ </div>
50
+
51
+ </div>
52
+ </div>