lookbook 0.9.3 → 1.0.0.beta.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (207) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +43 -867
  3. data/app/assets/lookbook/css/lookbook.css +55 -0
  4. data/app/assets/lookbook/css/themes/blue.css +42 -0
  5. data/app/assets/lookbook/css/themes/indigo.css +42 -0
  6. data/app/assets/lookbook/css/themes/zinc.css +42 -0
  7. data/app/assets/lookbook/css/{tooltip_theme.css → tooltip.css} +14 -8
  8. data/app/assets/lookbook/js/app.js +64 -63
  9. data/app/assets/lookbook/js/components/clipboard.js +47 -0
  10. data/app/assets/lookbook/js/components/tooltip.js +30 -0
  11. data/app/assets/lookbook/js/config.js +7 -4
  12. data/app/assets/lookbook/js/helpers/build.js +22 -0
  13. data/app/assets/lookbook/js/helpers/dom.js +45 -0
  14. data/app/assets/lookbook/js/helpers/layout.js +21 -0
  15. data/app/assets/lookbook/js/helpers/request.js +16 -0
  16. data/app/assets/lookbook/js/helpers/string.js +11 -0
  17. data/app/assets/lookbook/js/lib/socket.js +4 -3
  18. data/app/assets/lookbook/js/lib/tippy.js +8 -0
  19. data/app/assets/lookbook/js/lookbook.js +61 -0
  20. data/app/assets/lookbook/js/plugins/logger.js +39 -0
  21. data/app/assets/lookbook/js/stores/filter.js +2 -2
  22. data/app/assets/lookbook/js/stores/inspector.js +22 -16
  23. data/app/assets/lookbook/js/stores/layout.js +101 -5
  24. data/app/assets/lookbook/js/stores/nav.js +17 -16
  25. data/app/assets/lookbook/js/stores/pages.js +4 -2
  26. data/app/assets/lookbook/js/stores/settings.js +7 -0
  27. data/app/assets/lookbook/js/stores/workbench.js +29 -0
  28. data/app/components/lookbook/button/component.html.erb +28 -0
  29. data/app/components/lookbook/button/component.js +55 -0
  30. data/app/components/lookbook/button/component.rb +39 -0
  31. data/app/components/lookbook/button_group/component.html.erb +3 -0
  32. data/app/components/lookbook/button_group/component.rb +18 -0
  33. data/app/components/lookbook/code/component.css +57 -0
  34. data/app/components/lookbook/code/component.html.erb +10 -0
  35. data/app/components/lookbook/code/component.js +3 -0
  36. data/app/components/lookbook/code/component.rb +56 -0
  37. data/app/components/lookbook/code/highlight_github_light.css +217 -0
  38. data/app/components/lookbook/component.rb +41 -0
  39. data/app/components/lookbook/copy_button/component.html.erb +11 -0
  40. data/app/components/lookbook/copy_button/component.js +16 -0
  41. data/app/components/lookbook/copy_button/component.rb +23 -0
  42. data/app/components/lookbook/dimensions_display/component.html.erb +10 -0
  43. data/app/components/lookbook/dimensions_display/component.js +30 -0
  44. data/app/components/lookbook/dimensions_display/component.rb +18 -0
  45. data/app/components/lookbook/embed/component.html.erb +50 -0
  46. data/app/components/lookbook/embed/component.js +39 -0
  47. data/app/components/lookbook/embed/component.rb +22 -0
  48. data/app/components/lookbook/filter/component.html.erb +17 -0
  49. data/app/components/lookbook/filter/component.js +21 -0
  50. data/app/components/lookbook/filter/component.rb +15 -0
  51. data/app/components/lookbook/header/component.html.erb +79 -0
  52. data/app/components/lookbook/header/component.rb +9 -0
  53. data/app/components/lookbook/icon/component.css +11 -0
  54. data/app/components/lookbook/icon/component.html.erb +5 -0
  55. data/app/components/lookbook/icon/component.js +5 -0
  56. data/app/components/lookbook/icon/component.rb +23 -0
  57. data/app/components/lookbook/nav/component.html.erb +33 -0
  58. data/app/components/lookbook/nav/component.js +52 -0
  59. data/app/components/lookbook/nav/component.rb +37 -0
  60. data/app/components/lookbook/nav/item/component.html.erb +23 -0
  61. data/app/components/lookbook/nav/item/component.js +66 -0
  62. data/app/components/lookbook/nav/item/component.rb +84 -0
  63. data/app/components/lookbook/params_editor/component.html.erb +3 -0
  64. data/app/components/lookbook/params_editor/component.js +12 -0
  65. data/app/components/lookbook/params_editor/component.rb +11 -0
  66. data/app/components/lookbook/params_editor/field/component.html.erb +50 -0
  67. data/app/components/lookbook/params_editor/field/component.js +36 -0
  68. data/app/components/lookbook/params_editor/field/component.rb +41 -0
  69. data/app/components/lookbook/prose/component.css +12 -0
  70. data/app/components/lookbook/prose/component.html.erb +3 -0
  71. data/app/components/lookbook/prose/component.rb +26 -0
  72. data/app/components/lookbook/split_layout/component.html.erb +13 -0
  73. data/app/components/lookbook/split_layout/component.js +151 -0
  74. data/app/components/lookbook/split_layout/component.rb +11 -0
  75. data/app/components/lookbook/tabbed_content/component.html.erb +5 -0
  76. data/app/components/lookbook/tabbed_content/component.js +21 -0
  77. data/app/components/lookbook/tabbed_content/component.rb +20 -0
  78. data/app/components/lookbook/tabbed_content/section/component.html.erb +8 -0
  79. data/app/components/lookbook/tabbed_content/section/component.rb +9 -0
  80. data/app/components/lookbook/tabs/component.css +8 -0
  81. data/app/components/lookbook/tabs/component.html.erb +14 -0
  82. data/app/components/lookbook/tabs/component.js +107 -0
  83. data/app/components/lookbook/tabs/component.rb +30 -0
  84. data/app/components/lookbook/tabs/dropdown_tab/component.html.erb +14 -0
  85. data/app/components/lookbook/tabs/dropdown_tab/component.rb +16 -0
  86. data/app/components/lookbook/tabs/tab/component.html.erb +18 -0
  87. data/app/components/lookbook/tabs/tab/component.rb +16 -0
  88. data/app/components/lookbook/tag_component.rb +29 -0
  89. data/app/components/lookbook/toolbar/component.css +16 -0
  90. data/app/components/lookbook/toolbar/component.html.erb +5 -0
  91. data/app/components/lookbook/toolbar/component.rb +26 -0
  92. data/app/components/lookbook/viewport/component.css +11 -0
  93. data/app/components/lookbook/viewport/component.html.erb +57 -0
  94. data/app/{assets/lookbook/js/components/preview-window.js → components/lookbook/viewport/component.js} +57 -14
  95. data/app/components/lookbook/viewport/component.rb +21 -0
  96. data/app/controllers/lookbook/application_controller.rb +16 -5
  97. data/app/controllers/lookbook/pages_controller.rb +18 -10
  98. data/app/controllers/lookbook/previews_controller.rb +62 -25
  99. data/app/helpers/lookbook/application_helper.rb +7 -3
  100. data/app/helpers/lookbook/component_helper.rb +22 -10
  101. data/app/helpers/lookbook/output_helper.rb +8 -4
  102. data/app/helpers/lookbook/page_helper.rb +13 -21
  103. data/app/views/layouts/lookbook/application.html.erb +76 -28
  104. data/app/views/layouts/lookbook/inspector.html.erb +7 -0
  105. data/app/views/layouts/lookbook/page.html.erb +53 -0
  106. data/app/views/layouts/lookbook/shell.html.erb +64 -0
  107. data/app/views/layouts/lookbook/skeleton.html.erb +27 -10
  108. data/app/views/layouts/lookbook/standalone.html.erb +5 -0
  109. data/app/views/lookbook/404.html.erb +15 -0
  110. data/app/views/lookbook/error.html.erb +34 -34
  111. data/app/views/lookbook/index.html.erb +11 -6
  112. data/app/views/lookbook/pages/show.html.erb +29 -93
  113. data/app/views/{layouts/lookbook → lookbook}/preview.html.erb +3 -5
  114. data/app/views/lookbook/previews/panels/_notes.html.erb +19 -25
  115. data/app/views/lookbook/previews/panels/_output.html.erb +7 -18
  116. data/app/views/lookbook/previews/panels/_params.html.erb +13 -15
  117. data/app/views/lookbook/previews/panels/_preview.html.erb +6 -52
  118. data/app/views/lookbook/previews/panels/_source.html.erb +7 -16
  119. data/app/views/lookbook/previews/show.html.erb +130 -24
  120. data/config/routes.rb +7 -7
  121. data/lib/lookbook/code_formatter.rb +37 -13
  122. data/lib/lookbook/collection.rb +19 -16
  123. data/lib/lookbook/config.rb +125 -0
  124. data/lib/lookbook/engine.rb +69 -67
  125. data/lib/lookbook/entity.rb +47 -0
  126. data/lib/lookbook/error.rb +1 -2
  127. data/lib/lookbook/features.rb +1 -1
  128. data/lib/lookbook/markdown.rb +3 -5
  129. data/lib/lookbook/page.rb +26 -43
  130. data/lib/lookbook/page_collection.rb +8 -0
  131. data/lib/lookbook/params.rb +14 -3
  132. data/lib/lookbook/parser.rb +4 -0
  133. data/lib/lookbook/preview.rb +16 -7
  134. data/lib/lookbook/preview_collection.rb +8 -0
  135. data/lib/lookbook/preview_controller.rb +6 -2
  136. data/lib/lookbook/preview_example.rb +5 -6
  137. data/lib/lookbook/preview_group.rb +4 -9
  138. data/lib/lookbook/{code_inspector.rb → source_inspector.rb} +2 -2
  139. data/lib/lookbook/theme.rb +22 -0
  140. data/lib/lookbook/utils.rb +11 -3
  141. data/lib/lookbook/version.rb +1 -1
  142. data/lib/lookbook.rb +4 -1
  143. data/lib/tasks/lookbook_tasks.rake +13 -1
  144. data/public/lookbook-assets/css/app.css +2340 -1
  145. data/public/lookbook-assets/css/app.css.map +11 -1
  146. data/public/lookbook-assets/css/lookbook.css +3040 -0
  147. data/public/lookbook-assets/css/lookbook.css.map +1 -0
  148. data/public/lookbook-assets/css/themes/blue.css +44 -0
  149. data/public/lookbook-assets/css/themes/blue.css.map +1 -0
  150. data/public/lookbook-assets/css/themes/indigo.css +44 -0
  151. data/public/lookbook-assets/css/themes/indigo.css.map +1 -0
  152. data/public/lookbook-assets/css/themes/zinc.css +44 -0
  153. data/public/lookbook-assets/css/themes/zinc.css.map +1 -0
  154. data/public/lookbook-assets/js/app.js +10861 -1
  155. data/public/lookbook-assets/js/app.js.map +2571 -1
  156. data/public/lookbook-assets/js/embed.js +895 -1
  157. data/public/lookbook-assets/js/embed.js.map +1 -1
  158. data/public/lookbook-assets/js/lookbook.js +13529 -0
  159. data/public/lookbook-assets/js/lookbook.js.map +1 -0
  160. metadata +128 -116
  161. data/app/assets/lookbook/css/app.css +0 -161
  162. data/app/assets/lookbook/css/code_theme.css +0 -214
  163. data/app/assets/lookbook/js/components/app.js +0 -55
  164. data/app/assets/lookbook/js/components/code.js +0 -5
  165. data/app/assets/lookbook/js/components/copy.js +0 -20
  166. data/app/assets/lookbook/js/components/embed.js +0 -89
  167. data/app/assets/lookbook/js/components/filter.js +0 -35
  168. data/app/assets/lookbook/js/components/inspector.js +0 -66
  169. data/app/assets/lookbook/js/components/nav-group.js +0 -47
  170. data/app/assets/lookbook/js/components/nav-item.js +0 -29
  171. data/app/assets/lookbook/js/components/nav.js +0 -28
  172. data/app/assets/lookbook/js/components/page-tabs.js +0 -9
  173. data/app/assets/lookbook/js/components/page.js +0 -25
  174. data/app/assets/lookbook/js/components/param.js +0 -34
  175. data/app/assets/lookbook/js/components/sidebar.js +0 -18
  176. data/app/assets/lookbook/js/components/sizes.js +0 -16
  177. data/app/assets/lookbook/js/components/splitter.js +0 -25
  178. data/app/assets/lookbook/js/components/tabs.js +0 -52
  179. data/app/assets/lookbook/js/lib/split.js +0 -15
  180. data/app/assets/lookbook/js/stores/sidebar.js +0 -26
  181. data/app/views/layouts/lookbook/basic.html.erb +0 -7
  182. data/app/views/lookbook/components/_branding.html.erb +0 -8
  183. data/app/views/lookbook/components/_code.html.erb +0 -17
  184. data/app/views/lookbook/components/_copy_button.html.erb +0 -11
  185. data/app/views/lookbook/components/_drawer.html.erb +0 -112
  186. data/app/views/lookbook/components/_embed.html.erb +0 -39
  187. data/app/views/lookbook/components/_errors.html.erb +0 -13
  188. data/app/views/lookbook/components/_filter.html.erb +0 -18
  189. data/app/views/lookbook/components/_header.html.erb +0 -6
  190. data/app/views/lookbook/components/_icon.html.erb +0 -5
  191. data/app/views/lookbook/components/_nav.html.erb +0 -16
  192. data/app/views/lookbook/components/_nav_collection.html.erb +0 -5
  193. data/app/views/lookbook/components/_nav_group.html.erb +0 -14
  194. data/app/views/lookbook/components/_nav_item.html.erb +0 -24
  195. data/app/views/lookbook/components/_nav_page.html.erb +0 -22
  196. data/app/views/lookbook/components/_nav_preview.html.erb +0 -13
  197. data/app/views/lookbook/components/_not_found.html.erb +0 -11
  198. data/app/views/lookbook/components/_param.html.erb +0 -21
  199. data/app/views/lookbook/components/_preview.html.erb +0 -77
  200. data/app/views/lookbook/components/_sidebar.html.erb +0 -69
  201. data/app/views/lookbook/pages/not_found.html.erb +0 -15
  202. data/app/views/lookbook/previews/error.html.erb +0 -1
  203. data/app/views/lookbook/previews/inputs/_select.html.erb +0 -7
  204. data/app/views/lookbook/previews/inputs/_text.html.erb +0 -8
  205. data/app/views/lookbook/previews/inputs/_textarea.html.erb +0 -8
  206. data/app/views/lookbook/previews/inputs/_toggle.html.erb +0 -13
  207. data/app/views/lookbook/previews/not_found.html.erb +0 -23
