lookbook 0.8.3 → 1.0.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (210) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +90 -795
  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 -61
  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 +23 -17
  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 +11 -0
  43. data/app/components/lookbook/dimensions_display/component.js +37 -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/page_tabs/component.html.erb +18 -0
  64. data/app/components/lookbook/page_tabs/component.rb +19 -0
  65. data/app/components/lookbook/params_editor/component.html.erb +3 -0
  66. data/app/components/lookbook/params_editor/component.js +12 -0
  67. data/app/components/lookbook/params_editor/component.rb +11 -0
  68. data/app/components/lookbook/params_editor/field/component.html.erb +50 -0
  69. data/app/components/lookbook/params_editor/field/component.js +36 -0
  70. data/app/components/lookbook/params_editor/field/component.rb +41 -0
  71. data/app/components/lookbook/prose/component.css +12 -0
  72. data/app/components/lookbook/prose/component.html.erb +3 -0
  73. data/app/components/lookbook/prose/component.rb +26 -0
  74. data/app/components/lookbook/split_layout/component.html.erb +13 -0
  75. data/app/components/lookbook/split_layout/component.js +151 -0
  76. data/app/components/lookbook/split_layout/component.rb +11 -0
  77. data/app/components/lookbook/tab_panels/component.html.erb +5 -0
  78. data/app/components/lookbook/tab_panels/component.js +25 -0
  79. data/app/components/lookbook/tab_panels/component.rb +20 -0
  80. data/app/components/lookbook/tab_panels/panel/component.html.erb +8 -0
  81. data/app/components/lookbook/tab_panels/panel/component.rb +9 -0
  82. data/app/components/lookbook/tabs/component.css +8 -0
  83. data/app/components/lookbook/tabs/component.html.erb +20 -0
  84. data/app/components/lookbook/tabs/component.js +115 -0
  85. data/app/components/lookbook/tabs/component.rb +28 -0
  86. data/app/components/lookbook/tabs/dropdown_tab/component.html.erb +20 -0
  87. data/app/components/lookbook/tabs/dropdown_tab/component.rb +17 -0
  88. data/app/components/lookbook/tabs/tab/component.html.erb +24 -0
  89. data/app/components/lookbook/tabs/tab/component.rb +17 -0
  90. data/app/components/lookbook/tag_component.rb +29 -0
  91. data/app/components/lookbook/toolbar/component.css +16 -0
  92. data/app/components/lookbook/toolbar/component.html.erb +5 -0
  93. data/app/components/lookbook/toolbar/component.rb +26 -0
  94. data/app/components/lookbook/viewport/component.css +11 -0
  95. data/app/components/lookbook/viewport/component.html.erb +57 -0
  96. data/app/{assets/lookbook/js/components/preview-window.js → components/lookbook/viewport/component.js} +57 -14
  97. data/app/components/lookbook/viewport/component.rb +21 -0
  98. data/app/controllers/lookbook/application_controller.rb +16 -5
  99. data/app/controllers/lookbook/pages_controller.rb +19 -8
  100. data/app/controllers/lookbook/previews_controller.rb +131 -90
  101. data/app/helpers/lookbook/application_helper.rb +5 -1
  102. data/app/helpers/lookbook/component_helper.rb +22 -10
  103. data/app/helpers/lookbook/output_helper.rb +8 -4
  104. data/app/helpers/lookbook/page_helper.rb +13 -21
  105. data/app/views/layouts/lookbook/application.html.erb +76 -28
  106. data/app/views/layouts/lookbook/inspector.html.erb +7 -0
  107. data/app/views/layouts/lookbook/page.html.erb +53 -0
  108. data/app/views/layouts/lookbook/shell.html.erb +64 -0
  109. data/app/views/layouts/lookbook/skeleton.html.erb +27 -10
  110. data/app/views/layouts/lookbook/standalone.html.erb +5 -0
  111. data/app/views/lookbook/404.html.erb +15 -0
  112. data/app/views/lookbook/error.html.erb +34 -34
  113. data/app/views/lookbook/index.html.erb +11 -6
  114. data/app/views/lookbook/pages/show.html.erb +38 -66
  115. data/app/views/{layouts/lookbook → lookbook}/preview.html.erb +6 -8
  116. data/app/views/lookbook/previews/panels/_content.html.erb +13 -0
  117. data/app/views/lookbook/previews/panels/_notes.html.erb +19 -25
  118. data/app/views/lookbook/previews/panels/_output.html.erb +7 -18
  119. data/app/views/lookbook/previews/panels/_params.html.erb +13 -15
  120. data/app/views/lookbook/previews/panels/_preview.html.erb +6 -52
  121. data/app/views/lookbook/previews/panels/_source.html.erb +6 -15
  122. data/app/views/lookbook/previews/show.html.erb +133 -24
  123. data/config/routes.rb +5 -5
  124. data/lib/lookbook/code_formatter.rb +37 -13
  125. data/lib/lookbook/collection.rb +19 -16
  126. data/lib/lookbook/config.rb +180 -0
  127. data/lib/lookbook/engine.rb +66 -59
  128. data/lib/lookbook/entity.rb +47 -0
  129. data/lib/lookbook/error.rb +1 -2
  130. data/lib/lookbook/features.rb +1 -1
  131. data/lib/lookbook/markdown.rb +3 -4
  132. data/lib/lookbook/page.rb +52 -20
  133. data/lib/lookbook/page_collection.rb +8 -0
  134. data/lib/lookbook/page_section.rb +31 -0
  135. data/lib/lookbook/params.rb +14 -3
  136. data/lib/lookbook/preview.rb +16 -7
  137. data/lib/lookbook/preview_collection.rb +8 -0
  138. data/lib/lookbook/preview_controller.rb +6 -2
  139. data/lib/lookbook/preview_example.rb +5 -6
  140. data/lib/lookbook/preview_group.rb +4 -9
  141. data/lib/lookbook/{code_inspector.rb → source_inspector.rb} +2 -2
  142. data/lib/lookbook/store.rb +36 -0
  143. data/lib/lookbook/theme.rb +29 -0
  144. data/lib/lookbook/utils.rb +11 -3
  145. data/lib/lookbook/version.rb +1 -1
  146. data/lib/lookbook.rb +6 -1
  147. data/lib/tasks/lookbook_tasks.rake +12 -0
  148. data/public/lookbook-assets/css/app.css +2340 -1
  149. data/public/lookbook-assets/css/app.css.map +11 -1
  150. data/public/lookbook-assets/css/lookbook.css +3069 -0
  151. data/public/lookbook-assets/css/lookbook.css.map +1 -0
  152. data/public/lookbook-assets/css/themes/blue.css +44 -0
  153. data/public/lookbook-assets/css/themes/blue.css.map +1 -0
  154. data/public/lookbook-assets/css/themes/indigo.css +44 -0
  155. data/public/lookbook-assets/css/themes/indigo.css.map +1 -0
  156. data/public/lookbook-assets/css/themes/zinc.css +44 -0
  157. data/public/lookbook-assets/css/themes/zinc.css.map +1 -0
  158. data/public/lookbook-assets/js/app.js +10861 -1
  159. data/public/lookbook-assets/js/app.js.map +2571 -1
  160. data/public/lookbook-assets/js/embed.js +895 -1
  161. data/public/lookbook-assets/js/embed.js.map +1 -1
  162. data/public/lookbook-assets/js/lookbook.js +13541 -0
  163. data/public/lookbook-assets/js/lookbook.js.map +1 -0
  164. metadata +133 -115
  165. data/app/assets/lookbook/css/app.css +0 -161
  166. data/app/assets/lookbook/css/code_theme.css +0 -214
  167. data/app/assets/lookbook/js/components/app.js +0 -55
  168. data/app/assets/lookbook/js/components/code.js +0 -5
  169. data/app/assets/lookbook/js/components/copy.js +0 -20
  170. data/app/assets/lookbook/js/components/embed.js +0 -89
  171. data/app/assets/lookbook/js/components/filter.js +0 -35
  172. data/app/assets/lookbook/js/components/inspector.js +0 -66
  173. data/app/assets/lookbook/js/components/nav-group.js +0 -47
  174. data/app/assets/lookbook/js/components/nav-item.js +0 -29
  175. data/app/assets/lookbook/js/components/nav.js +0 -28
  176. data/app/assets/lookbook/js/components/page.js +0 -25
  177. data/app/assets/lookbook/js/components/param.js +0 -34
  178. data/app/assets/lookbook/js/components/sidebar.js +0 -18
  179. data/app/assets/lookbook/js/components/sizes.js +0 -16
  180. data/app/assets/lookbook/js/components/splitter.js +0 -25
  181. data/app/assets/lookbook/js/components/tabs.js +0 -52
  182. data/app/assets/lookbook/js/lib/split.js +0 -15
  183. data/app/assets/lookbook/js/stores/sidebar.js +0 -26
  184. data/app/views/layouts/lookbook/basic.html.erb +0 -7
  185. data/app/views/lookbook/components/_branding.html.erb +0 -8
  186. data/app/views/lookbook/components/_code.html.erb +0 -17
  187. data/app/views/lookbook/components/_copy_button.html.erb +0 -11
  188. data/app/views/lookbook/components/_drawer.html.erb +0 -112
  189. data/app/views/lookbook/components/_embed.html.erb +0 -39
  190. data/app/views/lookbook/components/_errors.html.erb +0 -13
  191. data/app/views/lookbook/components/_filter.html.erb +0 -18
  192. data/app/views/lookbook/components/_header.html.erb +0 -6
  193. data/app/views/lookbook/components/_icon.html.erb +0 -5
  194. data/app/views/lookbook/components/_nav.html.erb +0 -16
  195. data/app/views/lookbook/components/_nav_collection.html.erb +0 -5
  196. data/app/views/lookbook/components/_nav_group.html.erb +0 -14
  197. data/app/views/lookbook/components/_nav_item.html.erb +0 -24
  198. data/app/views/lookbook/components/_nav_page.html.erb +0 -22
  199. data/app/views/lookbook/components/_nav_preview.html.erb +0 -13
  200. data/app/views/lookbook/components/_not_found.html.erb +0 -11
  201. data/app/views/lookbook/components/_param.html.erb +0 -21
  202. data/app/views/lookbook/components/_preview.html.erb +0 -77
  203. data/app/views/lookbook/components/_sidebar.html.erb +0 -69
  204. data/app/views/lookbook/pages/not_found.html.erb +0 -15
  205. data/app/views/lookbook/previews/error.html.erb +0 -1
  206. data/app/views/lookbook/previews/inputs/_select.html.erb +0 -7
  207. data/app/views/lookbook/previews/inputs/_text.html.erb +0 -8
  208. data/app/views/lookbook/previews/inputs/_textarea.html.erb +0 -8
  209. data/app/views/lookbook/previews/inputs/_toggle.html.erb +0 -13
  210. data/app/views/lookbook/previews/not_found.html.erb +0 -23
