lookbook 0.4.6 → 0.4.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/lookbook/css/app.css +55 -5
  3. data/app/assets/lookbook/js/app.js +38 -54
  4. data/app/assets/lookbook/js/components/copy.js +16 -0
  5. data/app/assets/lookbook/js/components/filter.js +24 -0
  6. data/app/assets/lookbook/js/components/inspector.js +21 -0
  7. data/app/assets/lookbook/js/{nav/node.js → components/nav-group.js} +16 -15
  8. data/app/assets/lookbook/js/components/nav-item.js +26 -0
  9. data/app/assets/lookbook/js/components/nav.js +35 -0
  10. data/app/assets/lookbook/js/components/page.js +33 -0
  11. data/app/assets/lookbook/js/{workbench → components}/param.js +3 -4
  12. data/app/assets/lookbook/js/{workbench/preview.js → components/preview-window.js} +9 -10
  13. data/app/assets/lookbook/js/components/sidebar.js +3 -0
  14. data/app/assets/lookbook/js/components/sizes.js +16 -0
  15. data/app/assets/lookbook/js/components/splitter.js +25 -0
  16. data/app/assets/lookbook/js/config.js +14 -0
  17. data/app/assets/lookbook/js/{utils/reloader.js → lib/socket.js} +7 -12
  18. data/app/assets/lookbook/js/lib/split.js +21 -0
  19. data/app/assets/lookbook/js/lib/utils.js +3 -0
  20. data/app/assets/lookbook/js/stores/filter.js +11 -0
  21. data/app/assets/lookbook/js/stores/inspector.js +17 -0
  22. data/app/assets/lookbook/js/stores/layout.js +12 -0
  23. data/app/assets/lookbook/js/stores/nav.js +21 -0
  24. data/app/assets/lookbook/js/stores/sidebar.js +14 -0
  25. data/app/controllers/lookbook/app_controller.rb +70 -97
  26. data/app/helpers/lookbook/application_helper.rb +48 -4
  27. data/app/views/layouts/lookbook/app.html.erb +54 -0
  28. data/app/views/layouts/lookbook/preview.html.erb +12 -0
  29. data/app/views/lookbook/components/_code.html.erb +8 -0
  30. data/app/views/lookbook/{shared/_clipboard.html.erb → components/_copy.html.erb} +4 -5
  31. data/app/views/lookbook/components/_filter.html.erb +15 -0
  32. data/app/views/lookbook/{shared → components}/_header.html.erb +3 -3
  33. data/app/views/lookbook/components/_icon.html.erb +5 -0
  34. data/app/views/lookbook/components/_nav.html.erb +17 -0
  35. data/app/views/lookbook/components/_nav_collection.html.erb +5 -0
  36. data/app/views/lookbook/components/_nav_group.html.erb +17 -0
  37. data/app/views/lookbook/components/_nav_item.html.erb +21 -0
  38. data/app/views/lookbook/components/_nav_preview.html.erb +11 -0
  39. data/app/views/lookbook/components/_param.html.erb +20 -0
  40. data/app/views/lookbook/{workbench → components}/_preview.html.erb +8 -8
  41. data/app/views/lookbook/{app/error.html.erb → error.html.erb} +0 -0
  42. data/app/views/lookbook/index.html.erb +9 -0
  43. data/app/views/lookbook/{workbench/inspector/params → inputs}/_select.html.erb +1 -1
  44. data/app/views/lookbook/{workbench/inspector/params → inputs}/_text.html.erb +1 -1
  45. data/app/views/lookbook/{workbench/inspector/params → inputs}/_textarea.html.erb +1 -1
  46. data/app/views/lookbook/{workbench/inspector/params → inputs}/_toggle.html.erb +1 -1
  47. data/app/views/lookbook/{app/not_found.html.erb → not_found.html.erb} +2 -4
  48. data/app/views/lookbook/panels/_notes.html.erb +25 -0
  49. data/app/views/lookbook/panels/_output.html.erb +18 -0
  50. data/app/views/lookbook/panels/_params.html.erb +17 -0
  51. data/app/views/lookbook/panels/_source.html.erb +20 -0
  52. data/app/views/lookbook/show.html.erb +90 -0
  53. data/lib/lookbook/code_formatter.rb +20 -0
  54. data/lib/lookbook/engine.rb +4 -1
  55. data/lib/lookbook/lang.rb +10 -5
  56. data/lib/lookbook/preview_controller.rb +1 -1
  57. data/lib/lookbook/preview_group.rb +5 -1
  58. data/lib/lookbook/version.rb +1 -1
  59. data/lib/lookbook.rb +1 -0
  60. data/public/lookbook-assets/css/app.css +2 -0
  61. data/public/lookbook-assets/css/app.css.map +1 -0
  62. data/public/lookbook-assets/js/app.js +2 -0
  63. data/public/lookbook-assets/js/app.js.map +1 -0
  64. metadata +54 -43
  65. data/app/assets/lookbook/js/nav/leaf.js +0 -20
  66. data/app/assets/lookbook/js/nav.js +0 -38
  67. data/app/assets/lookbook/js/page.js +0 -38
  68. data/app/assets/lookbook/js/utils/clipboard.js +0 -13
  69. data/app/assets/lookbook/js/utils/morph.js +0 -19
  70. data/app/assets/lookbook/js/utils/screen.js +0 -44
  71. data/app/assets/lookbook/js/utils/size_observer.js +0 -16
  72. data/app/assets/lookbook/js/utils/split.js +0 -26
  73. data/app/assets/lookbook/js/workbench/inspector.js +0 -11
  74. data/app/assets/lookbook/js/workbench.js +0 -14
  75. data/app/views/lookbook/app/index.html.erb +0 -11
  76. data/app/views/lookbook/app/show.html.erb +0 -1
  77. data/app/views/lookbook/layouts/app.html.erb +0 -41
  78. data/app/views/lookbook/nav/_collection.html.erb +0 -5
  79. data/app/views/lookbook/nav/_leaf.html.erb +0 -22
  80. data/app/views/lookbook/nav/_node.html.erb +0 -19
  81. data/app/views/lookbook/nav/_preview.html.erb +0 -11
  82. data/app/views/lookbook/preview/group.html.erb +0 -8
  83. data/app/views/lookbook/shared/_sidebar.html.erb +0 -45
  84. data/app/views/lookbook/shared/_workbench.html.erb +0 -12
  85. data/app/views/lookbook/workbench/_header.html.erb +0 -39
  86. data/app/views/lookbook/workbench/_inspector.html.erb +0 -38
  87. data/app/views/lookbook/workbench/inspector/_code.html.erb +0 -3
  88. data/app/views/lookbook/workbench/inspector/_notes.html.erb +0 -24
  89. data/app/views/lookbook/workbench/inspector/_params.html.erb +0 -28
  90. data/app/views/lookbook/workbench/inspector/_plain.html.erb +0 -3
  91. data/public/lookbook-assets/app.css +0 -2626
  92. data/public/lookbook-assets/app.js +0 -8718
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 93eda55ac8a014e5027a7a1176653a8ecbf9f1b5a95b26820c68ef93f2402269
4
- data.tar.gz: c5a4dde94d4ce0c84298dfe5d8592d3ccaf887fe56fa21a9cb0bbc78b797604f
3
+ metadata.gz: ce922c11cf8df5a1161c555189786265e51e29881c5a5e0948153fa65e855a50
4
+ data.tar.gz: 38fe97d9e04c6505ebc8e1b8bc877fe761db215b525117b42a044cadf7b2eb50
5
5
  SHA512:
6
- metadata.gz: 704265eb0b3c0b15417b47446ac900f14ca3bf746f9bbbabbbeb563eefe672f907d01ebbe5ab70d77633235d228ca509738826d674035528b12a0eb96dfcfa17
7
- data.tar.gz: 562c86882d1a2da3eb06b660006dc3d37223c80273d9aaaacafb9a85ee8a009081eecd1acfd8d451e850d34b4055400b9d9e8e5d452f7dcc66c2428a3928db7d
6
+ metadata.gz: d319e159fc2b87e710532dbd6c426360f2a6173e174d3e0eac05c677bdfd945cf0c5a391c426a8f987cb7539797aa10241e45cdddd55048f25af84689d0af9b2
7
+ data.tar.gz: 80a217bf6303a778676872bd9d6c1412a3811323903031d491e945c0788ebba20cc2ccbb059d011e823b80d74b5342994c9b42f7590fd4fbfd305166b187d345
@@ -56,15 +56,65 @@
56
56
  }
57
57
  }
58
58
 
59
- @layer utilities {
60
- .h-fill {
61
- height: fill-available;
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;
62
92
  }
63
93
 
64
- .min-h-fill {
65
- min-height: fill-available;
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;
66
101
  }
67
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 {
68
118
  .form-input {
69
119
  @apply border-gray-300 text-gray-700 focus:ring-indigo-300 focus:border-indigo-300 rounded-sm text-sm w-full;
70
120
  }
@@ -1,66 +1,54 @@
1
1
  import { install } from "@github/hotkey";
2
2
  import Alpine from "alpinejs";
3
- import Fern from "@ryangjchandler/fern";
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 param from "./workbench/param";
13
- import nav from "./nav";
14
- import navNode from "./nav/node";
15
- import navLeaf from "./nav/leaf";
16
- import sizeObserver from "./utils/size_observer";
17
- import reloader from "./utils/reloader";
18
- import clipboard from "./utils/clipboard";
19
-
20
- window.Alpine = Alpine;
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";
21
24
 
22
25
  // Plugins
23
26
 
24
- Alpine.plugin(Fern);
25
- Alpine.plugin(AlpineTooltip);
26
- Alpine.plugin(AlpineClipboard);
27
- Alpine.plugin(Screen);
27
+ Alpine.plugin(Persist);
28
+ Alpine.plugin(Morph);
29
+ Alpine.plugin(Tooltip);
28
30
 
29
31
  // Stores
30
32
 
31
- Alpine.store("page", {
32
- reflowing: false,
33
- doc: window.document,
34
- });
35
-
36
- Alpine.persistedStore("nav", {
37
- width: 280,
38
- filter: "",
39
- open: {},
40
- });
41
-
42
- Alpine.persistedStore("inspector", {
43
- height: 200,
44
- active: "source",
45
- });
46
-
47
- Alpine.persistedStore("preview", {
48
- width: "100%",
49
- });
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));
50
38
 
