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
@@ -1,6 +1,6 @@
1
1
  module Lookbook
2
2
  class PagesController < ApplicationController
3
- helper_method :page_controller
3
+ layout "lookbook/page"
4
4
 
5
5
  def self.controller_path
6
6
  "lookbook/pages"
@@ -9,10 +9,9 @@ module Lookbook
9
9
  def index
10
10
  landing = Lookbook.pages.find(&:landing) || Lookbook.pages.first
11
11
  if landing.present?
12
- redirect_to lookbook_page_path landing.lookup_path
12
+ redirect_to page_path landing.lookup_path
13
13
  else
14
- @title = "Not found"
15
- render "not_found"
14
+ show_404
16
15
  end
17
16
  end
18
17
 
@@ -20,27 +19,36 @@ module Lookbook
20
19
  @pages = Lookbook.pages
21
20
  @page = @pages.find_by_path(params[:path])
22
21
  if @page
22
+ @next_page = @pages.find_next(@page)
23
+ @previous_page = @pages.find_previous(@page)
23
24
  if @page.errors.any?
24
- render "lookbook/error", locals: {error: @page.errors.first}
25
+ render_in_layout "lookbook/error",
26
+ layout: "lookbook/page",
27
+ error: @page.errors.first
25
28
  else
26
29
  begin
27
30
  @page_content = page_controller.render_page(@page)
28
- @next_page = @pages.find_next(@page)
29
- @previous_page = @pages.find_previous(@page)
30
31
  @title = @page.title
31
32
  rescue => exception
32
- render "lookbook/error", locals: {
33
+ render_in_layout "lookbook/error",
34
+ layout: "lookbook/page",
33
35
  error: Lookbook::Error.new(exception, file_path: @page.full_path, source_code: @page.content)
34
- }
35
36
  end
36
37
  end
37
38
  else
38
- render "not_found"
39
+ show_404
39
40
  end
40
41
  end
41
42
 
42
43
  protected
43
44
 
45
+ def show_404
46
+ render "lookbook/404", locals: {
47
+ message: "Page not found",
48
+ description: "The page may have been removed or renamed."
49
+ }
50
+ end
51
+
44
52
  def page_controller
45
53
  controller_class = Lookbook.config.page_controller.constantize
46
54
  controller = controller_class.new
@@ -1,5 +1,7 @@
1
1
  module Lookbook
2
2
  class PreviewsController < ApplicationController
3
+ layout "lookbook/inspector"
4
+
3
5
  def self.controller_path
4
6
  "lookbook/previews"
5
7
  end
@@ -14,12 +16,11 @@ module Lookbook
14
16
  render html: render_examples(examples_data)
15
17
  rescue => exception
16
18
  render_in_layout "lookbook/error",
17
- layout: "lookbook/basic",
18
- error: prettify_error(exception),
19
- disable_header: true
19
+ layout: "lookbook/standalone",
20
+ error: prettify_error(exception)
20
21
  end
21
22
  else
22
- render_in_layout "not_found"
23
+ show_404 layout: "lookbook/standalone"
23
24
  end
24
25
  end
25
26
 
@@ -27,30 +28,55 @@ module Lookbook
27
28
  if @example
28
29
  begin
29
30
  set_params
30
- @examples = examples_data
31
- @drawer_panels = drawer_panels.select { |name, panel| panel[:show] }
32
- @preview_panels = preview_panels.select { |name, panel| panel[:show] }
31
+ @rendered_examples = examples_data
32
+ @drawer_panels = drawer_panels.filter { |name, panel| panel[:show] }
33
+ @preview_panels = preview_panels.filter { |name, panel| panel[:show] }
33
34
  rescue => exception
34
- render_in_layout "lookbook/error", error: prettify_error(exception)
35
+ render_in_layout "lookbook/error", layout: "lookbook/inspector", error: prettify_error(exception)
35
36
  end
36
37
  else
37
- render_in_layout "not_found"
38
+ show_404
38
39
  end
39
40
  end
40
41
 
42
+ def show_legacy
43
+ Lookbook.logger.warn("Legacy URL path detected. These paths are deprecated and will be removed in a future version")
44
+ redirect_to inspect_path params[:path]
45
+ end
46
+
41
47
  private
42
48
 
43
49
  def lookup_entities
44
50
  @example = Lookbook.previews.find_example(params[:path])
45
- if @example
51
+ if @example.present?
46
52
  @preview = @example.preview
