lookbook 0.4.1 → 0.4.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +220 -53
- data/app/assets/lookbook/css/app.css +14 -8
- data/app/assets/lookbook/js/app.js +2 -0
- data/app/assets/lookbook/js/nav.js +5 -6
- data/app/assets/lookbook/js/page.js +5 -0
- data/app/assets/lookbook/js/utils/morph.js +3 -0
- data/app/assets/lookbook/js/workbench/param.js +19 -0
- data/app/controllers/lookbook/app_controller.rb +24 -7
- data/app/helpers/lookbook/application_helper.rb +6 -1
- data/app/helpers/lookbook/preview_helper.rb +7 -0
- data/app/views/lookbook/workbench/_inspector.html.erb +6 -1
- data/app/views/lookbook/workbench/inspector/_params.html.erb +28 -0
- data/app/views/lookbook/workbench/inspector/params/_select.html.erb +8 -0
- data/app/views/lookbook/workbench/inspector/params/_text.html.erb +8 -0
- data/app/views/lookbook/workbench/inspector/params/_textarea.html.erb +8 -0
- data/app/views/lookbook/workbench/inspector/params/_toggle.html.erb +13 -0
- data/lib/lookbook/engine.rb +6 -0
- data/lib/lookbook/features.rb +24 -0
- data/lib/lookbook/params.rb +110 -0
- data/lib/lookbook/parser.rb +1 -1
- data/lib/lookbook/preview.rb +1 -1
- data/lib/lookbook/preview_controller.rb +2 -3
- data/lib/lookbook/preview_example.rb +13 -1
- data/lib/lookbook/preview_group.rb +5 -1
- data/lib/lookbook/taggable.rb +2 -2
- data/lib/lookbook/version.rb +1 -1
- data/lib/lookbook.rb +2 -0
- data/public/lookbook-assets/app.css +129 -7
- data/public/lookbook-assets/app.js +46 -8
- metadata +12 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 676b8a78237532971ec7d22d7265b3da7d3b896aa8020d7ab1c514edc3859b45
|
4
|
+
data.tar.gz: dfb016bf927d7492afdeacd3b10a2425563e227b5cbd4ebd4d3f7a5bfa97609f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2e5aeb26c2db3322e7aa127e176b691744d5af3cfbd207159f65d0e9dee1362382f418b07bda2fa7b75d7f85b35f522efe106707e665c6e12f9ab5e4ca1f4cd1
|
7
|
+
data.tar.gz: be2908ed45f9645dd9387adf6547c8c45ba262310325438197de22d6db9909705fa3e45de0912914004d516c4546618ccc73fd96fea3fbdc86f2affa5e7ebb3d
|
data/README.md
CHANGED
@@ -28,6 +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
32
|
|
32
33
|
## Lookbook demo
|
33
34
|
|
@@ -76,7 +77,7 @@ Lookbook parses [Yard-style comment tags](https://rubydoc.info/gems/yard/file/do
|
|
76
77
|
|
77
78
|
```ruby
|
78
79
|
# @label Basic Button
|
79
|
-
# @display bg_color
|
80
|
+
# @display bg_color #fff
|
80
81
|
class ButtonComponentPreview < ViewComponent::Preview
|
81
82
|
|
82
83
|
# Primary button
|
@@ -90,11 +91,24 @@ class ButtonComponentPreview < ViewComponent::Preview
|
|
90
91
|
end
|
91
92
|
end
|
92
93
|
|
94
|
+
# Button with icon
|
95
|
+
# ----------------
|
96
|
+
# This example uses dynamic preview parameters
|
97
|
+
# which can be edited live in the Lookbook UI
|
98
|
+
#
|
99
|
+
# @param text
|
100
|
+
# @param icon select [heart, cog, alert]
|
101
|
+
def icon(text: "Spread the love", icon: "heart")
|
102
|
+
render ButtonComponent.new(icon: icon) do
|
103
|
+
text
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
93
107
|
# Inverted button
|
94
108
|
# ---------------
|
95
109
|
# For light-on-dark screens
|
96
110
|
#
|
97
|
-
# @display bg_color
|
111
|
+
# @display bg_color #000
|
98
112
|
def secondary
|
99
113
|
render ButtonComponent.new(style: :inverted) do
|
100
114
|
"Click me"
|
@@ -141,54 +155,41 @@ end
|
|
141
155
|
|
142
156
|
The following Lookbook-specific tags are available for use:
|
143
157
|
|
144
|
-
* `@label
|
145
|
-
* `@
|
146
|
-
*
|
147
|
-
*
|
158
|
+
* [`@label`](#label-tag)
|
159
|
+
* [`@display`](#display-tag)
|
160
|
+
* [`@!group ... @!endgroup`](#group-tag)
|
161
|
+
* [`@hidden`](#hidden-tag)
|
162
|
+
* [`@param`](#param-tag) [⚠️ **experimental!** - requires [feature opt-in](#experimental-features) ⚠️]
|
148
163
|
|
149
|
-
|
164
|
+
<h3 id="label-tag">🏷 @label</h3>
|
150
165
|
|
151
166
|
Used to replace the auto-generated navigation label for the item with `<text>`.
|
152
167
|
|
153
|
-
> Available for preview classes & example methods.
|
154
|
-
|
155
168
|
```ruby
|
156
|
-
|
157
|
-
class FooComponentPreview < ViewComponent::Preview
|
158
|
-
|
159
|
-
# @label Example Label
|
160
|
-
def default
|
161
|
-
end
|
162
|
-
end
|
169
|
+
@label <text>
|
163
170
|
```
|
164
171
|
|
165
|
-
|
166
|
-
|
167
|
-
Used to temporarily exclude an item from the Lookbook navigation. The item will still be accessible via it's URL.
|
168
|
-
|
169
|
-
Can be useful when a component (or a variant of a component) is still in development and is not ready to be shared with the wider team.
|
170
|
-
|
171
|
-
> Available for both preview classes & example methods.
|
172
|
+
> Available for preview classes & example methods.
|
172
173
|
|
173
174
|
```ruby
|
174
|
-
# @
|
175
|
+
# @label Preview Label
|
175
176
|
class FooComponentPreview < ViewComponent::Preview
|
176
177
|
|
177
|
-
# @
|
178
|
+
# @label Example Label
|
178
179
|
def default
|
179
180
|
end
|
180
181
|
end
|
181
182
|
```
|
182
183
|
|
183
|
-
|
184
|
+
<h3 id="display-tag">🏷 @display</h3>
|
184
185
|
|
185
186
|
The `@display` tag lets you pass custom parameters to your preview layout so that the component preview can be customised on a per-example basis.
|
186
187
|
|
187
188
|
```ruby
|
188
|
-
# @display bg_color
|
189
|
+
# @display bg_color #eee
|
189
190
|
class FooComponentPreview < ViewComponent::Preview
|
190
191
|
|
191
|
-
# @display max_width
|
192
|
+
# @display max_width 500px
|
192
193
|
# @display wrapper true
|
193
194
|
def default
|
194
195
|
end
|
@@ -198,13 +199,11 @@ end
|
|
198
199
|
The `@display` tag can be applied at the preview (class) or at the example (method) level, and takes the following format:
|
199
200
|
|
200
201
|
```ruby
|
201
|
-
|
202
|
+
@display <key> <value>
|
202
203
|
```
|
203
204
|
|
204
205
|
- `<key>` must be a valid Ruby hash key name, without quotes or spaces
|
205
|
-
- `<value>`
|
206
|
-
|
207
|
-
> [See below for some examples](#some-display-value-examples) of valid and invalid `@display` values.
|
206
|
+
- `<value>` will be parsed using the [Ruby YAML parser](https://yaml.org/YAML_for_ruby.html) to resolve the value
|
208
207
|
|
209
208
|
These display parameters can then be accessed via the `params` hash in your preview layout using `params[:lookbook][:display][<key>]`:
|
210
209
|
|
@@ -244,27 +243,7 @@ config.lookbook.preview_display_params = {
|
|
244
243
|
|
245
244
|
Globally defined display params will be available to all previews. Any preview or example-level `@display` values with the same name will take precedence and override a globally-set one.
|
246
245
|
|
247
|
-
|
248
|
-
|
249
|
-
Valid:
|
250
|
-
|
251
|
-
```ruby
|
252
|
-
# @display body_classes "bg-red border border-4 border-green"
|
253
|
-
# @display wrap_in_container true
|
254
|
-
# @display emojis_to_show 4
|
255
|
-
# @display page_title "Special example title"
|
256
|
-
```
|
257
|
-
|
258
|
-
Invalid:
|
259
|
-
|
260
|
-
```ruby
|
261
|
-
# @display body_classes 'bg-red border border-4 border-green' [❌ single quotes]
|
262
|
-
# @display wrap_in_container should_wrap [❌ unquoted string, perhaps trying to call a method]
|
263
|
-
# @display page title "Special example title" [❌ space in key]
|
264
|
-
# @display bg_color #fff [❌ colors need quotes around them, it's not CSS!]
|
265
|
-
```
|
266
|
-
|
267
|
-
### 🔖 `@!group <name> ... @!endgroup`
|
246
|
+
<h3 id="group-tag">🔖 `@!group ... @!endgroup`</h3>
|
268
247
|
|
269
248
|
For smaller components, it can often make sense to render a set of preview examples in a single window, rather than representing them as individual items in the navigation which can start to look a bit cluttered.
|
270
249
|
|
@@ -310,6 +289,167 @@ The example above would display the `Sizes` examples grouped together on a singl
|
|
310
289
|
|
311
290
|
You can have as many groups as you like within a single preview class, but each example can only belong to one group.
|
312
291
|
|
292
|
+
<h3 id="hidden-tag">🏷 `@hidden`</h3>
|
293
|
+
|
294
|
+
Used to temporarily exclude an item from the Lookbook navigation. The item will still be accessible via it's URL.
|
295
|
+
|
296
|
+
Can be useful when a component (or a variant of a component) is still in development and is not ready to be shared with the wider team.
|
297
|
+
|
298
|
+
> Available for both preview classes & example methods.
|
299
|
+
|
300
|
+
```ruby
|
301
|
+
# @hidden
|
302
|
+
class FooComponentPreview < ViewComponent::Preview
|
303
|
+
|
304
|
+
# @hidden
|
305
|
+
def default
|
306
|
+
end
|
307
|
+
end
|
308
|
+
```
|
309
|
+
|
310
|
+
<h3 id="param-tag"> 🚧 @param (experimental)</h3>
|
311
|
+
|
312
|
+
> ⚠️ 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.
|
313
|
+
|
314
|
+
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.
|
315
|
+
|
316
|
+
Each `@param` will have an associated form field generated for it. The values for each field will be handled as [dynamic preview params](https://viewcomponent.org/guide/previews.html#:~:text=It%E2%80%99s%20also%20possible%20to%20set%20dynamic%20values%20from%20the%20params%20by%20setting%20them%20as%20arguments%3A) when rendering the example.
|
317
|
+
|
318
|
+
The `@param` tag takes the following format:
|
319
|
+
|
320
|
+
```ruby
|
321
|
+
@param <name> <input_type> <opts?>
|
322
|
+
```
|
323
|
+
|
324
|
+
- `<name>` - name of the dynamic preview param
|
325
|
+
- `<input_type>` - input field type to generate in the UI
|
326
|
+
- `<opts?>` - YAML-encoded field options, used for some field types
|
327
|
+
|
328
|
+
#### Input types
|
329
|
+
|
330
|
+
The following **input field types** are available for use:
|
331
|
+
|
332
|
+
📝 **Text-style inputs** - Single line fields, useful for short strings of text or numbers.
|
333
|
+
|
334
|
+
```ruby
|
335
|
+
@param <name> text
|
336
|
+
@param <name> email
|
337
|
+
@param <name> number
|
338
|
+
@param <name> url
|
339
|
+
@param <name> tel
|
340
|
+
```
|
341
|
+
|
342
|
+
> The above types only differ in the validation constraints they impose on the input field.
|
343
|
+
|
344
|
+
📝 **Textarea** - Multi-line textarea field for longer-form content.
|
345
|
+
|
346
|
+
```ruby
|
347
|
+
@param <name> textarea
|
348
|
+
```
|
349
|
+
|
350
|
+
📝 **Select box** - Dropdown select field for selecting from a list of known options.
|
351
|
+
|
352
|
+
```ruby
|
353
|
+
@param <name> select <options>
|
354
|
+
```
|
355
|
+
|
356
|
+
`<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:
|
357
|
+
|
358
|
+
```ruby
|
359
|
+
# Basic options:
|
360
|
+
# @param theme select [primary, secondary, danger]
|
361
|
+
|
362
|
+
# With custom labels (each item itself an array of [label, value]):
|
363
|
+
# @param theme select [[Primary theme, primary], [Secondary theme, secondary], [Danger theme, danger]]
|
364
|
+
|
365
|
+
# With empty option (`~` in YAML)
|
366
|
+
# @param theme select [~, primary, secondary, danger]
|
367
|
+
```
|
368
|
+
|
369
|
+
> **Note**: In most cases YAML does not require quoting of strings, however if you are running into issues check out the [Ruby YAML docs](https://yaml.org/YAML_for_ruby.html) for a complete syntax reference.
|
370
|
+
|
371
|
+
📝 **Toggle** - On/off switch for toggling boolean values.
|
372
|
+
|
373
|
+
```ruby
|
374
|
+
@param <name> toggle
|
375
|
+
```
|
376
|
+
|
377
|
+
#### Default values
|
378
|
+
|
379
|
+
Default values are specified as part of the preview example method parameters in the usual Ruby way:
|
380
|
+
|
381
|
+
```ruby
|
382
|
+
def button(content: "Click me", theme: "primary", arrow: false)
|
383
|
+
# ...
|
384
|
+
end
|
385
|
+
```
|
386
|
+
|
387
|
+
These will be used as the default values for the param fields.
|
388
|
+
|
389
|
+
> Note that the default values are **not** evaluated at runtime, so you cannot use method calls to generate the defaults. Only static default values are supported.
|
390
|
+
|
391
|
+
#### Type casting values
|
392
|
+
|
393
|
+
Most dynamic param values are passed to the example method as strings, with the following exceptions:
|
394
|
+
|
395
|
+
- `toggle` input - values are cast to booleans
|
396
|
+
- `number` input - values are cast to integers
|
397
|
+
|
398
|
+
In some cases, you may want to type cast the parameter value to something else (for example a `Symbol`) before using it when initializing the component.
|
399
|
+
|
400
|
+
To help with this, a `type` option can be specified in the `@param` definition to automatically cast the dynamic value to a different type:
|
401
|
+
|
402
|
+
```ruby
|
403
|
+
# @param <name> [<type>] <input_type> <opts?>
|
404
|
+
```
|
405
|
+
|
406
|
+
In the example below, the value of the `theme` param (by default a string) will be automatically cast to a Symbol, ready for use in instantiating the component.
|
407
|
+
|
408
|
+
```ruby
|
409
|
+
# @param theme [Symbol] select [primary, secondary, danger]
|
410
|
+
def default(theme: :primary)
|
411
|
+
render Elements::ButtonComponent.new(theme: theme) do
|
412
|
+
"Click me"
|
413
|
+
end
|
414
|
+
end
|
415
|
+
```
|
416
|
+
|
417
|
+
The supported types to cast to are:
|
418
|
+
|
419
|
+
- `String` - *default for all except `toggle` inputs*
|
420
|
+
- `Boolean` - *default for `toggle` inputs*
|
421
|
+
- `Symbol`
|
422
|
+
- `Date`
|
423
|
+
- `DateTime`
|
424
|
+
- `Integer`
|
425
|
+
- `Float`
|
426
|
+
|
427
|
+
The following structured types are also available but should be considered **experimental** - you may run into bugs!
|
428
|
+
|
429
|
+
- `Hash` - *value string converted to Hash using the Ruby YAML parser*
|
430
|
+
- `Array` - *value string converted to Array using the Ruby YAML parser*
|
431
|
+
|
432
|
+
#### Full example:
|
433
|
+
|
434
|
+
```ruby
|
435
|
+
class ButtonComponentPreview < ViewComponent::Preview
|
436
|
+
|
437
|
+
# The params defined below will be editable in the UI:
|
438
|
+
#
|
439
|
+
# @param content text
|
440
|
+
# @param theme select [primary, secondary, danger]
|
441
|
+
# @param arrow toggle
|
442
|
+
def default(content: "Click me", theme: "primary", arrow: true)
|
443
|
+
render Elements::ButtonComponent.new(theme: theme, arrow: arrow) do
|
444
|
+
content
|
445
|
+
end
|
446
|
+
end
|
447
|
+
|
448
|
+
end
|
449
|
+
```
|
450
|
+
|
451
|
+
<img src=".github/assets/dynamic_params.png">
|
452
|
+
|
313
453
|
### Adding notes
|
314
454
|
|
315
455
|
All comment text other than tags will be treated as markdown and rendered in the **Notes** panel for that example in the Lookbook UI.
|
@@ -352,6 +492,33 @@ If you wish to add additional paths to listen for changes in, you can use the `l
|
|
352
492
|
config.lookbook.listen_paths << Rails.root.join('app/other/directory')
|
353
493
|
```
|
354
494
|
|
495
|
+
<h3 id="experimental-features">Experimental features opt-in</h3>
|
496
|
+
|
497
|
+
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.
|
498
|
+
|
499
|
+
> ⚠️ **Please note:** Experimental features should be considered to be **subject to extensive change** and breaking changes to them may be made within point releases - these features are **not** considered to be covered by [semver](https://semver.org/) whilst flagged as 'experimental'. ⚠️
|
500
|
+
|
501
|
+
#### Opting into specific features (recommended)
|
502
|
+
|
503
|
+
To opt into individual experimental features, include the name of the feature in the `experimental_features` config option:
|
504
|
+
|
505
|
+
```ruby
|
506
|
+
config.lookbook.experimental_features = ["feature_name"]
|
507
|
+
```
|
508
|
+
|
509
|
+
The current experimental features that can be opted into are:
|
510
|
+
|
511
|
+
- `params`: Live-editable, dynamic preview parameters ([read more](#param-tag)). Include `"params"` in the `experimental_features` config option to opt in.
|
512
|
+
|
513
|
+
#### Opting into all experimental features (not recommended!)
|
514
|
+
|
515
|
+
If you want to live life on the bleeding-edge you can opt-in to all current **and future** experimental features (usual caveats apply):
|
516
|
+
|
517
|
+
```ruby
|
518
|
+
config.lookbook.experimental_features = true
|
519
|
+
```
|
520
|
+
|
521
|
+
|
355
522
|
## Keyboard shortcuts
|
356
523
|
|
357
524
|
Lookbook provides a few keyboard shortcuts to help you quickly move around the UI.
|
@@ -35,14 +35,6 @@
|
|
35
35
|
fill: none;
|
36
36
|
}
|
37
37
|
|
38
|
-
.h-fill {
|
39
|
-
height: fill-available;
|
40
|
-
}
|
41
|
-
|
42
|
-
.min-h-fill {
|
43
|
-
min-height: fill-available;
|
44
|
-
}
|
45
|
-
|
46
38
|
::-webkit-scrollbar {
|
47
39
|
width: 8px;
|
48
40
|
height: 8px;
|
@@ -63,3 +55,17 @@
|
|
63
55
|
@apply bg-gray-400;
|
64
56
|
}
|
65
57
|
}
|
58
|
+
|
59
|
+
@layer utilities {
|
60
|
+
.h-fill {
|
61
|
+
height: fill-available;
|
62
|
+
}
|
63
|
+
|
64
|
+
.min-h-fill {
|
65
|
+
min-height: fill-available;
|
66
|
+
}
|
67
|
+
|
68
|
+
.form-input {
|
69
|
+
@apply border-gray-300 text-gray-700 focus:ring-indigo-300 focus:border-indigo-300 rounded-sm text-sm w-full;
|
70
|
+
}
|
71
|
+
}
|
@@ -9,6 +9,7 @@ import page from "./page";
|
|
9
9
|
import workbench from "./workbench";
|
10
10
|
import preview from "./workbench/preview";
|
11
11
|
import inspector from "./workbench/inspector";
|
12
|
+
import param from "./workbench/param";
|
12
13
|
import nav from "./nav";
|
13
14
|
import navNode from "./nav/node";
|
14
15
|
import navLeaf from "./nav/leaf";
|
@@ -56,6 +57,7 @@ Alpine.data("navLeaf", navLeaf);
|
|
56
57
|
Alpine.data("workbench", workbench);
|
57
58
|
Alpine.data("preview", preview);
|
58
59
|
Alpine.data("inspector", inspector);
|
60
|
+
Alpine.data("param", param);
|
59
61
|
Alpine.data("clipboard", clipboard);
|
60
62
|
Alpine.data("sizeObserver", sizeObserver);
|
61
63
|
Alpine.data("split", split);
|
@@ -22,13 +22,12 @@ export default function () {
|
|
22
22
|
});
|
23
23
|
},
|
24
24
|
navigate(path) {
|
25
|
-
|
26
|
-
path = path.currentTarget.href;
|
27
|
-
}
|
28
|
-
history.pushState({}, null, path);
|
29
|
-
this.$dispatch("popstate");
|
25
|
+
this.navigateTo(path instanceof Event ? path.currentTarget.href : path);
|
30
26
|
},
|
31
|
-
focusFilter() {
|
27
|
+
focusFilter($event) {
|
28
|
+
if ($event.target.tagName === "INPUT") {
|
29
|
+
return;
|
30
|
+
}
|
32
31
|
this.currentFocus = this.$refs.filter;
|
33
32
|
setTimeout(() => this.$refs.filter.focus(), 0);
|
34
33
|
},
|
@@ -27,7 +27,12 @@ export default function page() {
|
|
27
27
|
render() {
|
28
28
|
if (this.ready) {
|
29
29
|
morph(this.$el, store.doc.getElementById(this.$el.id));
|
30
|
+
this.$dispatch("document:patched");
|
30
31
|
}
|
31
32
|
},
|
33
|
+
navigateTo(path) {
|
34
|
+
history.pushState({}, null, path);
|
35
|
+
this.$dispatch("popstate");
|
36
|
+
},
|
32
37
|
};
|
33
38
|
}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
export default function param() {
|
2
|
+
return {
|
3
|
+
focused: false,
|
4
|
+
setFocus() {
|
5
|
+
if (this.focused && this.$el.focus) {
|
6
|
+
this.$el.focus();
|
7
|
+
}
|
8
|
+
},
|
9
|
+
update(name, value) {
|
10
|
+
const searchParams = new URLSearchParams(window.location.search);
|
11
|
+
searchParams.set(name, value);
|
12
|
+
const path = location.href.replace(location.search, "");
|
13
|
+
this.navigateTo(`${path}?${searchParams.toString()}`);
|
14
|
+
},
|
15
|
+
validate() {
|
16
|
+
return this.$el.reportValidity ? this.$el.reportValidity() : true;
|
17
|
+
},
|
18
|
+
};
|
19
|
+
}
|
@@ -8,7 +8,7 @@ module Lookbook
|
|
8
8
|
prepend_view_path File.expand_path("../../views/lookbook", __dir__)
|
9
9
|
|
10
10
|
layout "layouts/app"
|
11
|
-
helper Lookbook::
|
11
|
+
helper Lookbook::ApplicationHelper
|
12
12
|
|
13
13
|
before_action :find_preview, only: [:preview, :show]
|
14
14
|
before_action :find_example, only: [:preview, :show]
|
@@ -96,8 +96,7 @@ module Lookbook
|
|
96
96
|
}
|
97
97
|
end
|
98
98
|
set_params
|
99
|
-
|
100
|
-
preview_controller.render_in_layout_to_string("lookbook/preview/group", {examples: examples}, layout)
|
99
|
+
preview_controller.render_in_layout_to_string("lookbook/preview/group", {examples: examples}, @preview.lookbook_layout)
|
101
100
|
else
|
102
101
|
set_params(@example)
|
103
102
|
preview_controller.params[:path] = "#{@preview.preview_name}/#{@example.name}".chomp("/")
|
@@ -106,6 +105,15 @@ module Lookbook
|
|
106
105
|
end
|
107
106
|
|
108
107
|
def set_params(example = nil)
|
108
|
+
if example.present? && enabled?(:params)
|
109
|
+
# cast known params to type
|
110
|
+
example.params.each do |param|
|
111
|
+
if preview_controller.params.key?(param[:name])
|
112
|
+
preview_controller.params[param[:name]] = Lookbook::Params.cast(preview_controller.params[param[:name]], param[:type])
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
# set display params
|
109
117
|
example_params = example.nil? ? @preview.display_params : example.display_params
|
110
118
|
preview_controller.params.merge!({
|
111
119
|
lookbook: {
|
@@ -114,10 +122,6 @@ module Lookbook
|
|
114
122
|
})
|
115
123
|
end
|
116
124
|
|
117
|
-
def current_layout
|
118
|
-
preview_controller.send :_layout, preview_controller.lookup_context, [:html]
|
119
|
-
end
|
120
|
-
|
121
125
|
def assign_inspector
|
122
126
|
@inspector = {
|
123
127
|
panes: {
|
@@ -144,6 +148,15 @@ module Lookbook
|
|
144
148
|
}
|
145
149
|
}
|
146
150
|
}
|
151
|
+
if enabled?(:params)
|
152
|
+
@inspector[:panes][:params] = {
|
153
|
+
label: "Params",
|
154
|
+
template: "params",
|
155
|
+
hotkey: "p",
|
156
|
+
items: @source.many? ? [] : @example.params,
|
157
|
+
disabled: @source.many? || @example.params.none?
|
158
|
+
}
|
159
|
+
end
|
147
160
|
end
|
148
161
|
|
149
162
|
def assign_nav
|
@@ -179,5 +192,9 @@ module Lookbook
|
|
179
192
|
controller.response = response
|
180
193
|
@preview_controller ||= controller
|
181
194
|
end
|
195
|
+
|
196
|
+
def enabled?(feature)
|
197
|
+
Lookbook::Features.enabled?(feature)
|
198
|
+
end
|
182
199
|
end
|
183
200
|
end
|
@@ -8,7 +8,12 @@ module Lookbook
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def markdown(text)
|
11
|
-
Markdown.new(
|
11
|
+
markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML, {
|
12
|
+
tables: true,
|
13
|
+
fenced_code_blocks: true,
|
14
|
+
disable_indented_code_blocks: true
|
15
|
+
})
|
16
|
+
markdown.render(text).html_safe
|
12
17
|
end
|
13
18
|
|
14
19
|
def highlight(source, language)
|
@@ -20,7 +20,12 @@
|
|
20
20
|
</div>
|
21
21
|
<div class="flex-auto overflow-auto bg-gray-50">
|
22
22
|
<% panes.each do |key, props| %>
|
23
|
-
<div class="flex flex-col h-full relative" x-show="active('<%= key %>')" x-
|
23
|
+
<div class="flex flex-col h-full relative" x-show="active('<%= key %>')" x-effect="
|
24
|
+
if ($store.inspector.active === '<%= key %>') {
|
25
|
+
const input = $el.querySelector('[data-param-input]');
|
26
|
+
if (input) setTimeout(() => input.focus(), 0)
|
27
|
+
}
|
28
|
+
" x-cloak>
|
24
29
|
<% if props[:clipboard].present? %>
|
25
30
|
<%= render "shared/clipboard" do %><%= h props[:clipboard].strip %><% end %>
|
26
31
|
<% end %>
|
@@ -0,0 +1,28 @@
|
|
1
|
+
<% if @example.type == :group %>
|
2
|
+
<div class="p-4 prose prose-sm">
|
3
|
+
<em class='opacity-50'>Params are not supported for grouped previews.</em>
|
4
|
+
</div>
|
5
|
+
<% elsif items.none? %>
|
6
|
+
<div class="p-4 prose prose-sm">
|
7
|
+
<em class='opacity-50'>No params configured.</em>
|
8
|
+
</div>
|
9
|
+
<% else %>
|
10
|
+
<div class="py-3">
|
11
|
+
<% items.each do |param| %>
|
12
|
+
<div class="px-4 py-3" x-data="param" @document:patched="setFocus">
|
13
|
+
<div class="flex items-start max-w-[800px]">
|
14
|
+
<div class="w-[200px] flex-none py-2">
|
15
|
+
<label for="param-<%= param[:name] %>" class="font-bold"><%= param[:name].titleize %></label>
|
16
|
+
</div>
|
17
|
+
<div class="flex-grow" @focus="focussed = true" @blur="focussed = false">
|
18
|
+
<%= render "workbench/inspector/params/#{param[:input]}",
|
19
|
+
**param,
|
20
|
+
value: params.key?(param[:name]) ? params[param[:name]] : param[:default],
|
21
|
+
id: "#{@example.id}-param-#{param[:name]}"
|
22
|
+
%>
|
23
|
+
</div>
|
24
|
+
</div>
|
25
|
+
</div>
|
26
|
+
<% end %>
|
27
|
+
</div>
|
28
|
+
<% end %>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<div id="<%= id %>" x-init="checked = <%= value == "true" ? "true" : "false" %>" data-param-input>
|
2
|
+
<button type="button"
|
3
|
+
class="relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-400"
|
4
|
+
:class="{'bg-indigo-500': checked, 'bg-gray-300': !checked}"
|
5
|
+
role="switch"
|
6
|
+
@click.stop="checked = !checked; update('<%= name %>', checked)">
|
7
|
+
<span
|
8
|
+
aria-hidden="true"
|
9
|
+
class="pointer-events-none inline-block h-5 w-5 rounded-full bg-white shadow transform ring-0 transition ease-in-out duration-200"
|
10
|
+
:class="{'translate-x-5': checked, 'translate-x-0': !checked}"
|
11
|
+
></span>
|
12
|
+
</button>
|
13
|
+
</div>
|