@@ -0,0 +1,23 @@
1
+ module Lookbook
2
+ class Icon::Component < Lookbook::Component
3
+ def initialize(name:, size: 4, **html_attrs)
4
+ @icon_name = name.is_a?(Symbol) ? name.to_s.tr("_", "-").to_json : name
5
+ @size = size || 4
6
+ super(**html_attrs)
7
+ end
8
+
9
+ def size_rems
10
+ "#{@size * 0.25}rem"
11
+ end
12
+
13
+ protected
14
+
15
+ def alpine_data
16
+ @icon_name
17
+ end
18
+
19
+ def alpine_component
20
+ "iconComponent"
21
+ end
22
+ end
23
+ end
@@ -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,18 @@
1
+ <%= render_component_tag x_data: "{ activeTab: null }" do %>
2
+ <div class="flex w-full border-b border-lookbook-divider mb-6">
3
+ <%= render_component :tabs, theme: :page do |t| %>
4
+ <% @tabs.each do |props| %>
5
+ <%= t.tab **props %>
6
+ <% end %>
7
+ <% end %>
8
+ </div>
9
+ <%= render_component :tab_panels do |t| %>
10
+ <% @tabs.each do |props| %>
11
+ <% t.panel name: props[:name] do %>
12
+ <%= render_component :prose, markdown: props[:markdown], class: "max-w-none flex-none" do %>
13
+ <%== props[:content] %>
14
+ <% end %>
15
+ <% end %>
16
+ <% end %>
17
+ <% end %>
18
+ <% end %>
@@ -0,0 +1,19 @@
1
+ module Lookbook
2
+ class PageTabs::Component < Lookbook::Component
3
+ renders_many :tabs, ->(**attrs, &block) do
4
+ @tabs ||= []
5
+ attrs[:content] = capture(&block)
6
+ attrs[:markdown] ||= @markdown
7
+ @tabs << attrs
8
+ end
9
+
10
+ def initialize(markdown: true, **html_attrs)
11
+ @markdown = markdown
12
+ super(**html_attrs)
13
+ end
14
+
15
+ def before_render
16
+ tabs.size
17
+ end
18
+ end
19
+ 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 %>