lookbook 0.4.4 → 0.4.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +223 -54
- data/app/assets/lookbook/css/app.css +64 -8
- data/app/assets/lookbook/js/app.js +39 -53
- data/app/assets/lookbook/js/components/copy.js +16 -0
- data/app/assets/lookbook/js/components/filter.js +24 -0
- data/app/assets/lookbook/js/components/inspector.js +21 -0
- data/app/assets/lookbook/js/{nav/node.js → components/nav-group.js} +16 -15
- data/app/assets/lookbook/js/components/nav-item.js +26 -0
- data/app/assets/lookbook/js/components/nav.js +35 -0
- data/app/assets/lookbook/js/components/page.js +33 -0
- data/app/assets/lookbook/js/components/param.js +18 -0
- data/app/assets/lookbook/js/{workbench/preview.js → components/preview-window.js} +9 -10
- data/app/assets/lookbook/js/components/sidebar.js +3 -0
- data/app/assets/lookbook/js/components/sizes.js +16 -0
- data/app/assets/lookbook/js/components/splitter.js +25 -0
- data/app/assets/lookbook/js/config.js +14 -0
- data/app/assets/lookbook/js/{utils/reloader.js → lib/socket.js} +7 -12
- data/app/assets/lookbook/js/lib/split.js +21 -0
- data/app/assets/lookbook/js/lib/utils.js +3 -0
- data/app/assets/lookbook/js/stores/filter.js +11 -0
- data/app/assets/lookbook/js/stores/inspector.js +17 -0
- data/app/assets/lookbook/js/stores/layout.js +12 -0
- data/app/assets/lookbook/js/stores/nav.js +21 -0
- data/app/assets/lookbook/js/stores/sidebar.js +14 -0
- data/app/controllers/lookbook/app_controller.rb +82 -87
- data/app/helpers/lookbook/application_helper.rb +49 -5
- data/app/helpers/lookbook/preview_helper.rb +7 -0
- data/app/views/layouts/lookbook/app.html.erb +54 -0
- data/app/views/layouts/lookbook/preview.html.erb +12 -0
- data/app/views/lookbook/components/_code.html.erb +8 -0
- data/app/views/lookbook/{shared/_clipboard.html.erb → components/_copy.html.erb} +4 -5
- data/app/views/lookbook/components/_filter.html.erb +15 -0
- data/app/views/lookbook/{shared → components}/_header.html.erb +3 -3
- data/app/views/lookbook/components/_icon.html.erb +5 -0
- data/app/views/lookbook/components/_nav.html.erb +17 -0
- data/app/views/lookbook/components/_nav_collection.html.erb +5 -0
- data/app/views/lookbook/components/_nav_group.html.erb +17 -0
- data/app/views/lookbook/components/_nav_item.html.erb +21 -0
- data/app/views/lookbook/components/_nav_preview.html.erb +11 -0
- data/app/views/lookbook/components/_param.html.erb +20 -0
- data/app/views/lookbook/{workbench → components}/_preview.html.erb +8 -8
- data/app/views/lookbook/{app/error.html.erb → error.html.erb} +0 -0
- data/app/views/lookbook/index.html.erb +9 -0
- data/app/views/lookbook/inputs/_select.html.erb +8 -0
- data/app/views/lookbook/inputs/_text.html.erb +8 -0
- data/app/views/lookbook/inputs/_textarea.html.erb +8 -0
- data/app/views/lookbook/inputs/_toggle.html.erb +13 -0
- data/app/views/lookbook/{app/not_found.html.erb → not_found.html.erb} +2 -4
- data/app/views/lookbook/panels/_notes.html.erb +25 -0
- data/app/views/lookbook/panels/_output.html.erb +18 -0
- data/app/views/lookbook/panels/_params.html.erb +17 -0
- data/app/views/lookbook/panels/_source.html.erb +20 -0
- data/app/views/lookbook/show.html.erb +90 -0
- data/lib/lookbook/code_formatter.rb +20 -0
- data/lib/lookbook/engine.rb +14 -1
- data/lib/lookbook/features.rb +24 -0
- data/lib/lookbook/lang.rb +10 -5
- data/lib/lookbook/params.rb +110 -0
- data/lib/lookbook/preview.rb +1 -1
- data/lib/lookbook/preview_controller.rb +1 -1
- data/lib/lookbook/preview_example.rb +13 -1
- data/lib/lookbook/preview_group.rb +9 -1
- data/lib/lookbook/taggable.rb +2 -2
- data/lib/lookbook/version.rb +1 -1
- data/lib/lookbook.rb +4 -0
- data/public/lookbook-assets/css/app.css +2 -0
- data/public/lookbook-assets/css/app.css.map +1 -0
- data/public/lookbook-assets/js/app.js +2 -0
- data/public/lookbook-assets/js/app.js.map +1 -0
- metadata +58 -38
- data/app/assets/lookbook/js/nav/leaf.js +0 -20
- data/app/assets/lookbook/js/nav.js +0 -39
- data/app/assets/lookbook/js/page.js +0 -33
- data/app/assets/lookbook/js/utils/clipboard.js +0 -13
- data/app/assets/lookbook/js/utils/morph.js +0 -16
- data/app/assets/lookbook/js/utils/screen.js +0 -44
- data/app/assets/lookbook/js/utils/size_observer.js +0 -16
- data/app/assets/lookbook/js/utils/split.js +0 -26
- data/app/assets/lookbook/js/workbench/inspector.js +0 -11
- data/app/assets/lookbook/js/workbench.js +0 -14
- data/app/views/lookbook/app/index.html.erb +0 -11
- data/app/views/lookbook/app/show.html.erb +0 -1
- data/app/views/lookbook/layouts/app.html.erb +0 -41
- data/app/views/lookbook/nav/_collection.html.erb +0 -5
- data/app/views/lookbook/nav/_leaf.html.erb +0 -22
- data/app/views/lookbook/nav/_node.html.erb +0 -19
- data/app/views/lookbook/nav/_preview.html.erb +0 -11
- data/app/views/lookbook/preview/group.html.erb +0 -8
- data/app/views/lookbook/shared/_sidebar.html.erb +0 -45
- data/app/views/lookbook/shared/_workbench.html.erb +0 -12
- data/app/views/lookbook/workbench/_header.html.erb +0 -39
- data/app/views/lookbook/workbench/_inspector.html.erb +0 -33
- data/app/views/lookbook/workbench/inspector/_code.html.erb +0 -3
- data/app/views/lookbook/workbench/inspector/_notes.html.erb +0 -24
- data/app/views/lookbook/workbench/inspector/_plain.html.erb +0 -3
- data/public/lookbook-assets/app.css +0 -2504
- data/public/lookbook-assets/app.js +0 -8680
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7a4c7c01727ccbd4cc232198f9bcc33236f0fa90618d10944b78b1858d750fe2
|
4
|
+
data.tar.gz: a7615d2ca70fad9bb2b05670f0bc120245b14137b18e9673b5d5fb73bd6c9bce
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 89ae1a5899bfd6bd848ea8bebc895d85b0d88a9b4d66914f52ddf04de24a7d566b0deeb0239e51d857afac2f4e1d2706aab77098191419d2b6e0c52df946b4b1
|
7
|
+
data.tar.gz: 48729571a609a5505095f11d69b4ddb53735eeb4a6f26b83ec326a8f86ad346b17c7b66087efbd87a0002737ec000efbeefbba1acf56560d87be1a667b3d24d3
|
data/README.md
CHANGED
@@ -28,12 +28,15 @@ 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
|
|
34
35
|
If you want to have a quick play with Lookbook, the easiest way is to [give the demo app](https://github.com/allmarkedup/lookbook-demo) a spin. It's a basic Rails/ViewComponent app with a few test components included to tinker with.
|
35
36
|
|
36
|
-
|
37
|
+
**Online demo: https://lookbook-demo-app.herokuapp.com/lookbook**
|
38
|
+
|
39
|
+
If you'd rather dig in a bit more and run the demo app locally, the [demo repo](https://github.com/allmarkedup/lookbook-demo) contains instructions on how to get it up and running.
|
37
40
|
|
38
41
|
## Installing
|
39
42
|
|
@@ -76,7 +79,7 @@ Lookbook parses [Yard-style comment tags](https://rubydoc.info/gems/yard/file/do
|
|
76
79
|
|
77
80
|
```ruby
|
78
81
|
# @label Basic Button
|
79
|
-
# @display bg_color
|
82
|
+
# @display bg_color #fff
|
80
83
|
class ButtonComponentPreview < ViewComponent::Preview
|
81
84
|
|
82
85
|
# Primary button
|
@@ -90,11 +93,24 @@ class ButtonComponentPreview < ViewComponent::Preview
|
|
90
93
|
end
|
91
94
|
end
|
92
95
|
|
96
|
+
# Button with icon
|
97
|
+
# ----------------
|
98
|
+
# This example uses dynamic preview parameters
|
99
|
+
# which can be edited live in the Lookbook UI
|
100
|
+
#
|
101
|
+
# @param text
|
102
|
+
# @param icon select [heart, cog, alert]
|
103
|
+
def icon(text: "Spread the love", icon: "heart")
|
104
|
+
render ButtonComponent.new(icon: icon) do
|
105
|
+
text
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
93
109
|
# Inverted button
|
94
110
|
# ---------------
|
95
111
|
# For light-on-dark screens
|
96
112
|
#
|
97
|
-
# @display bg_color
|
113
|
+
# @display bg_color #000
|
98
114
|
def secondary
|
99
115
|
render ButtonComponent.new(style: :inverted) do
|
100
116
|
"Click me"
|
@@ -141,54 +157,41 @@ end
|
|
141
157
|
|
142
158
|
The following Lookbook-specific tags are available for use:
|
143
159
|
|
144
|
-
* `@label
|
145
|
-
* `@
|
146
|
-
*
|
147
|
-
*
|
160
|
+
* [`@label`](#label-tag)
|
161
|
+
* [`@display`](#display-tag)
|
162
|
+
* [`@!group ... @!endgroup`](#group-tag)
|
163
|
+
* [`@hidden`](#hidden-tag)
|
164
|
+
* [`@param`](#param-tag) [⚠️ **experimental!** - requires [feature opt-in](#experimental-features) ⚠️]
|
148
165
|
|
149
|
-
|
166
|
+
<h3 id="label-tag">🏷 @label</h3>
|
150
167
|
|
151
168
|
Used to replace the auto-generated navigation label for the item with `<text>`.
|
152
169
|
|
153
|
-
> Available for preview classes & example methods.
|
154
|
-
|
155
170
|
```ruby
|
156
|
-
|
157
|
-
class FooComponentPreview < ViewComponent::Preview
|
158
|
-
|
159
|
-
# @label Example Label
|
160
|
-
def default
|
161
|
-
end
|
162
|
-
end
|
171
|
+
@label <text>
|
163
172
|
```
|
164
173
|
|
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.
|
174
|
+
> Available for preview classes & example methods.
|
172
175
|
|
173
176
|
```ruby
|
174
|
-
# @
|
177
|
+
# @label Preview Label
|
175
178
|
class FooComponentPreview < ViewComponent::Preview
|
176
179
|
|
177
|
-
# @
|
180
|
+
# @label Example Label
|
178
181
|
def default
|
179
182
|
end
|
180
183
|
end
|
181
184
|
```
|
182
185
|
|
183
|
-
|
186
|
+
<h3 id="display-tag">🏷 @display</h3>
|
184
187
|
|
185
188
|
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
189
|
|
187
190
|
```ruby
|
188
|
-
# @display bg_color
|
191
|
+
# @display bg_color #eee
|
189
192
|
class FooComponentPreview < ViewComponent::Preview
|
190
193
|
|
191
|
-
# @display max_width
|
194
|
+
# @display max_width 500px
|
192
195
|
# @display wrapper true
|
193
196
|
def default
|
194
197
|
end
|
@@ -198,13 +201,11 @@ end
|
|
198
201
|
The `@display` tag can be applied at the preview (class) or at the example (method) level, and takes the following format:
|
199
202
|
|
200
203
|
```ruby
|
201
|
-
|
204
|
+
@display <key> <value>
|
202
205
|
```
|
203
206
|
|
204
207
|
- `<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.
|
208
|
+
- `<value>` will be parsed using the [Ruby YAML parser](https://yaml.org/YAML_for_ruby.html) to resolve the value
|
208
209
|
|
209
210
|
These display parameters can then be accessed via the `params` hash in your preview layout using `params[:lookbook][:display][<key>]`:
|
210
211
|
|
@@ -244,27 +245,7 @@ config.lookbook.preview_display_params = {
|
|
244
245
|
|
245
246
|
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
247
|
|
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`
|
248
|
+
<h3 id="group-tag">🔖 `@!group ... @!endgroup`</h3>
|
268
249
|
|
269
250
|
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
251
|
|
@@ -310,6 +291,167 @@ The example above would display the `Sizes` examples grouped together on a singl
|
|
310
291
|
|
311
292
|
You can have as many groups as you like within a single preview class, but each example can only belong to one group.
|
312
293
|
|
294
|
+
<h3 id="hidden-tag">🏷 `@hidden`</h3>
|
295
|
+
|
296
|
+
Used to temporarily exclude an item from the Lookbook navigation. The item will still be accessible via it's URL.
|
297
|
+
|
298
|
+
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.
|
299
|
+
|
300
|
+
> Available for both preview classes & example methods.
|
301
|
+
|
302
|
+
```ruby
|
303
|
+
# @hidden
|
304
|
+
class FooComponentPreview < ViewComponent::Preview
|
305
|
+
|
306
|
+
# @hidden
|
307
|
+
def default
|
308
|
+
end
|
309
|
+
end
|
310
|
+
```
|
311
|
+
|
312
|
+
<h3 id="param-tag"> 🚧 @param (experimental)</h3>
|
313
|
+
|
314
|
+
> ⚠️ 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.
|
315
|
+
|
316
|
+
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.
|
317
|
+
|
318
|
+
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.
|
319
|
+
|
320
|
+
The `@param` tag takes the following format:
|
321
|
+
|
322
|
+
```ruby
|
323
|
+
@param <name> <input_type> <opts?>
|
324
|
+
```
|
325
|
+
|
326
|
+
- `<name>` - name of the dynamic preview param
|
327
|
+
- `<input_type>` - input field type to generate in the UI
|
328
|
+
- `<opts?>` - YAML-encoded field options, used for some field types
|
329
|
+
|
330
|
+
#### Input types
|
331
|
+
|
332
|
+
The following **input field types** are available for use:
|
333
|
+
|
334
|
+
📝 **Text-style inputs** - Single line fields, useful for short strings of text or numbers.
|
335
|
+
|
336
|
+
```ruby
|
337
|
+
@param <name> text
|
338
|
+
@param <name> email
|
339
|
+
@param <name> number
|
340
|
+
@param <name> url
|
341
|
+
@param <name> tel
|
342
|
+
```
|
343
|
+
|
344
|
+
> The above types only differ in the validation constraints they impose on the input field.
|
345
|
+
|
346
|
+
📝 **Textarea** - Multi-line textarea field for longer-form content.
|
347
|
+
|
348
|
+
```ruby
|
349
|
+
@param <name> textarea
|
350
|
+
```
|
351
|
+
|
352
|
+
📝 **Select box** - Dropdown select field for selecting from a list of known options.
|
353
|
+
|
354
|
+
```ruby
|
355
|
+
@param <name> select <options>
|
356
|
+
```
|
357
|
+
|
358
|
+
`<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:
|
359
|
+
|
360
|
+
```ruby
|
361
|
+
# Basic options:
|
362
|
+
# @param theme select [primary, secondary, danger]
|
363
|
+
|
364
|
+
# With custom labels (each item itself an array of [label, value]):
|
365
|
+
# @param theme select [[Primary theme, primary], [Secondary theme, secondary], [Danger theme, danger]]
|
366
|
+
|
367
|
+
# With empty option (`~` in YAML)
|
368
|
+
# @param theme select [~, primary, secondary, danger]
|
369
|
+
```
|
370
|
+
|
371
|
+
> **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.
|
372
|
+
|
373
|
+
📝 **Toggle** - On/off switch for toggling boolean values.
|
374
|
+
|
375
|
+
```ruby
|
376
|
+
@param <name> toggle
|
377
|
+
```
|
378
|
+
|
379
|
+
#### Default values
|
380
|
+
|
381
|
+
Default values are specified as part of the preview example method parameters in the usual Ruby way:
|
382
|
+
|
383
|
+
```ruby
|
384
|
+
def button(content: "Click me", theme: "primary", arrow: false)
|
385
|
+
# ...
|
386
|
+
end
|
387
|
+
```
|
388
|
+
|
389
|
+
These will be used as the default values for the param fields.
|
390
|
+
|
391
|
+
> 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.
|
392
|
+
|
393
|
+
#### Type casting values
|
394
|
+
|
395
|
+
Most dynamic param values are passed to the example method as strings, with the following exceptions:
|
396
|
+
|
397
|
+
- `toggle` input - values are cast to booleans
|
398
|
+
- `number` input - values are cast to integers
|
399
|
+
|
400
|
+
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.
|
401
|
+
|
402
|
+
To help with this, a `type` option can be specified in the `@param` definition to automatically cast the dynamic value to a different type:
|
403
|
+
|
404
|
+
```ruby
|
405
|
+
# @param <name> [<type>] <input_type> <opts?>
|
406
|
+
```
|
407
|
+
|
408
|
+
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.
|
409
|
+
|
410
|
+
```ruby
|
411
|
+
# @param theme [Symbol] select [primary, secondary, danger]
|
412
|
+
def default(theme: :primary)
|
413
|
+
render Elements::ButtonComponent.new(theme: theme) do
|
414
|
+
"Click me"
|
415
|
+
end
|
416
|
+
end
|
417
|
+
```
|
418
|
+
|
419
|
+
The supported types to cast to are:
|
420
|
+
|
421
|
+
- `String` - *default for all except `toggle` inputs*
|
422
|
+
- `Boolean` - *default for `toggle` inputs*
|
423
|
+
- `Symbol`
|
424
|
+
- `Date`
|
425
|
+
- `DateTime`
|
426
|
+
- `Integer`
|
427
|
+
- `Float`
|
428
|
+
|
429
|
+
The following structured types are also available but should be considered **experimental** - you may run into bugs!
|
430
|
+
|
431
|
+
- `Hash` - *value string converted to Hash using the Ruby YAML parser*
|
432
|
+
- `Array` - *value string converted to Array using the Ruby YAML parser*
|
433
|
+
|
434
|
+
#### Full example:
|
435
|
+
|
436
|
+
```ruby
|
437
|
+
class ButtonComponentPreview < ViewComponent::Preview
|
438
|
+
|
439
|
+
# The params defined below will be editable in the UI:
|
440
|
+
#
|
441
|
+
# @param content text
|
442
|
+
# @param theme select [primary, secondary, danger]
|
443
|
+
# @param arrow toggle
|
444
|
+
def default(content: "Click me", theme: "primary", arrow: true)
|
445
|
+
render Elements::ButtonComponent.new(theme: theme, arrow: arrow) do
|
446
|
+
content
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
450
|
+
end
|
451
|
+
```
|
452
|
+
|
453
|
+
<img src=".github/assets/dynamic_params.png">
|
454
|
+
|
313
455
|
### Adding notes
|
314
456
|
|
315
457
|
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 +494,33 @@ If you wish to add additional paths to listen for changes in, you can use the `l
|
|
352
494
|
config.lookbook.listen_paths << Rails.root.join('app/other/directory')
|
353
495
|
```
|
354
496
|
|
497
|
+
<h3 id="experimental-features">Experimental features opt-in</h3>
|
498
|
+
|
499
|
+
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.
|
500
|
+
|
501
|
+
> ⚠️ **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'. ⚠️
|
502
|
+
|
503
|
+
#### Opting into specific features (recommended)
|
504
|
+
|
505
|
+
To opt into individual experimental features, include the name of the feature in the `experimental_features` config option:
|
506
|
+
|
507
|
+
```ruby
|
508
|
+
config.lookbook.experimental_features = ["feature_name"]
|
509
|
+
```
|
510
|
+
|
511
|
+
The current experimental features that can be opted into are:
|
512
|
+
|
513
|
+
- `params`: Live-editable, dynamic preview parameters ([read more](#param-tag)). Include `"params"` in the `experimental_features` config option to opt in.
|
514
|
+
|
515
|
+
#### Opting into all experimental features (not recommended!)
|
516
|
+
|
517
|
+
If you want to live life on the bleeding-edge you can opt-in to all current **and future** experimental features (usual caveats apply):
|
518
|
+
|
519
|
+
```ruby
|
520
|
+
config.lookbook.experimental_features = true
|
521
|
+
```
|
522
|
+
|
523
|
+
|
355
524
|
## Keyboard shortcuts
|
356
525
|
|
357
526
|
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,67 @@
|
|
63
55
|
@apply bg-gray-400;
|
64
56
|
}
|
65
57
|
}
|
58
|
+
|
59
|
+
@layer components {
|
60
|
+
#nav > ul > li {
|
61
|
+
@apply py-1;
|
62
|
+
}
|
63
|
+
|
64
|
+
.nav-toggle {
|
65
|
+
@apply flex items-center cursor-pointer pr-3 hover:bg-gray-200 hover:bg-opacity-50;
|
66
|
+
}
|
67
|
+
|
68
|
+
.nav-label {
|
69
|
+
@apply truncate w-full whitespace-nowrap text-left select-none;
|
70
|
+
}
|
71
|
+
|
72
|
+
.code {
|
73
|
+
@apply font-mono;
|
74
|
+
}
|
75
|
+
|
76
|
+
.code pre {
|
77
|
+
@apply block;
|
78
|
+
}
|
79
|
+
|
80
|
+
.code .line {
|
81
|
+
@apply flex items-center leading-relaxed;
|
82
|
+
}
|
83
|
+
|
84
|
+
.code.numbered {
|
85
|
+
@apply relative pt-3;
|
86
|
+
}
|
87
|
+
|
88
|
+
.code.numbered:before {
|
89
|
+
content: "";
|
90
|
+
left: calc(2.7em + 8px);
|
91
|
+
@apply absolute top-0 bottom-0 border-r border-gray-200;
|
92
|
+
}
|
93
|
+
|
94
|
+
.code .line-number {
|
95
|
+
width: calc(2.7em + 8px);
|
96
|
+
padding-top: 3px;
|
97
|
+
padding-bottom: 3px;
|
98
|
+
padding-right: 8px;
|
99
|
+
margin-right: 16px;
|
100
|
+
@apply font-mono text-right text-gray-400 flex-none text-xs;
|
101
|
+
}
|
102
|
+
|
103
|
+
.code .line-content {
|
104
|
+
@apply flex-none pr-4;
|
105
|
+
}
|
106
|
+
|
107
|
+
/* .code .line:before {
|
108
|
+
content: counter(line);
|
109
|
+
width: calc(3em + 8px);
|
110
|
+
padding-top: 2px;
|
111
|
+
padding-bottom: 2px;
|
112
|
+
padding-right: 8px;
|
113
|
+
@apply font-mono inline-block text-right mr-4 text-gray-400 border-r border-gray-200;
|
114
|
+
} */
|
115
|
+
}
|
116
|
+
|
117
|
+
@layer utilities {
|
118
|
+
.form-input {
|
119
|
+
@apply border-gray-300 text-gray-700 focus:ring-indigo-300 focus:border-indigo-300 rounded-sm text-sm w-full;
|
120
|
+
}
|
121
|
+
}
|
@@ -1,64 +1,54 @@
|
|
1
1
|
import { install } from "@github/hotkey";
|
2
2
|
import Alpine from "alpinejs";
|
3
|
-
import
|
4
|
-
import
|
5
|
-
import
|
6
|
-
|
7
|
-
import
|
8
|
-
import
|
9
|
-
import
|
10
|
-
import
|
11
|
-
import
|
12
|
-
import nav from "./nav";
|
13
|
-
import
|
14
|
-
import
|
15
|
-
import
|
16
|
-
import
|
17
|
-
import
|
18
|
-
|
19
|
-
|
3
|
+
import Persist from "@alpinejs/persist";
|
4
|
+
import Morph from "@alpinejs/morph";
|
5
|
+
import Tooltip from "@ryangjchandler/alpine-tooltip";
|
6
|
+
|
7
|
+
import page from "./components/page";
|
8
|
+
import inspector from "./components/inspector";
|
9
|
+
import previewWindow from "./components/preview-window";
|
10
|
+
import filter from "./components/filter";
|
11
|
+
import param from "./components/param";
|
12
|
+
import nav from "./components/nav";
|
13
|
+
import navItem from "./components/nav-item";
|
14
|
+
import navGroup from "./components/nav-group";
|
15
|
+
import splitter from "./components/splitter";
|
16
|
+
import copy from "./components/copy";
|
17
|
+
import sizes from "./components/sizes";
|
18
|
+
|
19
|
+
import initFilterStore from "./stores/filter";
|
20
|
+
import initLayoutStore from "./stores/layout";
|
21
|
+
import initNavStore from "./stores/nav";
|
22
|
+
import initSidebarStore from "./stores/sidebar";
|
23
|
+
import initInspectorStore from "./stores/inspector";
|
20
24
|
|
21
25
|
// Plugins
|
22
26
|
|
23
|
-
Alpine.plugin(
|
24
|
-
Alpine.plugin(
|
25
|
-
Alpine.plugin(
|
26
|
-
Alpine.plugin(Screen);
|
27
|
+
Alpine.plugin(Persist);
|
28
|
+
Alpine.plugin(Morph);
|
29
|
+
Alpine.plugin(Tooltip);
|
27
30
|
|
28
31
|
// Stores
|
29
32
|
|
30
|
-
Alpine.store("
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
Alpine.persistedStore("nav", {
|
36
|
-
width: 280,
|
37
|
-
filter: "",
|
38
|
-
open: {},
|
39
|
-
});
|
40
|
-
|
41
|
-
Alpine.persistedStore("inspector", {
|
42
|
-
height: 200,
|
43
|
-
active: "source",
|
44
|
-
});
|
45
|
-
|
46
|
-
Alpine.persistedStore("preview", {
|
47
|
-
width: "100%",
|
48
|
-
});
|
33
|
+
Alpine.store("filter", initFilterStore(Alpine));
|
34
|
+
Alpine.store("layout", initLayoutStore(Alpine));
|
35
|
+
Alpine.store("nav", initNavStore(Alpine));
|
36
|
+
Alpine.store("sidebar", initSidebarStore(Alpine));
|
37
|
+
Alpine.store("inspector", initInspectorStore(Alpine));
|
49
38
|
|
50
|
-
// Components
|
39
|
+
// Components
|
51
40
|
|
52
41
|
Alpine.data("page", page);
|
53
|
-
Alpine.data("
|
54
|
-
Alpine.data("
|
55
|
-
Alpine.data("
|
56
|
-
Alpine.data("workbench", workbench);
|
57
|
-
Alpine.data("preview", preview);
|
42
|
+
Alpine.data("splitter", splitter);
|
43
|
+
Alpine.data("previewWindow", previewWindow);
|
44
|
+
Alpine.data("copy", copy);
|
58
45
|
Alpine.data("inspector", inspector);
|
59
|
-
Alpine.data("
|
60
|
-
Alpine.data("
|
61
|
-
Alpine.data("
|
46
|
+
Alpine.data("filter", filter);
|
47
|
+
Alpine.data("param", param);
|
48
|
+
Alpine.data("sizes", sizes);
|
49
|
+
Alpine.data("nav", nav);
|
50
|
+
Alpine.data("navItem", navItem);
|
51
|
+
Alpine.data("navGroup", navGroup);
|
62
52
|
|
63
53
|
// Init
|
64
54
|
|
@@ -66,9 +56,5 @@ for (const el of document.querySelectorAll("[data-hotkey]")) {
|
|
66
56
|
install(el);
|
67
57
|
}
|
68
58
|
|
69
|
-
if (window.SOCKET_PATH) {
|
70
|
-
reloader(window.SOCKET_PATH).start();
|
71
|
-
}
|
72
|
-
|
73
59
|
window.Alpine = Alpine;
|
74
60
|
Alpine.start();
|
@@ -0,0 +1,16 @@
|
|
1
|
+
export default function copy(id) {
|
2
|
+
return {
|
3
|
+
get content() {
|
4
|
+
const target = document.getElementById(id);
|
5
|
+
return (target ? target.innerHTML : "").trim();
|
6
|
+
},
|
7
|
+
done: false,
|
8
|
+
async save() {
|
9
|
+
await window.navigator.clipboard.writeText(this.content);
|
10
|
+
this.done = true;
|
11
|
+
setTimeout(() => {
|
12
|
+
this.done = false;
|
13
|
+
}, 1000);
|
14
|
+
},
|
15
|
+
};
|
16
|
+
}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
export default function filter() {
|
2
|
+
return {
|
3
|
+
get active() {
|
4
|
+
return this.$store.filter.active;
|
5
|
+
},
|
6
|
+
checkEsc($event) {
|
7
|
+
if ($event.key === "Escape") {
|
8
|
+
this.active ? this.clear() : this.blur();
|
9
|
+
}
|
10
|
+
},
|
11
|
+
clear() {
|
12
|
+
this.$store.filter.raw = "";
|
13
|
+
},
|
14
|
+
focus($event) {
|
15
|
+
if ($event.target.tagName === "INPUT") {
|
16
|
+
return;
|
17
|
+
}
|
18
|
+
setTimeout(() => this.$refs.input.focus(), 0);
|
19
|
+
},
|
20
|
+
blur() {
|
21
|
+
setTimeout(() => this.$refs.input.blur(), 0);
|
22
|
+
},
|
23
|
+
};
|
24
|
+
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
export default function inspector() {
|
2
|
+
return {
|
3
|
+
isActivePanel(panel) {
|
4
|
+
return this.$store.inspector.panels.active == panel;
|
5
|
+
},
|
6
|
+
switchPanel(panel) {
|
7
|
+
this.$store.inspector.panels.active = panel;
|
8
|
+
},
|
9
|
+
get showSource() {
|
10
|
+
return this.$store.inspector.preview.source;
|
11
|
+
},
|
12
|
+
toggleSource() {
|
13
|
+
this.$store.inspector.preview.source =
|
14
|
+
!this.$store.inspector.preview.source;
|
15
|
+
},
|
16
|
+
preview: {
|
17
|
+
width: null,
|
18
|
+
height: null,
|
19
|
+
},
|
20
|
+
};
|
21
|
+
}
|