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 +4 -4
- data/README.md +30 -18
- data/app/assets/lookbook/js/components/copy.js +4 -2
- data/app/assets/lookbook/js/components/inspector.js +15 -7
- data/app/assets/lookbook/js/config.js +3 -2
- data/app/assets/lookbook/js/stores/inspector.js +3 -2
- data/app/controllers/lookbook/app_controller.rb +23 -11
- data/app/views/layouts/lookbook/app.html.erb +3 -1
- data/app/views/lookbook/components/_drawer.html.erb +38 -35
- data/app/views/lookbook/components/_header.html.erb +2 -2
- data/app/views/lookbook/components/_nav_preview.html.erb +4 -2
- data/app/views/lookbook/components/_preview.html.erb +65 -46
- data/app/views/lookbook/panels/_output.html.erb +1 -1
- data/app/views/lookbook/panels/_preview.html.erb +52 -0
- data/app/views/lookbook/show.html.erb +5 -54
- data/lib/lookbook/features.rb +1 -1
- data/lib/lookbook/version.rb +1 -1
- data/public/lookbook-assets/css/app.css +1 -1
- data/public/lookbook-assets/css/app.css.map +1 -1
- data/public/lookbook-assets/js/app.js +1 -1
- data/public/lookbook-assets/js/app.js.map +1 -1
- metadata +5 -5
- data/app/views/lookbook/components/_copy.html.erb +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0bf7750f26cce0e0b6517443da61e75a2d954b50c4882637a21fdac8b7d9c520
|
4
|
+
data.tar.gz: bb81e6a5cbb6db75b62591d6c233c1f1831db92e04045eafd372ae60264cc9fc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
-
|
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)
|
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"
|
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
|
533
|
-
- `
|
534
|
-
- `
|
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(
|
1
|
+
export default function copy() {
|
2
2
|
return {
|
3
3
|
get content() {
|
4
|
-
const target = document.getElementById(
|
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
|
-
|
36
|
-
return this
|
35
|
+
get maxDrawerHeight() {
|
36
|
+
return Math.round(this.height * 0.7);
|
37
37
|
},
|
38
|
-
|
39
|
-
this
|
38
|
+
get maxDrawerWidth() {
|
39
|
+
return Math.round(this.width * 0.7);
|
40
40
|
},
|
41
|
-
|
42
|
-
this.$store.inspector.
|
43
|
-
|
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:
|
12
|
+
defaultHeight: 300,
|
13
13
|
defaultWidth: 500,
|
14
14
|
minWidth: 350,
|
15
|
+
minHeight: 200,
|
15
16
|
},
|
16
17
|
preview: {
|
17
|
-
|
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
|
-
|
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
|
-
|
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
|
-
@
|
31
|
-
|
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
|
120
|
+
def preview_panels
|
123
121
|
{
|
124
|
-
|
125
|
-
label: "
|
126
|
-
template: "lookbook/panels/
|
127
|
-
|
122
|
+
preview: {
|
123
|
+
label: "Preview",
|
124
|
+
template: "lookbook/panels/preview",
|
125
|
+
srcdoc: Lookbook.config.preview_srcdoc ? render_examples(examples_data).gsub("\"", """) : nil,
|
126
|
+
hotkey: "v",
|
128
127
|
show: true,
|
129
128
|
disabled: false,
|
130
|
-
copy:
|
129
|
+
copy: false
|
131
130
|
},
|
132
131
|
output: {
|
133
|
-
label: "
|
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
|
-
|
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="
|
3
|
-
<div class="
|
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':
|
18
|
-
'border-transparent text-gray-500 hover:text-gray-700': !
|
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="
|
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.
|
49
|
-
'border-transparent text-gray-500 hover:text-gray-700': $store.inspector.drawer.
|
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();
|
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
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
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
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
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="
|
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="`
|
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="
|
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="
|
2
|
-
<button class="flex-none mr-
|
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
|
-
<%
|
10
|
-
|
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="
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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="
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
<
|
25
|
-
|
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
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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>
|
@@ -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>
|