51
- // Components & utils
39
+ // Components
52
40
 
53
41
  Alpine.data("page", page);
54
- Alpine.data("nav", nav);
55
- Alpine.data("navNode", navNode);
56
- Alpine.data("navLeaf", navLeaf);
57
- Alpine.data("workbench", workbench);
58
- Alpine.data("preview", preview);
42
+ Alpine.data("splitter", splitter);
43
+ Alpine.data("previewWindow", previewWindow);
44
+ Alpine.data("copy", copy);
59
45
  Alpine.data("inspector", inspector);
46
+ Alpine.data("filter", filter);
60
47
  Alpine.data("param", param);
61
- Alpine.data("clipboard", clipboard);
62
- Alpine.data("sizeObserver", sizeObserver);
63
- Alpine.data("split", split);
48
+ Alpine.data("sizes", sizes);
49
+ Alpine.data("nav", nav);
50
+ Alpine.data("navItem", navItem);
51
+ Alpine.data("navGroup", navGroup);
64
52
 
65
53
  // Init
66
54
 
@@ -68,9 +56,5 @@ for (const el of document.querySelectorAll("[data-hotkey]")) {
68
56
  install(el);
69
57
  }
70
58
 
71
- if (window.SOCKET_PATH) {
72
- reloader(window.SOCKET_PATH).start();
73
- }
74
-
75
59
  window.Alpine = Alpine;