47
53
  if params[:path] == @preview&.lookup_path
48
- redirect_to lookbook_inspect_path "#{params[:path]}/#{@preview.default_example.name}"
54
+ redirect_to inspect_path "#{params[:path]}/#{@preview.default_example.name}"
55
+ end
56
+ else
57
+ @preview = Lookbook.previews.find(params[:path])
58
+ if @preview.present?
59
+ first_example = @preview.examples.first
60
+ redirect_to inspect_path(first_example.lookup_path) if first_example
61
+ else
62
+ @preview = Lookbook.previews.find(path_segments.slice(0, path_segments.size - 1).join("/"))
49
63
  end
64
+ end
65
+ end
66
+
67
+ def show_404(layout: nil)
68
+ locals = if @preview
69
+ {
70
+ message: "Example not found",
71
+ description: "The '#{@preview.label}' preview does not have an example named '#{path_segments.last}'."
72
+ }
50
73
  else
51
- first_example = Lookbook.previews.find(params[:path])&.examples&.first
52
- redirect_to lookbook_inspect_path(first_example.lookup_path) if first_example
74
+ {
75
+ message: "Not found",
76
+ description: "Looked for '#{params[:path]}'.<br>The preview may have been renamed or deleted."
77
+ }
53
78
  end
79
+ render_in_layout "lookbook/404", layout: layout, **locals
54
80
  end
55
81
 
56
82
  def set_title
@@ -72,12 +98,17 @@ module Lookbook
72
98
  html: preview_controller.process(:render_example_to_string, @preview, example.name),
73
99
  source: has_template ? example.template_source(render_args[:template]) : example.method_source,
74
100
  source_lang: has_template ? example.template_lang(render_args[:template]) : example.source_lang,
75
- params: example.params
101
+ params: example.params,
102
+ display: example.display_params
76
103
  }
77
104
  end
78
105
 
79
106
  def render_examples(examples)
80
- preview_controller.process(:render_in_layout_to_string, "layouts/lookbook/preview", {examples: examples}, @preview.layout)
107
+ opts = {layout: @preview.layout}
108
+ if params[:lookbook_embed] == "true"
109
+ opts[:append_html] = "<script src=\"/lookbook-assets/js/embed.js?v=#{Lookbook.version}\"></script>".html_safe
110
+ end
111
+ preview_controller.process(:render_in_layout_to_string, "lookbook/preview", {examples: examples}, **opts)
81
112
  end
82
113
 
83
114
  def set_params
@@ -99,21 +130,22 @@ module Lookbook
99
130
  def preview_panels
100
131
  {
101
132
  preview: {
133
+ id: "preview-panel-preview",
102
134
  label: "Preview",
103
135
  template: "lookbook/previews/panels/preview",
104
- srcdoc: Lookbook.config.preview_srcdoc ? render_examples(examples_data).gsub("\"", "&quot;") : nil,
105
136
  hotkey: "v",
106
137
  show: true,
107
138
  disabled: false,
108
139
  copy: false
109
140
  },
110
141
  output: {
142
+ id: "preview-panel-html",
111
143
  label: "HTML",
112
144
  template: "lookbook/previews/panels/output",
113
- hotkey: "o",
145
+ hotkey: "h",
114
146
  show: true,
115
147
  disabled: false,
116
- copy: true
148
+ copy: false
117
149
  }
118
150
  }
119
151
  end
@@ -121,26 +153,31 @@ module Lookbook
121
153
  def drawer_panels
122
154
  {
123
155
  source: {
156
+ id: "drawer-panel-source",
124
157
  label: "Source",
125
158
  template: "lookbook/previews/panels/source",
126
159
  hotkey: "s",
127
160
  show: true,
128
161
  disabled: false,
129
- copy: true
162
+ copy: @rendered_examples.map { |e| e[:source] }.join("\n")
130
163
  },
131
164
  notes: {
165
+ id: "drawer-panel-notes",
132
166
  label: "Notes",
133
167
  template: "lookbook/previews/panels/notes",
134
168
  hotkey: "n",
135
169
  show: true,
136
- disabled: @examples.select { |e| e[:notes].present? }.none?
170
+ copy: false,
171
+ disabled: @rendered_examples.filter { |e| e[:notes].present? }.none?
137
172
  },
138
173
  params: {
174
+ id: "drawer-panel-params",
139
175
  label: "Params",
140
176
  template: "lookbook/previews/panels/params",
141
177
  hotkey: "p",
142
178
  show: true,
143
- disabled: @example.type == :group || @example.params.none?
179
+ disabled: @example.params.none?,
180
+ copy: false
144
181
  }
145
182
  }