@@ -0,0 +1,33 @@
1
+ <%= render_component_tag class: "flex flex-col overflow-hidden h-full",
2
+ "@filter:change.stop": "filter($event.detail.text)" do %>
3
+
4
+ <% if label.present? %>
5
+ <%= render_component :toolbar do |toolbar| %>
6
+ <% toolbar.section padded: true do %>
7
+ <h4 class="pt-1"><%= label %></h4>
8
+ <% end %>
9
+ <% end %>
10
+ <% end %>
11
+
12
+ <% if filter && items.any? %>
13
+ <div class="p-2 pb-0">
14
+ <%= filter %>
15
+ </div>
16
+ <% end %>
17
+
18
+ <div class="overflow-auto">
19
+ <% if items.any? %>
20
+ <ul class="py-2" x-ref="items" x-show="!empty" x-cloak>
21
+ <%= safe_join(items) %>
22
+ </ul>
23
+ <div class="p-4 text-center" x-show="empty" x-cloak>
24
+ <h4 class="opacity-50 italic">No matching <%= label.downcase %>.</h4>
25
+ </div>
26
+ <% else %>
27
+ <div class="p-4 text-center">
28
+ <h4 class="opacity-50 italic">No <%= label.downcase %> available.</h4>
29
+ </div>
30
+ <% end %>
31
+ </div>
32
+
33
+ <% end %>
@@ -0,0 +1,52 @@
1
+ export default function navComponent(store) {
2
+ return {
3
+ empty: false,
4
+
5
+ children: [],
6
+
7
+ init() {
8
+ this.children = this.$refs.items
9
+ ? Array.from(this.$refs.items.children)
10
+ : [];
11
+ },
12
+
13
+ isOpen(id) {
14
+ return store.open.includes(id);
15
+ },
16
+
17
+ setOpen(id) {
18
+ store.open.push(id);
19
+ },
20
+
21
+ setClosed(id) {
22
+ const index = store.open.indexOf(id);
23
+ if (index > -1) {
24
+ store.open.splice(index, 1);
25
+ }
26
+ },
27
+
28
+ toggleOpen(id) {
29
+ this.isOpen(id) ? this.setClosed(id) : this.setOpen(id);
30
+ },
31
+
32
+ async filter(text) {
33
+ this.debug(`Filter text: ${text}`);
34
+
35
+ await this.$nextTick();
36
+ const filteredStates = await Promise.all(
37
+ this.children.map(async (child) => {
38
+ const data = Alpine.$data(child);
39
+ await data.filter(text);
40
+ return data.filteredOut;
41
+ })
42
+ );
43
+
44
+ const matchedChildCount = filteredStates.filter((s) => !s).length;
45
+ this.empty = matchedChildCount === 0;
46
+
47
+ this.debug(
48
+ `Children matching filter: ${matchedChildCount}/${this.children.length}`
49
+ );
50
+ },
51
+ };
52
+ }
@@ -0,0 +1,37 @@
1
+ module Lookbook
2
+ class Nav::Component < Lookbook::Component
3
+ renders_one :filter, Lookbook::Filter::Component
4
+
5
+ def initialize(
6
+ collection:,
7
+ label: nil,
8
+ collapse_singles: false,
9
+ **attrs
10
+ )
11
+ @collection = collection.as_tree
12
+ @label = label
13
+ @item_args = {
14
+ collapse_singles: collapse_singles
15
+ }
16
+ super(**attrs)
17
+ end
18
+
19
+ def label
20
+ @label || @collection.label
21
+ end
22
+
23
+ def items
24
+ @collection.non_empty_items.map do |item|
25
+ render Lookbook::Nav::Item::Component.new item,
26
+ depth: 1,
27
+ **@item_args
28
+ end
29
+ end
30
+
31
+ protected
32
+
33
+ def alpine_component
34
+ "navComponent"
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,23 @@
1
+ <%= render_component_tag :li, id: @item.id, class: "list-none", "x-show": "!filteredOut", cloak: true do %>
2
+
3
+ <%= render_tag href.present? ? :a : :div,
4
+ href: href,
5
+ class: "flex items-center py-1 select-none cursor-pointer text-lookbook-nav-text hover:bg-lookbook-nav-item-hover",
6
+ style: "padding-left: #{left_pad}px",
7
+ x_bind: "bindings.#{href.present? ? "link" : "toggle"}" do %>
8
+ <div class="relative flex items-center">
9
+ <%= render_component :icon, name: nil,
10
+ size: 3,
11
+ class: "mr-1 text-lookbook-nav-toggle absolute -left-4",
12
+ x_effect: "iconName = open ? 'chevron-down' : 'chevron-right'" if children? %>
13
+ <%= render_component :icon, name: nav_icon(@item), size: 3.5, class: "mr-1.5 text-lookbook-nav-icon" %>
14
+ <span><%= label %></span>
15
+ </div>
16
+ <% end %>
17
+
18
+ <% if children? %>
19
+ <ul x-ref="items" x-show="open" x-cloak>
20
+ <%= safe_join(children) %>
21
+ </ul>
22
+ <% end %>
23
+ <% end %>
@@ -0,0 +1,66 @@
1
+ export default function navItemComponent({ id, matchers }) {
2
+ return {
3
+ filteredOut: false,
4
+
5
+ get open() {
6
+ return this.isCollection && this.isOpen(id);
7
+ },
8
+
9
+ get active() {
10
+ if (this.$refs.link) {
11
+ return (
12
+ this.location &&
13
+ this.location.pathname === this.$refs.link.getAttribute("href")
14
+ );
15
+ }
16
+ return false;
17
+ },
18
+
19
+ get children() {
20
+ return this.$refs.items ? Array.from(this.$refs.items.children) : [];
21
+ },
22
+
23
+ get isCollection() {
24
+ return !this.$refs.link;
25
+ },
26
+
27
+ toggle() {
28
+ this.toggleOpen(id);
29
+ },
30
+
31
+ async filter(text) {
32
+ if (this.isCollection) {
33
+ this.filteredOut = true;
34
+ this.children.forEach(async (child) => {
35
+ const data = Alpine.$data(child);
36
+ await data.filter(text);
37
+ if (!data.filteredOut) {
38
+ this.filteredOut = false;
39
+ }
40
+ });
41
+ } else {
42
+ this.filteredOut = !this.match(text);
43
+ }
44
+ return this;
45
+ },
46
+
47
+ match(text) {
48
+ if (text.length) {
49
+ const matched = (matchers || []).map((m) => m.includes(text));
50
+ return matched.filter((m) => m).length;
51
+ }
52
+ return true;
53
+ },
54
+
55
+ bindings: {
56
+ toggle: {
57
+ ["@click.stop"]: "toggle",
58
+ ["x-ref"]: "toggle",
59
+ },
60
+ link: {
61
+ [":class"]: "{'!bg-lookbook-nav-item-active':active}",
62
+ ["x-ref"]: "link",
63
+ },
64
+ },
65
+ };
66
+ }
@@ -0,0 +1,84 @@
1
+ module Lookbook
2
+ class Nav::Item::Component < Lookbook::Component
3
+ ICONS = {
4
+ page: :file,
5
+ page_collection: :folder,
6
+ preview_collection: :folder,
7
+ preview: :layers,
8
+ example: :eye,
9
+ group: :eye,
10
+ collection: :folder
11
+ }.freeze
12
+
13
+ delegate :label, to: :@item
14
+
15
+ def initialize(
16
+ item,
17
+ depth: 1,
18
+ collapse_singles: false,
19
+ **html_attrs
20
+ )
21
+ @item = item
22
+ @depth = depth
23
+ @collapse_singles = collapse_singles
24
+ super(**html_attrs)
25
+ end
26
+
27
+ def left_pad
28
+ ((@depth - 1) * 12) + 24
29
+ end
30
+
31
+ def href
32
+ if collapsed?
33
+ item.url_path
34
+ elsif !collection?
35
+ item.url_path
36
+ end
37
+ end
38
+
39
+ def children
40
+ @children ||= if collection? && !collapsed?
41
+ item.non_empty_items.map do |item|
42
+ render Lookbook::Nav::Item::Component.new item,
43
+ depth: (@depth + 1),
44
+ collapse_singles: @collapse_singles
45
+ end
46
+ else
47
+ []
48
+ end
49
+ end
50
+
51
+ def item
52
+ collapsed? ? @item.first : @item
53
+ end
54
+
55
+ def nav_icon(entity)
56
+ ICONS[entity.type] || :file
57
+ end
58
+
59
+ def collection?
60
+ @item.is_a? Lookbook::Collection
61
+ end
62
+
63
+ def children?
64
+ children.any? if collection? && !collapsed?
65
+ end
66
+
67
+ def collapsed?
68
+ @collapse_singles == true && collection? && @item.collapsible? && @item.one?
69
+ end
70
+
71
+ protected
72
+
73
+ def alpine_data
74
+ {
75
+ id: @item.id,
76
+ matchers: item.is_a?(Lookbook::Collection) ? nil : item.matchers
77
+ }.to_json
78
+ end
79
+
80
+ def alpine_component
81
+ "navItemComponent"
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,3 @@
1
+ <%= render_component_tag do %>
2
+ <%= safe_join(fields) %>
3
+ <% end %>
@@ -0,0 +1,12 @@
1
+ import { observeSize } from "@helpers/layout";
2
+
3
+ export default function paramsEditorComponent() {
4
+ return {
5
+ narrow: false,
6
+ init() {
7
+ observeSize(this.$el, ({ width }) => {
8
+ this.narrow = width < 450;
9
+ });
10
+ },
11
+ };
12
+ }
@@ -0,0 +1,11 @@
1
+ module Lookbook
2
+ class ParamsEditor::Component < Lookbook::Component
3
+ renders_many :fields, Lookbook::ParamsEditor::Field::Component
4
+
5
+ protected
6
+
7
+ def alpine_component
8
+ "paramsEditorComponent"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,50 @@
1
+ <%= render_component_tag class: "px-4 py-3" do %>
2
+ <div class="flex items-start max-w-[800px]" :class="isNarrowLayout && '!block'">
3
+ <label
4
+ for="param-<%= @name %>"
5
+ class="block font-bold cursor-pointer flex-none py-2 w-[140px] truncate pr-2">
6
+ <%= label %>
7
+ </label>
8
+
9
+ <div class="flex-grow">
10
+ <% if field_type == "text" %>
11
+
12
+ <input
13
+ class="form-input"
14
+ value="<%= value %>"
15
+ type="<%= input_type %>"
16
+ x-bind="bindings.input || {}">
17
+
18
+ <% elsif field_type == "textarea" %>
19
+
20
+ <textarea
21
+ class="form-input"
22
+ rows="4"
23
+ x-bind="bindings.input || {}"><%= value %></textarea>
24
+
25
+ <% elsif field_type == "select" %>
26
+
27
+ <select
28
+ class="form-input"
29
+ x-bind="bindings.input || {}"
30
+ x-model="value">
31
+ <%= options_for_select(@options || [], value) %>
32
+ </select>
33
+
34
+ <% elsif field_type == "toggle" %>
35
+
36
+ <button type="button"
37
+ class="<%= value == true ? "bg-lookbook-input-toggle-active" : "bg-lookbook-input-toggle" %> relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-input-border-focus"
38
+ role="switch"
39
+ @click.stop="value = !value">
40
+ <span
41
+ aria-hidden="true"
42
+ class="<%= value == true ? "translate-x-5" : "translate-x-0" %> pointer-events-none inline-block h-5 w-5 rounded-full bg-white shadow ring-0 transition ease-in-out duration-200"
43
+ ></span>
44
+ </button>
45
+
46
+ <% end %>
47
+ </div>
48
+ </div>
49
+ <% end %>
50
+
@@ -0,0 +1,36 @@
1
+ export default function paramsEditorFieldComponent({ name, value }) {
2
+ return {
3
+ name,
4
+ value,
5
+
6
+ init() {
7
+ this.$watch("value", () => this.update());
8
+ },
9
+
10
+ update() {
11
+ if (this.validate()) {
12
+ const searchParams = new URLSearchParams(window.location.search);
13
+ searchParams.set(this.name, this.value);
14
+ const path = location.href.replace(location.search, "");
15
+ this.navigateTo(`${path}?${searchParams.toString()}`);
16
+ }
17
+ },
18
+
19
+ validate() {
20
+ return this.$root.reportValidity ? this.$root.reportValidity() : true;
21
+ },
22
+
23
+ get isNarrowLayout() {
24
+ return this.narrow || false;
25
+ },
26
+
27
+ bindings: {
28
+ input: {
29
+ [":id"]: "`param-${name}`",
30
+ ["x-ref"]: "input",
31
+ ["x-model.debounce.200"]: "value",
32
+ ["@keydown.stop"]: true,
33
+ },
34
+ },
35
+ };
36
+ }
@@ -0,0 +1,41 @@
1
+ module Lookbook
2
+ class ParamsEditor::Field::Component < Lookbook::Component
3
+ def initialize(input:, name:, default: nil, value: nil, input_type: nil, type: nil, options: nil, **html_attrs)
4
+ @input = input
5
+ @name = name
6
+ @value = value
7
+ @default_value = default
8
+ @input_type = input_type
9
+ @type = type
10
+ @options = options
11
+ super(**html_attrs)
12
+ end
13
+
14
+ def label
15
+ @name.titleize
16
+ end
17
+
18
+ def value
19
+ val = @value.presence || @default_value
20
+ @type == "Boolean" ? val == "true" || val == true : val
21
+ end
22
+
23
+ def field_type
24
+ @input.to_s
25
+ end
26
+
27
+ def input_type
28
+ @input_type.nil? && field_type == "text" ? "text" : @input_type
29
+ end
30
+
31
+ protected
32
+
33
+ def alpine_data
34
+ "{name: '#{@name}', value: #{value.to_json}}"
35
+ end
36
+
37
+ def alpine_component
38
+ "paramsEditorFieldComponent"
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,12 @@
1
+ @layer components {
2
+ [data-component="prose"] {
3
+ [data-component="code"] {
4
+ @apply border border-lookbook-divider rounded-md;
5
+ }
6
+
7
+ [data-component="embed"],
8
+ [data-component="code"] {
9
+ @apply my-8;
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,3 @@
1
+ <%= render_component_tag class: "prose #{size_class} text-lookbook-prose-text bg-lookbook-prose prose-a:text-lookbook-prose-link" do %>
2
+ <%== rendered_content %>
3
+ <% end %>
@@ -0,0 +1,26 @@
1
+ module Lookbook
2
+ class Prose::Component < Lookbook::Component
3
+ include Lookbook::OutputHelper
4
+
5
+ def initialize(size: :md, markdown: true, **html_attrs)
6
+ @size = size
7
+ @markdown = markdown
8
+ super(**html_attrs)
9
+ end
10
+
11
+ def rendered_content
12
+ @markdown ? markdown(content.strip_heredoc) : helpers.raw(content)
13
+ end
14
+
15
+ def size_class
16
+ case @size
17
+ when :sm
18
+ "prose-sm"
19
+ when :lg
20
+ "prose-lg"
21
+ else
22
+ ""
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,13 @@
1
+ <%= render_component_tag class: "grid h-full w-full", x_bind: "bindings.root", x_effect: "initSplit" do %>
2
+ <% panes.each.with_index(1) do |pane, i| %>
3
+ <%= pane %>
4
+ <% if i < panes.size %>
5
+ <div class="bg-lookbook-divider relative" x-init="registerGutter">
6
+ <div class="absolute z-10 bg-transparent hover:bg-lookbook-draggable-hint transition-all" :class="{
7
+ 'w-[9px] h-full -translate-x-1/2 cursor-[col-resize]': vertical,
8
+ 'h-[9px] w-full -translate-y-1/2 cursor-[row-resize]': horizontal
9
+ }"></div>
10
+ </div>
11
+ <% end %>
12
+ <% end %>
13
+ <% end %>
@@ -0,0 +1,151 @@
1
+ import Split from "split-grid";
2
+ import { observeSize } from "@helpers/layout";
3
+
4
+ export default function splitLayoutComponent({ split, opts = {} }) {
5
+ let splitter = null;
6
+ const shouldSplit = split.sizes !== null;
7
+
8
+ return {
9
+ layoutResizing: false,
10
+
11
+ layoutWidth: null,
12
+
13
+ layoutHeight: null,
14
+
15
+ forceOrientation: null,
16
+
17
+ get vertical() {
18
+ if (this.forceOrientation) {
19
+ return this.forceOrientation === "vertical";
20
+ }
21
+ return split.direction === "vertical";
22
+ },
23
+
24
+ get horizontal() {
25
+ if (this.forceOrientation) {
26
+ return this.forceOrientation === "horizontal";
27
+ }
28
+ return split.direction === "horizontal";
29
+ },
30
+
31
+ get splits() {
32
+ if (this.horizontal && split.horizontalSizes) {
33
+ return split.horizontalSizes;
34
+ } else if (this.vertical && split.verticalSizes) {
35
+ return split.verticalSizes;
36
+ } else {
37
+ return split.sizes || [];
38
+ }
39
+ },
40
+
41
+ get minSizes() {
42
+ if (this.horizontal && opts.minHorizontalSizes) {
43
+ return opts.minHorizontalSizes;
44
+ } else if (this.vertical && opts.minVerticalSizes) {
45
+ return opts.minVerticalSizes;
46
+ } else {
47
+ return opts.minSizes || [];
48
+ }
49
+ },
50
+
51
+ init() {
52
+ observeSize(this.$el, ({ width, height }) => {
53
+ this.layoutWidth = width;
54
+ this.layoutHeight = height;
55
+ });
56
+ },
57
+
58
+ switchOrientation() {
59
+ split.direction = this.vertical ? "horizontal" : "vertical";
60
+ },
61
+
62
+ registerGutter() {
63
+ this._gutters.push(this.$el);
64
+ },
65
+
66
+ initSplit() {
67
+ if (shouldSplit && this._gutters.length) {
68
+ this._destroySplit();
69
+ const dir = this.horizontal ? "row" : "column";
70
+ splitter = Split({
71
+ [`${dir}Gutters`]: gutterSplits(this._gutters),
72
+ [`${dir}MinSizes`]: sizeSplits(this.minSizes),
73
+ snapOffset: 0,
74
+ dragInterval: 1,
75
+ writeStyle() {},
76
+ onDrag: (dir, gutterTrack, style) => {
77
+ const splits = style
78
+ .split(" ")
79
+ .map((value, i) => (i % 2 == 0 ? value : null))
80
+ .filter((v) => v);
81
+ this._setSplits(splits);
82
+ },
83
+ onDragStart: () => {
84
+ this.layoutResizing = true;
85
+ this.$dispatch("layout:resize-start", { layout: this });
86
+ },
87
+ onDragEnd: () => {
88
+ this.layoutResizing = false;
89
+ this.$dispatch("layout:resize-end", { layout: this });
90
+ },
91
+ });
92
+ }
93
+ },
94
+
95
+ bindings: {
96
+ root: {
97
+ [":style"]() {
98
+ return {
99
+ "grid-template-columns":
100
+ shouldSplit && this.vertical && sizeStr(this.splits),
101
+ "grid-template-rows":
102
+ shouldSplit && this.horizontal && sizeStr(this.splits),
103
+ };
104
+ },
105
+ },
106
+ },
107
+
108
+ // protected
109
+
110
+ _gutters: [],
111
+
112
+ _destroySplit() {
113
+ if (splitter) splitter.destroy();
114
+ },
115
+
116
+ _setSplits(splits) {
117
+ if (this.horizontal && split.horizontalSizes) {
118
+ split.horizontalSizes = splits;
119
+ } else if (this.vertical && split.verticalSizes) {
120
+ split.verticalSizes = splits;
121
+ } else {
122
+ split.sizes = splits;
123
+ }
124
+ },
125
+ };
126
+ }
127
+
128
+ // utils
129
+
130
+ function sizeStr(sizes) {
131
+ const values = [];
132
+ sizes.forEach((size) => values.push(size, "1px"));
133
+ return values.slice(0, -1).join(" ");
134
+ }
135
+
136
+ function gutterSplits(gutters) {
137
+ return gutters.map((element, i) => {
138
+ return {
139
+ track: i * 2 + 1,
140
+ element,
141
+ };
142
+ });
143
+ }
144
+
145
+ function sizeSplits(sizes) {
146
+ const splits = {};
147
+ sizes.forEach((value, i) => {
148
+ if (value !== null) splits[i * 2] = value;
149
+ });
150
+ return splits;
151
+ }
@@ -0,0 +1,11 @@
1
+ module Lookbook
2
+ class SplitLayout::Component < Lookbook::Component
3
+ renders_many :panes, Lookbook::TagComponent
4
+
5
+ protected
6
+
7
+ def alpine_component
8
+ "splitLayoutComponent"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ <%= render_component_tag class: "h-full" do %>
2
+ <div x-ref="sections" class="h-full">
3
+ <%= safe_join(sections) %>
4
+ </div>
5
+ <% end %>