76
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
+ }
@@ -1,13 +1,17 @@
1
- export default function navNode() {
1
+ import { getAlpineData } from "../lib/utils";
2
+
3
+ export default function navGroup() {
2
4
  return {
3
- id: null,
4
- hidden: true,
5
+ hidden: false,
5
6
  children: [],
6
- init() {
7
- this.id = this.$el.id;
7
+ get id() {
8
+ return this.$root.id;
8
9
  },
9
- open() {
10
- return this.$store.nav.open[this.id];
10
+ get open() {
11
+ return this.$store.nav.isOpen(this.id);
12
+ },
13
+ toggle() {
14
+ this.$store.nav.toggle(this.id);
11
15
  },
12
16
  getChildren() {
13
17
  return this.$refs.items
@@ -15,29 +19,26 @@ export default function navNode() {
15
19
  : [];
16
20
  },
17
21
  navigateToFirstChild() {
18
- if (this.open()) {
22
+ if (this.open) {
19
23
  const child = this.firstVisibleChild();
20
24
  if (child) {
21
25
  const link = child.querySelector(":scope > a.nav-link");
22
26
  if (link) {
23
- this.navigate(link.getAttribute("href"));
27
+ this.setLocation(link.getAttribute("href"));
24
28
  }
25
29
  }
26
30
  }
27
31
  },
28
- filter() {
32
+ filter(text) {
29
33
  this.hidden = true;
30
34
  this.getChildren().forEach((child) => {
31
- const data = child._x_dataStack[0];
32
- data.filter();
35
+ const data = getAlpineData(child);
36
+ data.filter(text);
33
37
  if (!data.hidden) {
34
38
  this.hidden = false;
35
39
  }
36
40
  });
37
41
  },
38
- toggle() {
39
- this.$store.nav.open[this.id] = !this.$store.nav.open[this.id];
40
- },
41
42
  firstVisibleChild() {
42
43
  return this.getChildren().find((child) => {
43
44
  return child._x_dataStack
@@ -0,0 +1,26 @@
1
+ export default function navItem(matchers) {
2
+ return {
3
+ hidden: false,
4
+ get id() {
5
+ return this.$root.id;
6
+ },
7
+ get path() {
8
+ return this.$root.getAttribute("data-path");
9
+ },
10
+ get active() {
11
+ return this.$store.nav.active === this.id;
12
+ },
13
+ navigate() {
14
+ this.setLocation(this.path);
15
+ this.$store.sidebar.open = false;
16
+ },
17
+ filter(text) {
18
+ if (text.length) {
19
+ const matched = matchers.map((m) => m.includes(text));
20
+ this.hidden = !matched.filter((m) => m).length;
21
+ } else {
22
+ this.hidden = false;
23
+ }
24
+ },
25
+ };
26
+ }
@@ -0,0 +1,35 @@
1
+ import { getAlpineData } from "../lib/utils";
2
+
3
+ export default function nav() {
4
+ return {
5
+ empty: false,
6
+ init() {
7
+ this.$watch("$store.filter.text", () => this.filter());
8
+ this.$nextTick(() => {
9
+ this.setActive();
10
+ this.filter();
11
+ });
12
+ },
13
+ filter() {
14
+ this.empty = true;
15
+ this.getChildren().forEach((child) => {
16
+ const data = getAlpineData(child);
17
+ data.filter(this.$store.filter.text);
18
+ if (!data.hidden) {
19
+ this.empty = false;
20
+ }
21
+ });
22
+ },
23
+ getChildren() {
24
+ return this.$refs.items
25
+ ? Array.from(this.$refs.items.querySelectorAll(":scope > li"))
26
+ : [];
27
+ },
28
+ setActive() {
29
+ const target = this.$el.querySelector(
30
+ `[data-path="${window.location.pathname}"]`
31
+ );
32
+ this.$store.nav.active = target ? target.id : "";
33
+ },
34
+ };
35
+ }
@@ -0,0 +1,33 @@
1
+ import createSocket from "../lib/socket";
2
+
3
+ export default function page() {
4
+ return {
5
+ init() {
6
+ const socket = createSocket(window.SOCKET_PATH);
7
+ socket.addListener("Lookbook::ReloadChannel", () => this.refresh());
8
+ },
9
+ async update() {
10
+ const response = await fetch(window.document.location);
11
+ if (!response.ok) return window.location.reload();
12
+ const html = await response.text();
13
+ this.morph(new DOMParser().parseFromString(html, "text/html"));
14
+ },
15
+ setLocation(loc) {
16
+ const path = loc instanceof Event ? loc.currentTarget.href : loc;
17
+ history.pushState({}, null, path);
18
+ this.$dispatch("popstate");
19
+ },
20
+ refresh() {
21
+ this.$dispatch("popstate");
22
+ },
23
+ morph(dom) {
24
+ 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
+ });
30
+ this.$dispatch("page:morphed");
31
+ },
32
+ };
33
+ }
@@ -1,16 +1,15 @@
1
1
  export default function param() {
2
2
  return {
3
- focused: false,
4
3
  setFocus() {
5
- if (this.focused && this.$el.focus) {
6
- this.$el.focus();
4
+ if (this.$refs.input) {
5
+ setTimeout(() => this.$refs.input.focus(), 0);
7
6
  }
8
7
  },
9
8
  update(name, value) {
10
9
  const searchParams = new URLSearchParams(window.location.search);
11
10
  searchParams.set(name, value);
12
11
  const path = location.href.replace(location.search, "");
13
- this.navigateTo(`${path}?${searchParams.toString()}`);
12
+ this.setLocation(`${path}?${searchParams.toString()}`);
14
13
  },
15
14
  validate() {
16
15
  return this.$el.reportValidity ? this.$el.reportValidity() : true;
@@ -1,33 +1,32 @@
1
1
  export default function preview() {
2
- const app = Alpine.store("page");
3
- const preview = Alpine.store("preview");
4
2
  return {
5
- init() {
6
- this.root = this.$el;
7
- },
8
3
  onResize(e) {
9
4
  const size =
10
5
  this.resizeStartSize - (this.resizeStartPosition - e.pageX) * 2;
11
- const parentSize = this.root.parentElement.clientWidth;
6
+ const parentSize = this.$root.parentElement.clientWidth;
12
7
  const percentSize = (Math.round(size) / parentSize) * 100;
13
8
  const minWidth = (300 / parentSize) * 100;
14
- preview.width = `${Math.min(Math.max(percentSize, minWidth), 100)}%`;
9
+ this.$store.inspector.preview.width = `${Math.min(
10
+ Math.max(percentSize, minWidth),
11
+ 100
12
+ )}%`;
15
13
  },
16
14
  onResizeStart(e) {
17
- app.reflowing = true;
15
+ this.$store.layout.reflowing = true;
18
16
  this.onResize = this.onResize.bind(this);
19
17
  this.onResizeEnd = this.onResizeEnd.bind(this);
20
18
  this.resizeStartPosition = e.pageX;
21
- this.resizeStartSize = this.root.clientWidth;
19
+ this.resizeStartSize = this.$root.clientWidth;
22
20
  window.addEventListener("pointermove", this.onResize);
23
21
  window.addEventListener("pointerup", this.onResizeEnd);
24
22
  },
25
23
  onResizeEnd() {
26
24
  window.removeEventListener("pointermove", this.onResize);
27
25
  window.removeEventListener("pointerup", this.onResizeEnd);
28
- app.reflowing = false;
26
+ this.$store.layout.reflowing = false;
29
27
  },
30
28
  toggleFullWidth() {
29
+ const preview = this.$store.inspector.preview;
31
30
  if (preview.width === "100%" && preview.lastWidth) {
32
31
  preview.width = preview.lastWidth;
33
32
  } else {
@@ -0,0 +1,3 @@
1
+ export default function sidebar() {
2
+ return {};
3
+ }
@@ -0,0 +1,16 @@
1
+ export default function sizeObserver() {
2
+ return {
3
+ width: 0,
4
+ height: 0,
5
+ init() {
6
+ const ro = new ResizeObserver((entries) => {
7
+ const rect = entries[0].contentRect;
8
+ this.width = Math.round(rect.width);
9
+ this.height = Math.round(rect.height);
10
+ });
11
+ ro.observe(this.$el);
12
+ this.width = Math.round(this.$el.clientWidth);
13
+ this.height = Math.round(this.$el.clientHeight);
14
+ },
15
+ };
16
+ }
@@ -0,0 +1,25 @@
1
+ import Split from "split-grid";
2
+
3
+ export default function splitter(direction, props = {}) {
4
+ return {
5
+ splits: [],
6
+ init() {
7
+ const type = `${direction === "vertical" ? "column" : "row"}Gutters`;
8
+ const element = this.$el;
9
+ Split({
10
+ [type]: [{ track: 1, element }],
11
+ minSize: props.minSize || 0,
12
+ writeStyle() {},
13
+ onDrag: (dir, track, style) => {
14
+ this.splits = style.split(" ").map((num) => parseInt(num));
15
+ },
16
+ onDragStart: () => {
17
+ this.$store.layout.reflowing = true;
18
+ },
19
+ onDragEnd: () => {
20
+ this.$store.layout.reflowing = false;
21
+ },
22
+ });
23
+ },
24
+ };
25
+ }
@@ -0,0 +1,14 @@
1
+ export default {
2
+ desktopWidth: 768,
3
+ sidebar: {
4
+ defaultWidth: 280,
5
+ minWidth: 200,
6
+ maxWidth: 500,
7
+ },
8
+ inspector: {
9
+ tabs: {
10
+ default: "source",
11
+ defaultHeight: 200,
12
+ },
13
+ },
14
+ };
@@ -1,21 +1,16 @@
1
1
  import { createConsumer } from "@rails/actioncable";
2
2
  import debounce from "debounce";
3
3
 
4
- export default function (endpoint) {
4
+ export default function socket(endpoint) {
5
5
  const uid = (Date.now() + ((Math.random() * 100) | 0)).toString();
6
6
  const consumer = createConsumer(`${endpoint}?uid=${uid}`);
7
-
8
7
  return {
9
- uid,
10
- consumer,
11
- start() {
12
- const received = debounce(() => {
13
- console.log("Lookbook files changed");
14
- document.dispatchEvent(new CustomEvent("refresh"));
15
- }, 300);
16
-
17
- consumer.subscriptions.create("Lookbook::ReloadChannel", {
18
- received,
8
+ addListener(channel, callback) {
9
+ consumer.subscriptions.create(channel, {
10
+ received: debounce((data) => {
11
+ console.log("Lookbook files changed");
12
+ callback(data);
13
+ }, 300),
19
14
  connected() {
20
15
  console.log("Lookbook websocket connected");
21
16
  },
@@ -0,0 +1,21 @@
1
+ import Split from "split-grid";
2
+
3
+ export default function (element, props) {
4
+ Split({
5
+ [`${props.direction === "vertical" ? "row" : "column"}Gutters`]: [
6
+ { track: 1, element },
7
+ ],
8
+ minSize: props.minSize,
9
+ writeStyle() {},
10
+ onDrag(dir, track, style) {
11
+ const splits = style.split(" ").map((num) => parseInt(num));
12
+ props.onDrag(splits);
13
+ },
14
+ // onDragStart() {
15
+ // this.reflowing = true;
16
+ // },
17
+ // onDragEnd() {
18
+ // this.reflowing = false;
19
+ // },
20
+ });
21
+ }
@@ -0,0 +1,3 @@
1
+ export function getAlpineData(el) {
2
+ return el._x_dataStack[0];
3
+ }
@@ -0,0 +1,11 @@
1
+ export default function createFilterStore(Alpine) {
2
+ return {
3
+ raw: Alpine.$persist("").as("filter-text"),
4
+ get text() {
5
+ return this.raw.replace(/\s/g, "").toLowerCase();
6
+ },
7
+ get active() {
8
+ return this.text.length > 0;
9
+ },
10
+ };
11
+ }
@@ -0,0 +1,17 @@
1
+ import config from "../config";
2
+
3
+ export default function createInspectorStore(Alpine) {
4
+ const { tabs } = config.inspector;
5
+ return {
6
+ panels: {
7
+ active: Alpine.$persist(tabs.default).as("inspector-panel-active"),
8
+ height: Alpine.$persist(tabs.defaultHeight).as("inspector-height"),
9
+ },
10
+ preview: {
11
+ width: Alpine.$persist("100%").as("preview-width"),
12
+ height: Alpine.$persist("100%").as("preview-height"),
13
+ source: Alpine.$persist(false).as("preview-source"),
14
+ lastWidth: null,
15
+ },
16
+ };
17
+ }
@@ -0,0 +1,12 @@
1
+ import config from "../config";
2
+
3
+ export default function createLayoutStore() {
4
+ return {
5
+ init() {
6
+ this.desktop = window.innerWidth >= config.desktopWidth;
7
+ },
8
+ reflowing: false,
9
+ desktop: true,
10
+ desktopWidth: config.desktopWidth,
11
+ };
12
+ }
@@ -0,0 +1,21 @@
1
+ export default function createNavStore(Alpine) {
2
+ return {
3
+ open: Alpine.$persist([]).as("nav-open"),
4
+ active: Alpine.$persist(null).as("nav-active"),
5
+ isOpen(id) {
6
+ return this.open.includes(id);
7
+ },
8
+ setOpen(id) {
9
+ this.open.push(id);
10
+ },
11
+ setClosed(id) {
12
+ const index = this.open.indexOf(id);
13
+ if (index > -1) {
14
+ this.open.splice(index, 1);
15
+ }
16
+ },
17
+ toggle(id) {
18
+ this.isOpen(id) ? this.setClosed(id) : this.setOpen(id);
19
+ },
20
+ };
21
+ }