146
183
  end
@@ -153,10 +190,6 @@ module Lookbook
153
190
  @preview_controller ||= controller
154
191
  end
155
192
 
156
- def render_in_layout(path, layout: nil, **locals)
157
- render path, layout: layout.presence || (params[:lookbook_embed] ? "lookbook/basic" : "lookbook/application"), locals: locals
158
- end
159
-
160
193
  def prettify_error(exception)
161
194
  error_params = if exception.is_a?(ViewComponent::PreviewTemplateError)
162
195
  {
@@ -178,5 +211,9 @@ module Lookbook
178
211
  end
179
212
  Lookbook::Error.new(exception, **(error_params || {}))
180
213
  end
214
+
215
+ def path_segments
216
+ params[:path].split("/")
217
+ end
181
218
  end
182
219
  end
@@ -9,12 +9,16 @@ module Lookbook
9
9
  end
10
10
 
11
11
  def landing_path
12
- landing = feature_enabled?(:pages) ? Lookbook.pages.find(&:landing) || Lookbook.pages.first : nil
12
+ landing = Lookbook.pages.find(&:landing) || Lookbook.pages.first
13
13
  if landing.present?
14
- lookbook_page_path landing.lookup_path
14
+ page_path(landing.lookup_path)
15
15
  else
16
- lookbook_home_path
16
+ home_path
17
17
  end
18
18
  end
19
+
20
+ def generate_id(*args)
21
+ args.map { |args| args.delete_prefix("/").tr("&?=/_\-", "-") }.join("-")
22
+ end
19
23
  end
20
24
  end
@@ -1,16 +1,15 @@
1
1
  module Lookbook
2
2
  module ComponentHelper
3
- def render_component(name, **attrs, &block)
4
- attrs[:classes] = class_names(attrs[:class])
5
- render "lookbook/components/#{name.underscore}", **attrs.except(:class), &block
6
- end
3
+ COMPONENT_CLASSES = {} # cache for constantized references
7
4
 
8
- def icon(name, size: 4, **attrs)
9
- render_component "icon", name: name, size: size, **attrs
5
+ def render_component(ref, **attrs, &block)
6
+ klass = component_class(ref)
7
+ comp = attrs.key?(:content) ? klass.new(**attrs.except(:content)).with_content(attrs[:content]) : klass.new(**attrs)
8
+ render comp, &block
10
9
  end
11
10
 
12
- def code(language = "ruby", **opts, &block)
13
- render_component "code", language: language, **opts, &block
11
+ def render_tag(tag = :div, **attrs, &block)
12
+ render Lookbook::TagComponent.new(tag: tag, **attrs), &block
14
13
  end
15
14
 
16
15
  if Rails.version.to_f < 6.1
@@ -20,10 +19,23 @@ module Lookbook
20
19
  end
21
20
  end
22
21
 
23
- alias_method :component, :render_component
24
-
25
22
  private
26
23
 
24
+ def component_class(ref)
25
+ klass = COMPONENT_CLASSES[ref]
26
+ if klass.nil?
27
+ ref = ref.to_s.tr("-", "_")
28
+ class_namespace = ref.camelize
29
+ begin
30
+ klass = "Lookbook::#{class_namespace}::Component".constantize
31
+ rescue
32
+ klass = "Lookbook::#{class_namespace}Component".constantize
33
+ end
34
+ COMPONENT_CLASSES[ref] = klass
35
+ end
36
+ klass
37
+ end
38
+
27
39
  def build_tag_values(*args)
28
40
  tag_values = []
29
41
  args.each do |tag_value|
@@ -4,12 +4,16 @@ module Lookbook
4
4
  Lookbook::Markdown.render(block ? capture(&block) : text)
5
5
  end
6
6
 
7
- def highlight(source, language, opts = {})
8
- Lookbook::CodeFormatter.highlight(source, language, opts)
7
+ def highlight(source, **opts)
8
+ Lookbook::CodeFormatter.highlight(source, **opts)
9
9
  end
10
10
 
11
- def beautify(source, language = "html")
12
- Lookbook::CodeFormatter.beautify(source, language)
11
+ def beautify(source, **opts)
12
+ Lookbook::CodeFormatter.beautify(source, **opts)
13
+ end
14
+
15
+ def pretty_json(obj)
16
+ JSON.pretty_generate(obj)
13
17
  end
14
18
  end
15
19
  end
@@ -4,38 +4,30 @@ module Lookbook
4
4
 
5
5
  def page_path(id)
6
6
  page = id.is_a?(Page) ? id : Lookbook.pages.find(id)
7
- lookbook_page_path page.lookup_path
7
+ if page.present?
8
+ lookbook.page_path page.lookup_path
9
+ else
10
+ Lookbook.logger.warn "Could not find page with id ':#{id}'"
11
+ end
8
12
  end
9
13
 
10
- def embed(*args, params: {}, type: :preview, **opts)
14
+ def embed(*args, params: {}, type: :preview, max_height: nil, **opts)
11
15
  return unless args.any?
12
16
 
13
17
  @embed_counter ||= 0
14
18
 
15
19
  preview_lookup = args.first.is_a?(Symbol) ? args.first : preview_class_name(args.first)
16
20
  preview = Lookbook.previews.find(preview_lookup)
17
-
18
21
  example = args[1] ? preview&.example(args[1]) : preview&.default_example
19
22
 
20
- if example
21
- @embed_counter += 1
22
- render_component "embed",
23
- id: generate_id("embed", url_for, example.lookup_path, @embed_counter - 1),
24
- example: example,
25
- params: params,
26
- opts: opts
27
- else
28
- embed_not_found
29
- end
30
- end
31
-
32
- protected
23
+ embed_id = "#{url_for}/embed/#{example.lookup_path}".delete_prefix("/").tr("/", "-")
33
24
 
34
- def embed_not_found
35
- render_component "not_found", {
36
- title: "Preview not found",
37
- text: "The preview may have been renamed or deleted."
38
- }
25
+ render_component :embed,
26
+ id: embed_id,
27
+ example: example,
28
+ params: params,
29
+ max_height: max_height,
30
+ opts: opts
39
31
  end
40
32
  end
41
33
  end
@@ -1,30 +1,78 @@
1
- <%= content_for :body do %>
2
- <div
3
- id="app"
4
- x-data="app"
5
- :style="`grid-template-columns: ${$store.sidebar.width}px 1px 1fr;`"
6
- :class="{'grid': $store.sidebar.open && $store.layout.desktop}"
7
- @popstate.window="await update(); $dispatch('page:changed')"
8
- @refresh.window="update"
9
- @resize.window="$store.layout.desktop = window.innerWidth >= $store.layout.desktopWidth"
10
- class="w-screen h-screen">
11
- <%= component "sidebar" %>
12
- <div
13
- x-data="splitter('vertical', {minSize: $store.sidebar.minWidth})"
14
- class="h-full gutter border-r border-gray-300 relative"
15
- x-show="$store.sidebar.open && $store.layout.desktop"
16
- x-effect="$store.sidebar.width = Math.min(splits[0] || $store.sidebar.width, $store.sidebar.maxWidth)"
17
- x-cloak>
18
- <div class="w-[9px] h-full bg-transparent hover:bg-indigo-100 hover:bg-opacity-20 transition absolute top-0 bottom-0 -translate-x-1/2 cursor-[col-resize] z-10"></div>
19
- </div>
20
- <main
21
- id="main"
22
- class="h-full overflow-hidden w-full"
23
- x-show="$store.layout.desktop || ($store.layout.mobile && !$store.sidebar.open)"
24
- x-cloak>
25
- <%= yield %>
26
- </main>
27
- </div>
1
+ <% content_for :shell do %>
2
+ <%= render_component :split_layout,
3
+ alpine_data: "$store.layout.main",
4
+ ":class": "$store.layout.mobile && '!block'" do |layout| %>
5
+
6
+ <% layout.pane class: "flex flex-col bg-lookbook-sidebar relative translate-x-0",
7
+ ":class": "{
8
+ 'transition': $store.layout.mobile,
9
+ 'translate-x-full': $store.layout.mobile && sidebarHidden,
10
+ '!absolute right-0 bottom-0 top-[40px] h-[calc(100%_-_40px)] w-full max-w-[420px] z-50 border-l border-lookbook-divider': $store.layout.mobile
11
+ }",
12
+ "@click.outside": "closeMobileSidebar",
13
+ x_cloak: true do %>
14
+
15
+ <%= render_component :split_layout,
16
+ alpine_data: "$store.layout.#{Lookbook.pages.any? ? "sidebar" : "singleSectionSidebar"}",
17
+ style: "height: calc(100vh - 2.5rem);" do |layout| %>
18
+ <% layout.pane class: "overflow-hidden" do %>
19
+ <%= render_component :nav,
20
+ collection: Lookbook.previews,
21
+ alpine_data: "$store.nav.previews",
22
+ label: "Previews",
23
+ collapse_singles: true do |nav| %>
24
+ <% nav.filter store: "$store.nav.previews.filter", placeholder: "Filter by preview name&hellip;" %>
25
+ <% end %>
26
+ <% end %>
27
+
28
+ <% if Lookbook.pages.any? %>
29
+ <% layout.pane class: "overflow-hidden" do %>
30
+ <%= render_component :nav,
31
+ collection: Lookbook.pages,
32
+ alpine_data: "$store.nav.pages",
33
+ label: "Pages" %>
34
+ <% end %>
35
+ <% end %>
36
+
37
+ <% end %>
38
+
39
+ <% if Lookbook::Preview.errors.any? %>
40
+ <div x-data="{hidden: false}" class="flex-none border-t border-lookbook-divider absolute bottom-0 left-0 right-0" x-show="!hidden">
41
+ <%= render_component :toolbar do |toolbar| %>
42
+ <% toolbar.section padded: true, class: "flex items-center" do %>
43
+ <%= render_component :icon, name: :alert_triangle, size: 4, class: "text-red-700" %>
44
+ <span class="ml-2">Preview load errors</span>
45
+ <% end %>
46
+ <% toolbar.section align: :right do %>
47
+ <% render_component :button, icon: :x, "@click": "hidden = !hidden" %>
48
+ <% end %>
49
+ <% end %>
50
+
51
+ <div class="h-full max-h-[300px] overflow-hidden">
52
+ <div class="bg-red-50 w-full overflow-auto h-full">
53
+ <ul class="text-sm divide-y divide-red-200">
54
+ <% Lookbook::Preview.errors.each do |error| %>
55
+ <% error = error.is_a?(Lookbook::Error) ? error : Lookbook::Error.new(error) %>
56
+ <li class="px-4 py-3">
57
+ <h4 class="break-all leading-tight text-xs ">
58
+ <%= error.file_name %><%= ":#{error.line_number}" if error.line_number %>
59
+ </h4>
60
+ <pre class="text-red-800 text-xs mt-2 whitespace-pre-wrap opacity-80 font-mono"><%= error.message %></pre>
61
+ </li>
62
+ <% end %>
63
+ </ul>
64
+ </div>
65
+ </div>
66
+ </div>
67
+ <% end %>
68
+ <% end %>
69
+
70
+ <% layout.pane class: "overflow-hidden", ":class": "$store.layout.mobile && 'w-screen'" do %>
71
+ <%= content_for?(:main) ? yield(:main) : yield %>
72
+ <% end %>
73
+
74
+ <% end %>
75
+ <div class="absolute opacity-0 bg-black inset-0 top-[39px] z-[-1] transition-opacity" :class="($store.layout.mobile && !sidebarHidden) && '!opacity-30 !z-40'" data-cloak></div>
28
76
  <% end %>
