lookbook 0.2.3 → 0.3.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 +93 -0
- data/app/assets/lookbook/css/app.css +28 -0
- data/app/assets/lookbook/js/app.js +49 -24
- data/app/assets/lookbook/js/nav/leaf.js +20 -0
- data/app/assets/lookbook/js/nav/node.js +31 -0
- data/app/assets/lookbook/js/nav.js +39 -0
- data/app/assets/lookbook/js/page.js +33 -0
- data/app/assets/lookbook/js/utils/clipboard.js +13 -0
- data/app/assets/lookbook/js/utils/morph.js +16 -0
- data/app/assets/lookbook/js/{reloader.js → utils/reloader.js} +0 -0
- data/app/assets/lookbook/js/utils/screen.js +44 -0
- data/app/assets/lookbook/js/{size_observer.js → utils/size_observer.js} +1 -1
- data/app/assets/lookbook/js/{split.js → utils/split.js} +4 -4
- data/app/assets/lookbook/js/workbench/inspector.js +11 -0
- data/app/assets/lookbook/js/workbench/preview.js +39 -0
- data/app/assets/lookbook/js/workbench.js +14 -0
- data/app/controllers/lookbook/{browser_controller.rb → app_controller.rb} +58 -31
- data/app/helpers/lookbook/application_helper.rb +1 -1
- data/app/views/lookbook/_sidebar.html.erb +45 -0
- data/app/views/lookbook/_workbench.html.erb +12 -0
- data/app/views/lookbook/{browser → app}/error.html.erb +0 -0
- data/app/views/lookbook/app/index.html.erb +11 -0
- data/app/views/lookbook/{browser → app}/not_found.html.erb +1 -1
- data/app/views/lookbook/app/show.html.erb +1 -0
- data/app/views/lookbook/layouts/app.html.erb +16 -26
- data/app/views/lookbook/nav/_collection.html.erb +5 -0
- data/app/views/lookbook/nav/_leaf.html.erb +21 -0
- data/app/views/lookbook/nav/_node.html.erb +19 -0
- data/app/views/lookbook/nav/_preview.html.erb +11 -0
- data/app/views/lookbook/preview_group.html.erb +8 -0
- data/app/views/lookbook/shared/_clipboard.html.erb +11 -0
- data/app/views/lookbook/shared/_header.html.erb +8 -0
- data/app/views/lookbook/workbench/_header.html.erb +37 -0
- data/app/views/lookbook/workbench/_inspector.html.erb +32 -0
- data/app/views/lookbook/workbench/_preview.html.erb +24 -0
- data/app/views/lookbook/workbench/inspector/_code.html.erb +3 -0
- data/app/views/lookbook/workbench/inspector/_notes.html.erb +24 -0
- data/app/views/lookbook/{partials → workbench}/inspector/_plain.html.erb +0 -0
- data/config/routes.rb +3 -3
- data/lib/lookbook/engine.rb +1 -0
- data/lib/lookbook/preview.rb +26 -3
- data/lib/lookbook/preview_controller.rb +6 -1
- data/lib/lookbook/preview_example.rb +3 -2
- data/lib/lookbook/preview_group.rb +37 -0
- data/lib/lookbook/taggable.rb +5 -1
- data/lib/lookbook/version.rb +1 -1
- data/lib/lookbook.rb +1 -0
- data/lib/tasks/lookbook_tasks.rake +1 -1
- data/public/lookbook-assets/app.css +229 -99
- data/public/lookbook-assets/app.js +882 -56
- data/{app/views/lookbook/partials/_icon_sprite.html.erb → public/lookbook-assets/feather-sprite.svg} +1 -1
- metadata +53 -24
- data/app/assets/lookbook/js/preview.js +0 -76
- data/app/views/lookbook/browser/index.html.erb +0 -8
- data/app/views/lookbook/browser/show.html.erb +0 -33
- data/app/views/lookbook/partials/_preview.html.erb +0 -18
- data/app/views/lookbook/partials/_sidebar.html.erb +0 -21
- data/app/views/lookbook/partials/inspector/_code.html.erb +0 -1
- data/app/views/lookbook/partials/inspector/_inspector.html.erb +0 -43
- data/app/views/lookbook/partials/inspector/_prose.html.erb +0 -3
- data/app/views/lookbook/partials/nav/_collection.html.erb +0 -17
- data/app/views/lookbook/partials/nav/_label.html.erb +0 -13
- data/app/views/lookbook/partials/nav/_nav.html.erb +0 -27
- data/app/views/lookbook/partials/nav/_preview.html.erb +0 -48
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 61d3cbcc3579d9a79aaa03fb87bda891923c10aed37eb78f11ef948b09b99ed9
|
4
|
+
data.tar.gz: 9ac3803965a4d9fc17eed96bb8a2e2a0821c78019e061032fa5f22276edbe321
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4d902210204c1f779a535dcf6aec261b827ff92cef73ce384f2d791ccc0fb85ff0f5de0d56f2cf19aeff67f5190a1ea753b1f6d2016108bc7fe3be55b8b0930e
|
7
|
+
data.tar.gz: 3d52cc3c23b60d1cc8fdef2f753ff7e80ad858e0f2eec598212307cfa0338b69b87071fd3fa45a3848f303533f033b1c55dc0995ba15364c9f831daa2c893338
|
data/README.md
CHANGED
@@ -112,6 +112,29 @@ class ButtonComponentPreview < ViewComponent::Preview
|
|
112
112
|
"Click me"
|
113
113
|
end
|
114
114
|
end
|
115
|
+
|
116
|
+
# @!group More examples
|
117
|
+
|
118
|
+
def short_text
|
119
|
+
render ButtonComponent.new do
|
120
|
+
"Go"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def long_text
|
125
|
+
render ButtonComponent.new do
|
126
|
+
"Click here to do this thing because it's the best way to do it"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def emoji_text
|
131
|
+
render ButtonComponent.new do
|
132
|
+
"👀📗"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# @!endgroup
|
137
|
+
|
115
138
|
end
|
116
139
|
```
|
117
140
|
|
@@ -153,6 +176,52 @@ class FooComponentPreview < ViewComponent::Preview
|
|
153
176
|
end
|
154
177
|
```
|
155
178
|
|
179
|
+
#### `@!group <name> ... @!endgroup`
|
180
|
+
|
181
|
+
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.
|
182
|
+
|
183
|
+
You can group a set of examples by wrapping them in `@!group <name>` / `@!endgroup` tags within your preview file:
|
184
|
+
|
185
|
+
```ruby
|
186
|
+
class HeaderComponentPreview < ViewComponent::Preview
|
187
|
+
|
188
|
+
def standard
|
189
|
+
render Elements::HeaderComponent.new do
|
190
|
+
"Standard header"
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
# @!group Sizes
|
195
|
+
|
196
|
+
def small
|
197
|
+
render Elements::HeaderComponent.new(size: 12) do
|
198
|
+
"Small header"
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def medium
|
203
|
+
render Elements::HeaderComponent.new(size: 16) do
|
204
|
+
"Small header"
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def big
|
209
|
+
render Elements::HeaderComponent.new(size: 24) do
|
210
|
+
"Small header"
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
# @!endgroup
|
215
|
+
|
216
|
+
end
|
217
|
+
```
|
218
|
+
|
219
|
+
The example above would display the `Sizes` examples grouped together on a single page, rather than as indiviual items in the navigation:
|
220
|
+
|
221
|
+
<img src=".github/assets/nav_group.png">
|
222
|
+
|
223
|
+
You can have as many groups as you like within a single preview class, but each example can only belong to one group.
|
224
|
+
|
156
225
|
#### Adding notes
|
157
226
|
|
158
227
|
All comment text other than tags will be treated as markdown and rendered in the **Notes** panel for that example in the Lookbook UI.
|
@@ -193,6 +262,30 @@ If you wish to add additional paths to listen for changes in, you can use the `l
|
|
193
262
|
config.lookbook.listen_paths << Rails.root.join('app/other/directory')
|
194
263
|
```
|
195
264
|
|
265
|
+
## Keyboard shortcuts
|
266
|
+
|
267
|
+
Lookbook provides a few keyboard shortcuts to help you quickly move around the UI.
|
268
|
+
|
269
|
+
- `f` - move focus to the nav filter box
|
270
|
+
- `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
|
271
|
+
- `s` - Switch to Source tab in the inspector
|
272
|
+
- `o` - Switch to Output tab in the inspector
|
273
|
+
- `n` - Switch to Notes tab in the inspector
|
274
|
+
- `r` - Refresh the preview (useful if using something like Faker to generate randomised data for the preview)
|
275
|
+
- `w` - Open the standalone rendered preview in a new window
|
276
|
+
|
277
|
+
## Troubleshooting
|
278
|
+
|
279
|
+
#### Blank preview window
|
280
|
+
|
281
|
+
Certain setups (for example when using `Rack::LiveReload`) can cause an issue with the way that the preview iframe displays the rendered component preview (i.e. using the `srcdoc` attribute to avoid extra requests).
|
282
|
+
|
283
|
+
If you are seeing a blank preview window, but the source and output tabs are both displaying code as expected, you can disable the use of the `srcdoc` attribute using the following configuration option:
|
284
|
+
|
285
|
+
```ruby
|
286
|
+
config.lookbook.preview_srcdoc = false
|
287
|
+
```
|
288
|
+
|
196
289
|
## Contributing
|
197
290
|
|
198
291
|
Lookbook is very much a small hobby/side project at the moment. I'd love to hear from anyone who is interested in contributing but I'm terrible at replying to emails or messages, so don't be surprised if I take forever to get back to you. It's not personal 😜
|
@@ -34,4 +34,32 @@
|
|
34
34
|
stroke-linejoin: round;
|
35
35
|
fill: none;
|
36
36
|
}
|
37
|
+
|
38
|
+
.h-fill {
|
39
|
+
height: fill-available;
|
40
|
+
}
|
41
|
+
|
42
|
+
.min-h-fill {
|
43
|
+
min-height: fill-available;
|
44
|
+
}
|
45
|
+
|
46
|
+
::-webkit-scrollbar {
|
47
|
+
width: 8px;
|
48
|
+
height: 8px;
|
49
|
+
}
|
50
|
+
|
51
|
+
::-webkit-scrollbar-track {
|
52
|
+
background: transparent;
|
53
|
+
}
|
54
|
+
|
55
|
+
::-webkit-scrollbar-thumb {
|
56
|
+
@apply bg-gray-300 transition-colors;
|
57
|
+
border-radius: 6px;
|
58
|
+
border: 2px solid transparent;
|
59
|
+
background-clip: content-box;
|
60
|
+
}
|
61
|
+
|
62
|
+
::-webkit-scrollbar-thumb:hover {
|
63
|
+
@apply bg-gray-400;
|
64
|
+
}
|
37
65
|
}
|
@@ -1,49 +1,74 @@
|
|
1
|
+
import { install } from "@github/hotkey";
|
1
2
|
import Alpine from "alpinejs";
|
2
3
|
import Fern from "@ryangjchandler/fern";
|
3
|
-
import
|
4
|
-
import
|
5
|
-
import
|
6
|
-
import
|
7
|
-
import
|
8
|
-
import
|
4
|
+
import AlpineTooltip from "@ryangjchandler/alpine-tooltip";
|
5
|
+
import AlpineClipboard from "@ryangjchandler/alpine-clipboard";
|
6
|
+
import Screen from "./utils/screen";
|
7
|
+
import split from "./utils/split";
|
8
|
+
import page from "./page";
|
9
|
+
import workbench from "./workbench";
|
10
|
+
import preview from "./workbench/preview";
|
11
|
+
import inspector from "./workbench/inspector";
|
12
|
+
import nav from "./nav";
|
13
|
+
import navNode from "./nav/node";
|
14
|
+
import navLeaf from "./nav/leaf";
|
15
|
+
import sizeObserver from "./utils/size_observer";
|
16
|
+
import reloader from "./utils/reloader";
|
17
|
+
import clipboard from "./utils/clipboard";
|
18
|
+
|
19
|
+
window.Alpine = Alpine;
|
9
20
|
|
10
21
|
// Plugins
|
11
22
|
|
12
23
|
Alpine.plugin(Fern);
|
13
|
-
Alpine.plugin(
|
14
|
-
Alpine.plugin(
|
15
|
-
|
16
|
-
// Data
|
17
|
-
|
18
|
-
Alpine.data("preview", preview);
|
19
|
-
Alpine.data("sizeObserver", observeSize);
|
20
|
-
Alpine.data("split", split);
|
24
|
+
Alpine.plugin(AlpineTooltip);
|
25
|
+
Alpine.plugin(AlpineClipboard);
|
26
|
+
Alpine.plugin(Screen);
|
21
27
|
|
22
28
|
// Stores
|
23
29
|
|
24
|
-
Alpine.store("
|
30
|
+
Alpine.store("page", {
|
31
|
+
reflowing: false,
|
32
|
+
doc: window.document,
|
33
|
+
});
|
34
|
+
|
25
35
|
Alpine.persistedStore("nav", {
|
26
36
|
width: 280,
|
27
37
|
filter: "",
|
28
38
|
open: {},
|
29
|
-
scrollTop: 0,
|
30
|
-
shouldDisplay(previewName) {
|
31
|
-
const cleanFilter = this.filter.replace(/\s/g, "");
|
32
|
-
return (
|
33
|
-
cleanFilter === "" || previewName.includes(cleanFilter.toLowerCase())
|
34
|
-
);
|
35
|
-
},
|
36
39
|
});
|
37
|
-
|
40
|
+
|
38
41
|
Alpine.persistedStore("inspector", {
|
39
42
|
height: 200,
|
40
43
|
active: "source",
|
41
44
|
});
|
42
45
|
|
46
|
+
Alpine.persistedStore("preview", {
|
47
|
+
width: "100%",
|
48
|
+
});
|
49
|
+
|
50
|
+
// Components & utils
|
51
|
+
|
52
|
+
Alpine.data("page", page);
|
53
|
+
Alpine.data("nav", nav);
|
54
|
+
Alpine.data("navNode", navNode);
|
55
|
+
Alpine.data("navLeaf", navLeaf);
|
56
|
+
Alpine.data("workbench", workbench);
|
57
|
+
Alpine.data("preview", preview);
|
58
|
+
Alpine.data("inspector", inspector);
|
59
|
+
Alpine.data("clipboard", clipboard);
|
60
|
+
Alpine.data("sizeObserver", sizeObserver);
|
61
|
+
Alpine.data("split", split);
|
62
|
+
|
43
63
|
// Init
|
44
64
|
|
45
|
-
|
65
|
+
for (const el of document.querySelectorAll("[data-hotkey]")) {
|
66
|
+
install(el);
|
67
|
+
}
|
68
|
+
|
46
69
|
if (window.SOCKET_PATH) {
|
47
70
|
reloader(window.SOCKET_PATH).start();
|
48
71
|
}
|
72
|
+
|
73
|
+
window.Alpine = Alpine;
|
49
74
|
Alpine.start();
|
@@ -0,0 +1,20 @@
|
|
1
|
+
export default function navLeaf() {
|
2
|
+
return {
|
3
|
+
path: null,
|
4
|
+
matchers: [],
|
5
|
+
active: false,
|
6
|
+
hidden: false,
|
7
|
+
setActive() {
|
8
|
+
this.active = this.path === window.location.pathname;
|
9
|
+
},
|
10
|
+
filter() {
|
11
|
+
if (this.$store.nav.filtering) {
|
12
|
+
const text = this.$store.nav.filterText;
|
13
|
+
const matched = this.matchers.map((m) => m.includes(text));
|
14
|
+
this.hidden = !matched.filter((m) => m).length;
|
15
|
+
} else {
|
16
|
+
this.hidden = false;
|
17
|
+
}
|
18
|
+
},
|
19
|
+
};
|
20
|
+
}
|
@@ -0,0 +1,31 @@
|
|
1
|
+
export default function navNode() {
|
2
|
+
return {
|
3
|
+
id: null,
|
4
|
+
hidden: true,
|
5
|
+
children: [],
|
6
|
+
init() {
|
7
|
+
this.id = this.$el.id;
|
8
|
+
},
|
9
|
+
open() {
|
10
|
+
return this.$store.nav.open[this.id];
|
11
|
+
},
|
12
|
+
getChildren() {
|
13
|
+
return this.$refs.items
|
14
|
+
? Array.from(this.$refs.items.querySelectorAll(":scope > li"))
|
15
|
+
: [];
|
16
|
+
},
|
17
|
+
filter() {
|
18
|
+
this.hidden = true;
|
19
|
+
this.getChildren().forEach((child) => {
|
20
|
+
const data = child._x_dataStack[0];
|
21
|
+
data.filter();
|
22
|
+
if (!data.hidden) {
|
23
|
+
this.hidden = false;
|
24
|
+
}
|
25
|
+
});
|
26
|
+
},
|
27
|
+
toggle() {
|
28
|
+
this.$store.nav.open[this.id] = !this.$store.nav.open[this.id];
|
29
|
+
},
|
30
|
+
};
|
31
|
+
}
|
@@ -0,0 +1,39 @@
|
|
1
|
+
import morph from "./utils/morph";
|
2
|
+
|
3
|
+
export default function () {
|
4
|
+
return {
|
5
|
+
clearFilter() {
|
6
|
+
this.$store.nav.filter = "";
|
7
|
+
},
|
8
|
+
init() {
|
9
|
+
this.$watch("$store.nav.filter", (value) => {
|
10
|
+
const nav = this.$store.nav;
|
11
|
+
nav.filterText = value.replace(/\s/g, "").toLowerCase();
|
12
|
+
nav.filtering = nav.filterText.length > 0;
|
13
|
+
});
|
14
|
+
},
|
15
|
+
updateNav(event) {
|
16
|
+
const nav = document.getElementById("nav");
|
17
|
+
nav.style.height = `${this.$refs.shim.offsetHeight}px`;
|
18
|
+
morph(nav, event.detail.doc.getElementById("nav"));
|
19
|
+
Promise.resolve().then(() => {
|
20
|
+
this.$refs.shim.style.height = "auto";
|
21
|
+
this.$dispatch("nav:updated");
|
22
|
+
});
|
23
|
+
},
|
24
|
+
navigate(path) {
|
25
|
+
if (path instanceof Event) {
|
26
|
+
path = path.currentTarget.href;
|
27
|
+
}
|
28
|
+
history.pushState({}, null, path);
|
29
|
+
this.$dispatch("popstate");
|
30
|
+
},
|
31
|
+
focusFilter() {
|
32
|
+
this.currentFocus = this.$refs.filter;
|
33
|
+
setTimeout(() => this.$refs.filter.focus(), 0);
|
34
|
+
},
|
35
|
+
unfocusFilter() {
|
36
|
+
this.$refs.filter.blur();
|
37
|
+
},
|
38
|
+
};
|
39
|
+
}
|
@@ -0,0 +1,33 @@
|
|
1
|
+
import morph from "./utils/morph";
|
2
|
+
|
3
|
+
export default function page() {
|
4
|
+
const store = Alpine.store("page");
|
5
|
+
return {
|
6
|
+
ready: false,
|
7
|
+
sidebarOpenMobile: false,
|
8
|
+
init() {
|
9
|
+
this.$nextTick(() => (this.ready = true));
|
10
|
+
},
|
11
|
+
splitProps: {
|
12
|
+
minSize: 200,
|
13
|
+
onDrag(splits) {
|
14
|
+
Alpine.store("nav").width = Math.min(splits[0], 500);
|
15
|
+
},
|
16
|
+
},
|
17
|
+
async fetchHTML() {
|
18
|
+
const response = await fetch(window.document.location);
|
19
|
+
if (!response.ok) return window.location.reload();
|
20
|
+
const html = await response.text();
|
21
|
+
store.doc = new DOMParser().parseFromString(html, "text/html");
|
22
|
+
return store.doc;
|
23
|
+
},
|
24
|
+
updateTitle() {
|
25
|
+
document.title = store.doc.title;
|
26
|
+
},
|
27
|
+
render() {
|
28
|
+
if (this.ready) {
|
29
|
+
morph(this.$el, store.doc.getElementById(this.$el.id));
|
30
|
+
}
|
31
|
+
},
|
32
|
+
};
|
33
|
+
}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
import morph from "morphdom";
|
2
|
+
|
3
|
+
export default function (from, to, opts = {}) {
|
4
|
+
morph(from, to, {
|
5
|
+
onBeforeElUpdated: function (fromEl, toEl) {
|
6
|
+
if (fromEl._x_dataStack) {
|
7
|
+
Alpine.clone(fromEl, toEl);
|
8
|
+
}
|
9
|
+
if (fromEl.isEqualNode(toEl)) {
|
10
|
+
return false;
|
11
|
+
}
|
12
|
+
return true;
|
13
|
+
},
|
14
|
+
...opts,
|
15
|
+
});
|
16
|
+
}
|
File without changes
|
@@ -0,0 +1,44 @@
|
|
1
|
+
// Adapted from: https://github.com/alpine-collective/toolkit
|
2
|
+
|
3
|
+
export default function (Alpine) {
|
4
|
+
// Create reactive data context
|
5
|
+
let data = Alpine.reactive({ screensize: window.innerWidth });
|
6
|
+
|
7
|
+
// Configuration
|
8
|
+
const defaultBreakpoints = {
|
9
|
+
xs: 0,
|
10
|
+
sm: 640,
|
11
|
+
md: 768,
|
12
|
+
lg: 1024,
|
13
|
+
xl: 1280,
|
14
|
+
"2xl": 1536,
|
15
|
+
};
|
16
|
+
|
17
|
+
const breakpoints =
|
18
|
+
window.AlpineMagicHelpersConfig &&
|
19
|
+
window.AlpineMagicHelpersConfig.breakpoints
|
20
|
+
? window.AlpineMagicHelpersConfig.breakpoints
|
21
|
+
: defaultBreakpoints;
|
22
|
+
|
23
|
+
window.addEventListener("resize", () => {
|
24
|
+
data.screensize = window.innerWidth;
|
25
|
+
});
|
26
|
+
|
27
|
+
Alpine.magic("screen", () => (breakpoint) => {
|
28
|
+
let width = data.screensize;
|
29
|
+
|
30
|
+
if (Number.isInteger(breakpoint)) return breakpoint <= width;
|
31
|
+
|
32
|
+
// Check if breakpoint exists
|
33
|
+
if (breakpoints[breakpoint] === undefined) {
|
34
|
+
throw Error(
|
35
|
+
"Undefined $screen property: " +
|
36
|
+
breakpoint +
|
37
|
+
". Supported properties: " +
|
38
|
+
Object.keys(breakpoints).join(", ")
|
39
|
+
);
|
40
|
+
}
|
41
|
+
|
42
|
+
return breakpoints[breakpoint] <= width;
|
43
|
+
});
|
44
|
+
}
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import Split from "split-grid";
|
2
2
|
|
3
3
|
export default function (props) {
|
4
|
-
const
|
4
|
+
const page = Alpine.store("page");
|
5
5
|
return {
|
6
6
|
init() {
|
7
7
|
Split({
|
@@ -11,14 +11,14 @@ export default function (props) {
|
|
11
11
|
minSize: props.minSize,
|
12
12
|
writeStyle() {},
|
13
13
|
onDrag(dir, track, style) {
|
14
|
-
splits = style.split(" ").map((num) => parseInt(num));
|
14
|
+
const splits = style.split(" ").map((num) => parseInt(num));
|
15
15
|
props.onDrag(splits);
|
16
16
|
},
|
17
17
|
onDragStart() {
|
18
|
-
|
18
|
+
page.reflowing = true;
|
19
19
|
},
|
20
20
|
onDragEnd() {
|
21
|
-
|
21
|
+
page.reflowing = false;
|
22
22
|
},
|
23
23
|
});
|
24
24
|
},
|
@@ -0,0 +1,39 @@
|
|
1
|
+
export default function preview() {
|
2
|
+
const app = Alpine.store("page");
|
3
|
+
const preview = Alpine.store("preview");
|
4
|
+
return {
|
5
|
+
init() {
|
6
|
+
this.root = this.$el;
|
7
|
+
},
|
8
|
+
onResize(e) {
|
9
|
+
const size =
|
10
|
+
this.resizeStartSize - (this.resizeStartPosition - e.pageX) * 2;
|
11
|
+
const parentSize = this.root.parentElement.clientWidth;
|
12
|
+
const percentSize = (Math.round(size) / parentSize) * 100;
|
13
|
+
const minWidth = (300 / parentSize) * 100;
|
14
|
+
preview.width = `${Math.min(Math.max(percentSize, minWidth), 100)}%`;
|
15
|
+
},
|
16
|
+
onResizeStart(e) {
|
17
|
+
app.reflowing = true;
|
18
|
+
this.onResize = this.onResize.bind(this);
|
19
|
+
this.onResizeEnd = this.onResizeEnd.bind(this);
|
20
|
+
this.resizeStartPosition = e.pageX;
|
21
|
+
this.resizeStartSize = this.root.clientWidth;
|
22
|
+
window.addEventListener("pointermove", this.onResize);
|
23
|
+
window.addEventListener("pointerup", this.onResizeEnd);
|
24
|
+
},
|
25
|
+
onResizeEnd() {
|
26
|
+
window.removeEventListener("pointermove", this.onResize);
|
27
|
+
window.removeEventListener("pointerup", this.onResizeEnd);
|
28
|
+
app.reflowing = false;
|
29
|
+
},
|
30
|
+
toggleFullWidth() {
|
31
|
+
if (preview.width === "100%" && preview.lastWidth) {
|
32
|
+
preview.width = preview.lastWidth;
|
33
|
+
} else {
|
34
|
+
preview.lastWidth = preview.width;
|
35
|
+
preview.width = "100%";
|
36
|
+
}
|
37
|
+
},
|
38
|
+
};
|
39
|
+
}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
export default function workbench() {
|
2
|
+
const inspector = Alpine.store("inspector");
|
3
|
+
return {
|
4
|
+
previewViewportHeight: 0,
|
5
|
+
previewViewportWidth: 0,
|
6
|
+
splitProps: {
|
7
|
+
direction: "vertical",
|
8
|
+
minSize: 200,
|
9
|
+
onDrag(splits) {
|
10
|
+
inspector.height = splits[2];
|
11
|
+
},
|
12
|
+
},
|
13
|
+
};
|
14
|
+
}
|