lookbook 0.4.7 → 0.5.0.beta.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +5 -3
- data/app/assets/lookbook/css/app.css +24 -13
- data/app/assets/lookbook/css/tooltip_theme.css +28 -0
- data/app/assets/lookbook/js/app.js +4 -0
- data/app/assets/lookbook/js/components/code.js +5 -0
- data/app/assets/lookbook/js/components/filter.js +1 -1
- data/app/assets/lookbook/js/components/inspector.js +44 -7
- data/app/assets/lookbook/js/components/nav-group.js +1 -1
- data/app/assets/lookbook/js/components/nav-item.js +1 -0
- data/app/assets/lookbook/js/components/nav.js +1 -1
- data/app/assets/lookbook/js/components/page.js +17 -5
- data/app/assets/lookbook/js/components/param.js +23 -7
- data/app/assets/lookbook/js/components/preview-window.js +95 -26
- data/app/assets/lookbook/js/components/tabs.js +50 -0
- data/app/assets/lookbook/js/config.js +9 -3
- data/app/assets/lookbook/js/lib/socket.js +1 -1
- data/app/assets/lookbook/js/stores/inspector.js +12 -5
- data/app/controllers/lookbook/app_controller.rb +3 -1
- data/app/views/layouts/lookbook/app.html.erb +7 -3
- data/app/views/lookbook/components/_code.html.erb +6 -1
- data/app/views/lookbook/components/_copy.html.erb +7 -3
- data/app/views/lookbook/components/_drawer.html.erb +121 -0
- data/app/views/lookbook/components/_filter.html.erb +1 -1
- data/app/views/lookbook/components/_header.html.erb +1 -1
- data/app/views/lookbook/components/_nav.html.erb +1 -1
- data/app/views/lookbook/components/_nav_group.html.erb +11 -14
- data/app/views/lookbook/components/_nav_item.html.erb +17 -15
- data/app/views/lookbook/components/_param.html.erb +6 -5
- data/app/views/lookbook/components/_preview.html.erb +49 -21
- data/app/views/lookbook/inputs/_select.html.erb +2 -3
- data/app/views/lookbook/inputs/_text.html.erb +3 -3
- data/app/views/lookbook/inputs/_textarea.html.erb +3 -3
- data/app/views/lookbook/inputs/_toggle.html.erb +5 -5
- data/app/views/lookbook/panels/_notes.html.erb +1 -1
- data/app/views/lookbook/panels/_output.html.erb +2 -2
- data/app/views/lookbook/panels/_params.html.erb +1 -1
- data/app/views/lookbook/panels/_source.html.erb +2 -2
- data/app/views/lookbook/show.html.erb +64 -81
- data/lib/lookbook/code_formatter.rb +3 -3
- data/lib/lookbook/engine.rb +4 -0
- data/lib/lookbook/preview.rb +1 -1
- data/lib/lookbook/version.rb +1 -1
- data/lib/lookbook.rb +1 -0
- data/public/lookbook-assets/css/app.css +3 -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 +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7838a877b435b1952e1eed9163cad4f21fa44b2578d9114430bfc1d262b15c23
|
4
|
+
data.tar.gz: 4f8512d21d07f2b93164706569f0a28483f6b43e60446f19857411b4e66ac6ee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bf6f6045ce9ea8d5bca9932bfb3538e0e5c307b856cdbc0a209520be5112bed281f623cc879af59e51216f1d284aa2de08ed6ef1b483f794ea74c434a150bb13
|
7
|
+
data.tar.gz: 4b2d545082ea784bc1122a51c947b0d5391cc829e895adfe224107591acdb68fabb23e8d21fe8be1f1d6acf405e774130dad1e1ba9676470a5bea9240f82cd34
|
data/README.md
CHANGED
@@ -79,7 +79,7 @@ Lookbook parses [Yard-style comment tags](https://rubydoc.info/gems/yard/file/do
|
|
79
79
|
|
80
80
|
```ruby
|
81
81
|
# @label Basic Button
|
82
|
-
# @display bg_color #fff
|
82
|
+
# @display bg_color "#fff"
|
83
83
|
class ButtonComponentPreview < ViewComponent::Preview
|
84
84
|
|
85
85
|
# Primary button
|
@@ -110,7 +110,7 @@ class ButtonComponentPreview < ViewComponent::Preview
|
|
110
110
|
# ---------------
|
111
111
|
# For light-on-dark screens
|
112
112
|
#
|
113
|
-
# @display bg_color #000
|
113
|
+
# @display bg_color "#000"
|
114
114
|
def secondary
|
115
115
|
render ButtonComponent.new(style: :inverted) do
|
116
116
|
"Click me"
|
@@ -188,7 +188,7 @@ end
|
|
188
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.
|
189
189
|
|
190
190
|
```ruby
|
191
|
-
# @display bg_color #eee
|
191
|
+
# @display bg_color "#eee"
|
192
192
|
class FooComponentPreview < ViewComponent::Preview
|
193
193
|
|
194
194
|
# @display max_width 500px
|
@@ -207,6 +207,8 @@ The `@display` tag can be applied at the preview (class) or at the example (meth
|
|
207
207
|
- `<key>` must be a valid Ruby hash key name, without quotes or spaces
|
208
208
|
- `<value>` will be parsed using the [Ruby YAML parser](https://yaml.org/YAML_for_ruby.html) to resolve the value
|
209
209
|
|
210
|
+
> Note: Ruby YAML does not (generally) require quoting of string values. However in some cases it _is_ required due to the presence of [indicator characters](https://yaml.org/YAML_for_ruby.html#indicators_in_strings) (such as `#`, `:` etc) - hence why the hex color code in the example above is surrounded by quotes. It's perfectly ok to quote all string values if you prefer.
|
211
|
+
|
210
212
|
These display parameters can then be accessed via the `params` hash in your preview layout using `params[:lookbook][:display][<key>]`:
|
211
213
|
|
212
214
|
```html
|
@@ -2,6 +2,7 @@
|
|
2
2
|
@import "tailwindcss/components";
|
3
3
|
@import "tailwindcss/utilities";
|
4
4
|
@import "tippy.js/dist/tippy";
|
5
|
+
@import "tippy.js/dist/border";
|
5
6
|
@import "code_theme";
|
6
7
|
@import "tooltip_theme";
|
7
8
|
|
@@ -57,8 +58,8 @@
|
|
57
58
|
}
|
58
59
|
|
59
60
|
@layer components {
|
60
|
-
#nav > ul > li {
|
61
|
-
@apply py-1;
|
61
|
+
#nav > ul > li > div {
|
62
|
+
@apply py-1 border-b border-gray-300;
|
62
63
|
}
|
63
64
|
|
64
65
|
.nav-toggle {
|
@@ -77,8 +78,12 @@
|
|
77
78
|
@apply block;
|
78
79
|
}
|
79
80
|
|
81
|
+
.code.wrapped pre {
|
82
|
+
@apply whitespace-pre-wrap;
|
83
|
+
}
|
84
|
+
|
80
85
|
.code .line {
|
81
|
-
@apply
|
86
|
+
@apply leading-relaxed;
|
82
87
|
}
|
83
88
|
|
84
89
|
.code.numbered {
|
@@ -87,35 +92,41 @@
|
|
87
92
|
|
88
93
|
.code.numbered:before {
|
89
94
|
content: "";
|
90
|
-
left:
|
95
|
+
left: 2.7em;
|
91
96
|
@apply absolute top-0 bottom-0 border-r border-gray-200;
|
92
97
|
}
|
93
98
|
|
99
|
+
.code.numbered .line {
|
100
|
+
padding-left: calc(2.7em + 8px);
|
101
|
+
@apply relative;
|
102
|
+
}
|
103
|
+
|
94
104
|
.code .line-number {
|
105
|
+
display: inline-block;
|
95
106
|
width: calc(2.7em + 8px);
|
96
107
|
padding-top: 3px;
|
97
108
|
padding-bottom: 3px;
|
98
109
|
padding-right: 8px;
|
99
110
|
margin-right: 16px;
|
100
|
-
@apply font-mono text-right text-gray-400 flex-none text-xs;
|
111
|
+
@apply font-mono text-right text-gray-400 flex-none text-xs absolute left-0;
|
101
112
|
}
|
102
113
|
|
103
114
|
.code .line-content {
|
104
115
|
@apply flex-none pr-4;
|
105
116
|
}
|
106
117
|
|
107
|
-
|
108
|
-
|
109
|
-
|
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
|
-
} */
|
118
|
+
.resize-handle {
|
119
|
+
@apply flex items-center justify-center h-full w-full border-gray-300 bg-white hover:bg-indigo-100 hover:bg-opacity-20 text-gray-400 hover:text-gray-700 transition select-none touch-none;
|
120
|
+
}
|
115
121
|
}
|
116
122
|
|
117
123
|
@layer utilities {
|
118
124
|
.form-input {
|
119
125
|
@apply border-gray-300 text-gray-700 focus:ring-indigo-300 focus:border-indigo-300 rounded-sm text-sm w-full;
|
120
126
|
}
|
127
|
+
|
128
|
+
.checked-bg {
|
129
|
+
background-color: #ffffff;
|
130
|
+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3E%3Cg fill='%23f3f3f3' fill-opacity='1'%3E%3Cpath fill-rule='evenodd' d='M0 0h4v4H0V0zm4 4h4v4H4V4z'/%3E%3C/g%3E%3C/svg%3E");
|
131
|
+
}
|
121
132
|
}
|
@@ -4,13 +4,41 @@
|
|
4
4
|
&[data-placement^="top"] > .tippy-arrow::before {
|
5
5
|
border-top-color: theme("colors.indigo.500");
|
6
6
|
}
|
7
|
+
|
7
8
|
&[data-placement^="bottom"] > .tippy-arrow::before {
|
8
9
|
border-bottom-color: theme("colors.indigo.500");
|
9
10
|
}
|
11
|
+
|
10
12
|
&[data-placement^="left"] > .tippy-arrow::before {
|
11
13
|
border-left-color: theme("colors.indigo.500");
|
12
14
|
}
|
15
|
+
|
13
16
|
&[data-placement^="right"] > .tippy-arrow::before {
|
14
17
|
border-right-color: theme("colors.indigo.500");
|
15
18
|
}
|
16
19
|
}
|
20
|
+
|
21
|
+
.tippy-box[data-theme~="menu"] {
|
22
|
+
border: 1px solid theme("colors.gray.300");
|
23
|
+
@apply bg-white text-gray-600 shadow-md rounded;
|
24
|
+
|
25
|
+
& > .tippy-content {
|
26
|
+
padding: 0;
|
27
|
+
}
|
28
|
+
|
29
|
+
&[data-placement^="top"] > .tippy-arrow::before {
|
30
|
+
border-top-color: white;
|
31
|
+
}
|
32
|
+
|
33
|
+
&[data-placement^="bottom"] > .tippy-arrow::before {
|
34
|
+
border-bottom-color: white;
|
35
|
+
}
|
36
|
+
|
37
|
+
&[data-placement^="left"] > .tippy-arrow::before {
|
38
|
+
border-left-color: white;
|
39
|
+
}
|
40
|
+
|
41
|
+
&[data-placement^="right"] > .tippy-arrow::before {
|
42
|
+
border-right-color: white;
|
43
|
+
}
|
44
|
+
}
|
@@ -13,7 +13,9 @@ import nav from "./components/nav";
|
|
13
13
|
import navItem from "./components/nav-item";
|
14
14
|
import navGroup from "./components/nav-group";
|
15
15
|
import splitter from "./components/splitter";
|
16
|
+
import tabs from "./components/tabs";
|
16
17
|
import copy from "./components/copy";
|
18
|
+
import code from "./components/code";
|
17
19
|
import sizes from "./components/sizes";
|
18
20
|
|
19
21
|
import initFilterStore from "./stores/filter";
|
@@ -42,11 +44,13 @@ Alpine.data("page", page);
|
|
42
44
|
Alpine.data("splitter", splitter);
|
43
45
|
Alpine.data("previewWindow", previewWindow);
|
44
46
|
Alpine.data("copy", copy);
|
47
|
+
Alpine.data("code", code);
|
45
48
|
Alpine.data("inspector", inspector);
|
46
49
|
Alpine.data("filter", filter);
|
47
50
|
Alpine.data("param", param);
|
48
51
|
Alpine.data("sizes", sizes);
|
49
52
|
Alpine.data("nav", nav);
|
53
|
+
Alpine.data("tabs", tabs);
|
50
54
|
Alpine.data("navItem", navItem);
|
51
55
|
Alpine.data("navGroup", navGroup);
|
52
56
|
|
@@ -1,17 +1,54 @@
|
|
1
|
+
import sizeObserver from "./sizes";
|
2
|
+
|
1
3
|
export default function inspector() {
|
2
4
|
return {
|
5
|
+
width: 0,
|
6
|
+
height: 0,
|
7
|
+
init() {
|
8
|
+
const ro = new ResizeObserver((entries) => {
|
9
|
+
const rect = entries[0].contentRect;
|
10
|
+
this.width = Math.round(rect.width);
|
11
|
+
this.height = Math.round(rect.height);
|
12
|
+
});
|
13
|
+
ro.observe(this.$el);
|
14
|
+
this.width = Math.round(this.$el.clientWidth);
|
15
|
+
this.height = Math.round(this.$el.clientHeight);
|
16
|
+
},
|
17
|
+
get orientation() {
|
18
|
+
return this.$store.inspector.drawer.orientation;
|
19
|
+
},
|
20
|
+
get view() {
|
21
|
+
return this.$store.inspector.preview.view;
|
22
|
+
},
|
23
|
+
get horizontal() {
|
24
|
+
return this.canBeVertical ? this.orientation === "horizontal" : true;
|
25
|
+
},
|
26
|
+
get vertical() {
|
27
|
+
return !this.horizontal;
|
28
|
+
},
|
29
|
+
get canBeVertical() {
|
30
|
+
return this.width > 800;
|
31
|
+
},
|
32
|
+
get drawerHidden() {
|
33
|
+
return this.$store.inspector.drawer.hidden;
|
34
|
+
},
|
3
35
|
isActivePanel(panel) {
|
4
|
-
return this.$store.inspector.
|
36
|
+
return this.$store.inspector.drawer.active == panel;
|
5
37
|
},
|
6
38
|
switchPanel(panel) {
|
7
|
-
this.$store.inspector.
|
39
|
+
this.$store.inspector.drawer.active = panel;
|
40
|
+
},
|
41
|
+
toggleView() {
|
42
|
+
this.$store.inspector.preview.view =
|
43
|
+
this.view === "html" ? "preview" : "html";
|
8
44
|
},
|
9
|
-
|
10
|
-
|
45
|
+
toggleOrientation() {
|
46
|
+
this.$store.inspector.drawer.orientation =
|
47
|
+
this.orientation === "horizontal" ? "vertical" : "horizontal";
|
11
48
|
},
|
12
|
-
|
13
|
-
this.$store.inspector.
|
14
|
-
!this.$store.inspector.
|
49
|
+
toggleDrawer() {
|
50
|
+
this.$store.inspector.drawer.hidden =
|
51
|
+
!this.$store.inspector.drawer.hidden;
|
15
52
|
},
|
16
53
|
preview: {
|
17
54
|
width: null,
|
@@ -15,7 +15,7 @@ export default function navGroup() {
|
|
15
15
|
},
|
16
16
|
getChildren() {
|
17
17
|
return this.$refs.items
|
18
|
-
? Array.from(this.$refs.items.querySelectorAll(":scope > li"))
|
18
|
+
? Array.from(this.$refs.items.querySelectorAll(":scope > li > div"))
|
19
19
|
: [];
|
20
20
|
},
|
21
21
|
navigateToFirstChild() {
|
@@ -1,5 +1,21 @@
|
|
1
1
|
import createSocket from "../lib/socket";
|
2
2
|
|
3
|
+
const morphOpts = {
|
4
|
+
key(el) {
|
5
|
+
return el.getAttribute("key") ? el.getAttribute("key") : el.id;
|
6
|
+
},
|
7
|
+
updating(el, toEl, childrenOnly, skip) {
|
8
|
+
if (
|
9
|
+
el.getAttribute &&
|
10
|
+
el.getAttribute("data-morph-strategy") === "replace"
|
11
|
+
) {
|
12
|
+
el.innerHTML = toEl.innerHTML;
|
13
|
+
return skip();
|
14
|
+
}
|
15
|
+
},
|
16
|
+
lookahead: true,
|
17
|
+
};
|
18
|
+
|
3
19
|
export default function page() {
|
4
20
|
return {
|
5
21
|
init() {
|
@@ -22,11 +38,7 @@ export default function page() {
|
|
22
38
|
},
|
23
39
|
morph(dom) {
|
24
40
|
const pageHtml = dom.getElementById(this.$root.id).outerHTML;
|
25
|
-
Alpine.morph(this.$root, pageHtml,
|
26
|
-
key(el) {
|
27
|
-
return el.getAttribute("key") ? el.getAttribute("key") : el.id;
|
28
|
-
},
|
29
|
-
});
|
41
|
+
Alpine.morph(this.$root, pageHtml, morphOpts);
|
30
42
|
this.$dispatch("page:morphed");
|
31
43
|
},
|
32
44
|
};
|
@@ -1,18 +1,34 @@
|
|
1
|
-
|
1
|
+
import debounce from "debounce";
|
2
|
+
|
3
|
+
export default function param(name, value, opts = {}) {
|
2
4
|
return {
|
3
|
-
|
4
|
-
|
5
|
-
|
5
|
+
name,
|
6
|
+
value,
|
7
|
+
updating: false,
|
8
|
+
init() {
|
9
|
+
if (opts.debounce) {
|
10
|
+
this.$watch(
|
11
|
+
"value",
|
12
|
+
debounce(() => this.updateIfValid(), opts.debounce)
|
13
|
+
);
|
14
|
+
} else {
|
15
|
+
this.$watch("value", () => this.updateIfValid());
|
6
16
|
}
|
7
17
|
},
|
8
|
-
|
18
|
+
setFocus() {
|
19
|
+
setTimeout(() => this.$root.focus(), 0);
|
20
|
+
},
|
21
|
+
updateIfValid() {
|
22
|
+
if (this.validate()) this.update();
|
23
|
+
},
|
24
|
+
update() {
|
9
25
|
const searchParams = new URLSearchParams(window.location.search);
|
10
|
-
searchParams.set(name, value);
|
26
|
+
searchParams.set(this.name, this.value);
|
11
27
|
const path = location.href.replace(location.search, "");
|
12
28
|
this.setLocation(`${path}?${searchParams.toString()}`);
|
13
29
|
},
|
14
30
|
validate() {
|
15
|
-
return this.$
|
31
|
+
return this.$root.reportValidity ? this.$root.reportValidity() : true;
|
16
32
|
},
|
17
33
|
};
|
18
34
|
}
|
@@ -1,37 +1,106 @@
|
|
1
1
|
export default function preview() {
|
2
2
|
return {
|
3
|
-
|
4
|
-
|
5
|
-
this.resizeStartSize - (this.resizeStartPosition - e.pageX) * 2;
|
6
|
-
const parentSize = this.$root.parentElement.clientWidth;
|
7
|
-
const percentSize = (Math.round(size) / parentSize) * 100;
|
8
|
-
const minWidth = (300 / parentSize) * 100;
|
9
|
-
this.$store.inspector.preview.width = `${Math.min(
|
10
|
-
Math.max(percentSize, minWidth),
|
11
|
-
100
|
12
|
-
)}%`;
|
3
|
+
get store() {
|
4
|
+
return this.$store.inspector.preview;
|
13
5
|
},
|
14
|
-
|
6
|
+
get maxWidth() {
|
7
|
+
return this.store.width === "100%" ? "100%" : `${this.store.width}px`;
|
8
|
+
},
|
9
|
+
get maxHeight() {
|
10
|
+
return this.store.height === "100%" ? "100%" : `${this.store.height}px`;
|
11
|
+
},
|
12
|
+
get parentWidth() {
|
13
|
+
return Math.round(this.$root.parentElement.clientWidth);
|
14
|
+
},
|
15
|
+
get parentHeight() {
|
16
|
+
return Math.round(this.$root.parentElement.clientHeight);
|
17
|
+
},
|
18
|
+
start() {
|
15
19
|
this.$store.layout.reflowing = true;
|
16
|
-
this.
|
17
|
-
|
18
|
-
|
19
|
-
this.resizeStartSize = this.$root.clientWidth;
|
20
|
-
window.addEventListener("pointermove", this.onResize);
|
21
|
-
window.addEventListener("pointerup", this.onResizeEnd);
|
22
|
-
},
|
23
|
-
onResizeEnd() {
|
24
|
-
window.removeEventListener("pointermove", this.onResize);
|
25
|
-
window.removeEventListener("pointerup", this.onResizeEnd);
|
20
|
+
this.store.resizing = true;
|
21
|
+
},
|
22
|
+
end() {
|
26
23
|
this.$store.layout.reflowing = false;
|
24
|
+
this.store.resizing = false;
|
25
|
+
},
|
26
|
+
onResizeStart(e) {
|
27
|
+
this.onResizeWidthStart(e);
|
28
|
+
this.onResizeHeightStart(e);
|
29
|
+
},
|
30
|
+
toggleFullSize() {
|
31
|
+
const { height, width } = this.store;
|
32
|
+
if (height === "100%" && width === "100%") {
|
33
|
+
this.toggleFullHeight();
|
34
|
+
this.toggleFullWidth();
|
35
|
+
} else {
|
36
|
+
if (height !== "100%") this.toggleFullHeight();
|
37
|
+
if (width !== "100%") this.toggleFullWidth();
|
38
|
+
}
|
39
|
+
},
|
40
|
+
onResizeWidth(e) {
|
41
|
+
const width =
|
42
|
+
this.resizeStartWidth - (this.resizeStartPositionX - e.pageX) * 2;
|
43
|
+
const boundedWidth = Math.min(
|
44
|
+
Math.max(Math.round(width), 200),
|
45
|
+
this.parentWidth
|
46
|
+
);
|
47
|
+
this.store.width =
|
48
|
+
boundedWidth === this.parentWidth ? "100%" : boundedWidth;
|
49
|
+
},
|
50
|
+
onResizeWidthStart(e) {
|
51
|
+
this.start();
|
52
|
+
this.onResizeWidth = this.onResizeWidth.bind(this);
|
53
|
+
this.onResizeWidthEnd = this.onResizeWidthEnd.bind(this);
|
54
|
+
this.resizeStartPositionX = e.pageX;
|
55
|
+
this.resizeStartWidth = this.$root.clientWidth;
|
56
|
+
window.addEventListener("pointermove", this.onResizeWidth);
|
57
|
+
window.addEventListener("pointerup", this.onResizeWidthEnd);
|
58
|
+
},
|
59
|
+
onResizeWidthEnd() {
|
60
|
+
window.removeEventListener("pointermove", this.onResizeWidth);
|
61
|
+
window.removeEventListener("pointerup", this.onResizeWidthEnd);
|
62
|
+
this.end();
|
27
63
|
},
|
28
64
|
toggleFullWidth() {
|
29
|
-
const
|
30
|
-
if (
|
31
|
-
|
65
|
+
const { width, lastWidth } = this.store;
|
66
|
+
if (width === "100%" && lastWidth) {
|
67
|
+
this.store.width = lastWidth;
|
68
|
+
} else {
|
69
|
+
this.store.lastWidth = width;
|
70
|
+
this.store.width = "100%";
|
71
|
+
}
|
72
|
+
},
|
73
|
+
onResizeHeight(e) {
|
74
|
+
const height =
|
75
|
+
this.resizeStartHeight - (this.resizeStartPositionY - e.pageY);
|
76
|
+
const boundedHeight = Math.min(
|
77
|
+
Math.max(Math.round(height), 200),
|
78
|
+
this.parentHeight
|
79
|
+
);
|
80
|
+
this.$store.inspector.preview.height =
|
81
|
+
boundedHeight === this.parentHeight ? "100%" : boundedHeight;
|
82
|
+
},
|
83
|
+
onResizeHeightStart(e) {
|
84
|
+
this.start();
|
85
|
+
this.onResizeHeight = this.onResizeHeight.bind(this);
|
86
|
+
this.onResizeHeightEnd = this.onResizeHeightEnd.bind(this);
|
87
|
+
this.resizeStartPositionY = e.pageY;
|
88
|
+
this.resizeStartHeight = this.$root.clientHeight;
|
89
|
+
window.addEventListener("pointermove", this.onResizeHeight);
|
90
|
+
window.addEventListener("pointerup", this.onResizeHeightEnd);
|
91
|
+
},
|
92
|
+
onResizeHeightEnd() {
|
93
|
+
window.removeEventListener("pointermove", this.onResizeHeight);
|
94
|
+
window.removeEventListener("pointerup", this.onResizeHeightEnd);
|
95
|
+
this.end();
|
96
|
+
},
|
97
|
+
toggleFullHeight() {
|
98
|
+
const { height, lastHeight } = this.store;
|
99
|
+
if (height === "100%" && lastHeight) {
|
100
|
+
this.store.height = lastHeight;
|
32
101
|
} else {
|
33
|
-
|
34
|
-
|
102
|
+
this.store.lastHeight = height;
|
103
|
+
this.store.height = "100%";
|
35
104
|
}
|
36
105
|
},
|
37
106
|
};
|
@@ -0,0 +1,50 @@
|
|
1
|
+
import tippy from "tippy.js";
|
2
|
+
|
3
|
+
export default function tabs() {
|
4
|
+
return {
|
5
|
+
width: 0,
|
6
|
+
tabsWidth: 0,
|
7
|
+
init() {
|
8
|
+
const ro = new ResizeObserver((entries) => {
|
9
|
+
this.width = Math.round(entries[0].contentRect.width);
|
10
|
+
});
|
11
|
+
ro.observe(this.$refs.tabs);
|
12
|
+
this.dropdown = tippy(this.$refs.toggle, {
|
13
|
+
allowHTML: true,
|
14
|
+
interactive: true,
|
15
|
+
trigger: "click",
|
16
|
+
placement: "bottom-end",
|
17
|
+
theme: "menu",
|
18
|
+
content: this.$refs.dropdown,
|
19
|
+
});
|
20
|
+
},
|
21
|
+
get tabs() {
|
22
|
+
return Array.from(this.$refs.tabs.querySelectorAll(":scope > a"));
|
23
|
+
},
|
24
|
+
get visibleTabCount() {
|
25
|
+
let cumulativeWidth = 0;
|
26
|
+
for (let i = 0; i < this.tabs.length; i++) {
|
27
|
+
const el = this.tabs[i];
|
28
|
+
const margin = parseInt(
|
29
|
+
window
|
30
|
+
.getComputedStyle(el)
|
31
|
+
.getPropertyValue("margin-left")
|
32
|
+
.replace("px", ""),
|
33
|
+
10
|
34
|
+
);
|
35
|
+
cumulativeWidth += el.clientWidth + margin;
|
36
|
+
if (cumulativeWidth > this.width) {
|
37
|
+
this.tabsWidth = cumulativeWidth - el.clientWidth;
|
38
|
+
return i;
|
39
|
+
}
|
40
|
+
}
|
41
|
+
return this.tabs.length;
|
42
|
+
},
|
43
|
+
get hiddenTabs() {
|
44
|
+
return this.tabs.slice(this.visibleTabCount, -1);
|
45
|
+
},
|
46
|
+
hideDropdown() {
|
47
|
+
this.dropdown.hide();
|
48
|
+
},
|
49
|
+
};
|
50
|
+
}
|
@@ -3,12 +3,18 @@ export default {
|
|
3
3
|
sidebar: {
|
4
4
|
defaultWidth: 280,
|
5
5
|
minWidth: 200,
|
6
|
-
maxWidth:
|
6
|
+
maxWidth: 350,
|
7
7
|
},
|
8
8
|
inspector: {
|
9
|
-
|
10
|
-
|
9
|
+
drawer: {
|
10
|
+
orientation: "horizontal",
|
11
|
+
defaultPanel: "source",
|
11
12
|
defaultHeight: 200,
|
13
|
+
defaultWidth: 500,
|
14
|
+
minWidth: 350,
|
15
|
+
},
|
16
|
+
preview: {
|
17
|
+
view: "preview",
|
12
18
|
},
|
13
19
|
},
|
14
20
|
};
|
@@ -1,17 +1,24 @@
|
|
1
1
|
import config from "../config";
|
2
2
|
|
3
3
|
export default function createInspectorStore(Alpine) {
|
4
|
-
const {
|
4
|
+
const { drawer, preview } = config.inspector;
|
5
5
|
return {
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
drawer: {
|
7
|
+
hidden: Alpine.$persist(false).as("drawer-hidden"),
|
8
|
+
orientation: Alpine.$persist(drawer.orientation).as("drawer-orientation"),
|
9
|
+
active: Alpine.$persist(drawer.defaultPanel).as("drawer-active"),
|
10
|
+
height: Alpine.$persist(drawer.defaultHeight).as("drawer-height"),
|
11
|
+
width: Alpine.$persist(drawer.defaultWidth).as("drawer-width"),
|
12
|
+
minWidth: drawer.minWidth,
|
13
|
+
visibleTabCount: Infinity,
|
9
14
|
},
|
10
15
|
preview: {
|
11
16
|
width: Alpine.$persist("100%").as("preview-width"),
|
12
17
|
height: Alpine.$persist("100%").as("preview-height"),
|
13
|
-
|
18
|
+
view: Alpine.$persist(preview.view).as("preview-view"),
|
14
19
|
lastWidth: null,
|
20
|
+
lastHeight: null,
|
21
|
+
resizing: false,
|
15
22
|
},
|
16
23
|
};
|
17
24
|
}
|
@@ -27,7 +27,9 @@ module Lookbook
|
|
27
27
|
begin
|
28
28
|
set_params
|
29
29
|
@examples = examples_data
|
30
|
-
@preview_srcdoc =
|
30
|
+
@preview_srcdoc = if Lookbook.config.preview_srcdoc
|
31
|
+
render_examples(examples_data).gsub("\"", """)
|
32
|
+
end
|
31
33
|
@panels = panels.filter { |name, panel| panel[:show] }
|
32
34
|
rescue *EXCEPTIONS
|
33
35
|
render "error"
|
@@ -13,7 +13,7 @@
|
|
13
13
|
window.SOCKET_PATH = "<%= Lookbook::Engine.websocket_mount_path %>";
|
14
14
|
</script>
|
15
15
|
<% end %>
|
16
|
-
<script src="/lookbook-assets/js/app.js?v=<%= Lookbook
|
16
|
+
<script src="/lookbook-assets/js/app.js?v=<%= Lookbook.version %>" defer></script>
|
17
17
|
|
18
18
|
<title><%= [@example&.label, @preview&.label, "Lookbook"].compact.join(" :: ") %></title>
|
19
19
|
</head>
|
@@ -44,9 +44,13 @@
|
|
44
44
|
x-effect="$store.sidebar.width = Math.min(splits[0] || $store.sidebar.width, $store.sidebar.maxWidth)"
|
45
45
|
x-cloak
|
46
46
|
>
|
47
|
-
<div class="w-[9px] h-full bg-transparent hover:bg-indigo-100 hover:bg-opacity-20 transition absolute top-0 bottom-0
|
47
|
+
<div class="w-[9px] h-full bg-transparent hover:bg-indigo-100 hover:bg-opacity-20 transition absolute top-0 bottom-0 -translate-x-1/2 cursor-[col-resize] z-10"></div>
|
48
48
|
</div>
|
49
|
-
<main
|
49
|
+
<main
|
50
|
+
id="main"
|
51
|
+
class="h-full overflow-hidden w-full"
|
52
|
+
x-show="$store.layout.desktop || !$store.sidebar.open" x-cloak
|
53
|
+
>
|
50
54
|
<%= yield %>
|
51
55
|
</main>
|
52
56
|
</div>
|