29
77
 
30
- <%= render template: "layouts/lookbook/skeleton" %>
78
+ <%= render template: "layouts/lookbook/shell" %>
@@ -0,0 +1,7 @@
1
+ <%= content_for :main do %>
2
+ <main class="h-[calc(100vh_-_2.5rem)]">
3
+ <%= yield %>
4
+ </main>
5
+ <% end %>
6
+
7
+ <%= render template: "layouts/lookbook/application" %>
@@ -0,0 +1,53 @@
1
+ <%= content_for :main do %>
2
+ <div
3
+ class="h-[calc(100vh_-_40px)]"
4
+ x-data="{}"
5
+ @navigation:complete.window="$refs.scroller.scrollTop = 0">
6
+
7
+ <div class="h-full bg-lookbook-page relative">
8
+ <% unless @error %>
9
+
10
+ <div class="absolute top-0 right-0 pt-1 pr-0 pl-1 pb-1 rounded-bl-md">
11
+ <div class="bg-lookbook-page opacity-90 absolute inset-0 w-full h-full z-0"></div>
12
+ <div class="relative z-10 flex items-center">
13
+
14
+ <% if @previous_page %>
15
+ <%= render_component :button,
16
+ size: :lg,
17
+ icon: :chevron_left,
18
+ tooltip: "Previous page",
19
+ href: page_path(@previous_page.lookup_path),
20
+ class: "pr-0.5 bg-transparent" %>
21
+ <% else %>
22
+ <%= render_component :button,
23
+ size: :lg,
24
+ icon: :chevron_left,
25
+ disabled: true,
26
+ class: "opacity-50 !cursor-default pr-0.5 bg-transparent" %>
27
+ <% end %>
28
+
29
+ <% if @next_page %>
30
+ <%= render_component :button,
31
+ size: :lg,
32
+ icon: :chevron_right,
33
+ tooltip: "Next page",
34
+ href: page_path(@next_page.lookup_path),
35
+ class: "pl-0.5 bg-transparent" %>
36
+ <% else %>
37
+ <%= render_component :button,
38
+ size: :lg,
39
+ icon: :chevron_right,
40
+ disabled: true,
41
+ class: "opacity-50 !cursor-default pl-0.5 bg-transparent" %>
42
+ <% end %>
43
+ </div>
44
+ </div>
45
+ <% end %>
46
+
47
+ <%= yield %>
48
+ </div>
49
+
50
+ </div>
51
+ <% end %>
52
+
53
+ <%= render template: "layouts/lookbook/application" %>
@@ -0,0 +1,64 @@
1
+ <%= content_for :body do %>
2
+ <div
3
+ id="app"
4
+ x-data="app"
5
+ @popstate.window="handleNavigation"
6
+ @click.document="hijax"
7
+ @navigation:start="closeMobileSidebar"
8
+ class="w-screen h-screen grid grid-rows-[40px_1fr] relative">
9
+
10
+ <%= render_component :header do |header| %>
11
+ <% header.branding { config.project_name } %>
12
+ <% end %>
13
+
14
+ <% if false %>
15
+ <%= render_component :toolbar, class: "group !bg-lookbook-header !text-lookbook-header-text" do |toolbar| %>
16
+ <% toolbar.section padded: true do %>
17
+ <%= render_component :branding,
18
+ text: config.project_name,
19
+ href: landing_path if config.project_name %>
20
+ <% end %>
21
+ <% toolbar.section padded: false, align: :right, class: "flex items-center" do %>
22
+ <%= render_component :button_group, class: "relative -top-px" do |group| %>
23
+ <% if Rails.env == "development" %>
24
+ <% group.button icon: :help_circle, class: "opacity-50 hover:opacity-100 transition !text-lookbook-header-text" do |button| %>
25
+ <% button.dropdown do %>
26
+ <%= tag.div class: "divide-y divide-lookbook-divider" do %>
27
+ <div class="flex items-center text-xs px-3 py-2">
28
+ <span class="opacity-60 mr-1">Lookbook</span>
29
+ <span class="mr-6">v<%= Lookbook::VERSION %></span>
30
+ <a href="https://github.com/allmarkedup/lookbook" target="_blank" class="ml-auto opacity-70">
31
+ <%= render_component :icon, name: :github, size: 3 %>
32
+ </a>
33
+ </div>
34
+ <div class="px-3 py-2">
35
+ <a href="#"
36
+ class="text-xs underline"
37
+ @click.stop="localStorage.clear(); window.location.reload();">
38
+ Clear local storage
39
+ </a>
40
+ </div>
41
+ <% end %>
42
+ <% end %>
43
+ <% end %>
44
+ <% end %>
45
+ <% group.button icon: :menu,
46
+ "@click.stop": "toggleSidebar",
47
+ x_show: "$store.layout.mobile && sidebarHidden",
48
+ class: "!text-lookbook-header-text" %>
49
+ <% group.button icon: :x,
50
+ "@click.stop": "toggleSidebar",
51
+ x_show: "$store.layout.mobile && !sidebarHidden",
52
+ "@keydown.esc.window": "closeMobileSidebar",
53
+ class: "!text-lookbook-header-text" %>
54
+ <% end %>
55
+ <% end %>
56
+ <% end %>
57
+ <% end %>
58
+
59
+ <%= content_for?(:shell) ? yield(:shell) : yield %>
60
+ </div>
61
+ <% end %>
62
+
63
+ <%= render template: "layouts/lookbook/skeleton" %>
64
+ 0