lookbook 0.8.3 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +38 -9
- data/app/assets/lookbook/css/app.css +1 -1
- data/app/assets/lookbook/js/app.js +2 -0
- data/app/assets/lookbook/js/components/page-tabs.js +9 -0
- data/app/controllers/lookbook/application_controller.rb +1 -1
- data/app/controllers/lookbook/pages_controller.rb +3 -1
- data/app/controllers/lookbook/previews_controller.rb +2 -2
- data/app/helpers/lookbook/application_helper.rb +1 -1
- data/app/helpers/lookbook/page_helper.rb +1 -1
- data/app/views/lookbook/components/_embed.html.erb +4 -4
- data/app/views/lookbook/components/_nav.html.erb +2 -2
- data/app/views/lookbook/components/_nav_item.html.erb +1 -1
- data/app/views/lookbook/components/_nav_page.html.erb +1 -1
- data/app/views/lookbook/components/_nav_preview.html.erb +1 -1
- data/app/views/lookbook/components/_preview.html.erb +1 -1
- data/app/views/lookbook/pages/show.html.erb +26 -0
- data/app/views/lookbook/previews/error.html.erb +1 -1
- data/app/views/lookbook/previews/panels/_preview.html.erb +1 -1
- data/config/routes.rb +5 -5
- data/lib/lookbook/page.rb +34 -8
- data/lib/lookbook/utils.rb +1 -1
- data/lib/lookbook/version.rb +1 -1
- data/public/lookbook-assets/css/app.css +1 -1
- data/public/lookbook-assets/css/app.css.map +1 -1
- data/public/lookbook-assets/js/app.js +1 -1
- data/public/lookbook-assets/js/app.js.map +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 71adea21d969026f205c494f5ebdfd5b1546a8dce639733da69bf8eeaa7f371d
|
4
|
+
data.tar.gz: dbd8406a04e3b6be61a97fba2daf96ce1bb005b0c7c0f9bdfc85e7443301d7d1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4913a862f29674edaa775ed2171b37d80f32a7d57b44efea92ee2901a7a122c2bfd941fe776cbc0338de72f0ed2f63c28f108a04d699e944cf93a03456b376c1
|
7
|
+
data.tar.gz: f6f914053d0d2db782537180a6193ce24e19641407c156d46ffe48179ca4d60a4d48609b01da58318e4bb8e727ccc86356269f5e96f7746e961516291c771a8e
|
data/README.md
CHANGED
@@ -13,7 +13,7 @@
|
|
13
13
|
---
|
14
14
|
|
15
15
|
<div align="center">
|
16
|
-
<a href="#installing">Installing</a> • <a href="#previews">Previews</a> • <a href="#pages">Pages</a> • <a href="#deployment">Deployment</a> • <a href="#config">Config</a>
|
16
|
+
<a href="#installing">Installing</a> • <a href="#previews">Previews</a> • <a href="#pages">Pages</a> • <a href="#deployment">Deployment</a> • <a href="#config">Config</a>
|
17
17
|
</div>
|
18
18
|
|
19
19
|
---
|
@@ -481,10 +481,10 @@ end
|
|
481
481
|
If you need to add more long-form documentation to live alongside your component previews you can do so using Lookbook's markdown-powered `pages` system.
|
482
482
|
|
483
483
|
> ⚠️ This feature is currently flagged as an **experimental** feature which requires [feature opt-in](#experimental-features) to use. Its API and implementation may change before it is released.
|
484
|
-
>
|
484
|
+
>
|
485
485
|
> To enable support for pages in your project, add `config.lookbook.experimental_features = [:pages]` into your application configuration file.
|
486
486
|
|
487
|
-
### Pages demo
|
487
|
+
### Pages demo
|
488
488
|
|
489
489
|
For an example of some pages in Lookbook, check out the [example pages](https://lookbook-demo-app.herokuapp.com/lookbook) in the Lookbook demo app and the associated [page files](https://github.com/allmarkedup/lookbook-demo/tree/main/test/components/docs) in the demo repo.
|
490
490
|
|
@@ -496,7 +496,7 @@ Pages must have either a `.html.erb` or a `.md.erb` file extension. All pages a
|
|
496
496
|
|
497
497
|
Pages can optionally make use of a **YAML frontmatter block** to customise the behaviour and content of the page itself.
|
498
498
|
|
499
|
-
An example page might look like this:
|
499
|
+
An example page might look like this:
|
500
500
|
|
501
501
|
```markdown
|
502
502
|
---
|
@@ -510,7 +510,7 @@ contents will be run through a Markdown parser/renderer before display.
|
|
510
510
|
Fenced code blocks are fully supported and will be highlighted appropriately.
|
511
511
|
|
512
512
|
ERB can be used in here.
|
513
|
-
The template will be rendered **before** being parsed as Markdown.
|
513
|
+
The template will be rendered **before** being parsed as Markdown.
|
514
514
|
|
515
515
|
You can can access data about the page using the `@page` variable.
|
516
516
|
The title of this page is "<%= @page.title %>".
|
@@ -656,6 +656,35 @@ The default language is `ruby`. To highlight a different language you need to sp
|
|
656
656
|
|
657
657
|
> Lookbook uses [Rouge](https://github.com/rouge-ruby/rouge) for syntax highlighting. You can find a [full list of supported languages here](https://github.com/rouge-ruby/rouge/blob/master/docs/Languages.md).
|
658
658
|
|
659
|
+
### Tabs
|
660
|
+
|
661
|
+
You can break up your page's content into tabs. If your avatar page is named `01_avatar.md.erb`, by declaring a page named `01_avatar[web].md.erb` it will create a **web** tab on the page. Tabs like normal Pages can contain embedded previews and code examples.
|
662
|
+
|
663
|
+
```
|
664
|
+
test/components/docs/
|
665
|
+
├── 01_avatar.md.erb
|
666
|
+
├── 01_avatar[design].md.erb
|
667
|
+
├── 01_avatar[mobile].md.erb
|
668
|
+
├── 01_avatar[web].md.erb
|
669
|
+
```
|
670
|
+
|
671
|
+
By declaring the `label` frontmatter you can change the label shown on the tab:
|
672
|
+
|
673
|
+
```
|
674
|
+
---
|
675
|
+
label: Website
|
676
|
+
---
|
677
|
+
```
|
678
|
+
|
679
|
+
If you want the tabs in a different order, you can use the `position` frontmatter:
|
680
|
+
|
681
|
+
```
|
682
|
+
---
|
683
|
+
label: Web
|
684
|
+
position: 1
|
685
|
+
---
|
686
|
+
```
|
687
|
+
|
659
688
|
---
|
660
689
|
|
661
690
|
### Pages configuration
|
@@ -743,10 +772,10 @@ If for some reason you wish to enable file watching or runtime preview annotatio
|
|
743
772
|
# config/environments/production.rb
|
744
773
|
|
745
774
|
# enable file-change listening
|
746
|
-
config.lookbook.listen = true
|
775
|
+
config.lookbook.listen = true
|
747
776
|
|
748
777
|
# enable runtime preview parsing
|
749
|
-
config.lookbook.runtime_parsing = true
|
778
|
+
config.lookbook.runtime_parsing = true
|
750
779
|
```
|
751
780
|
|
752
781
|
<h2 id="config">General Configuration</h2>
|
@@ -778,7 +807,7 @@ config.lookbook.listen_paths << Rails.root.join('app/other/directory')
|
|
778
807
|
If you want to change the favicon used by the Lookbook UI, you can provide a path to your own (or a data-uri string) using the `ui_favicon` option:
|
779
808
|
|
780
809
|
```ruby
|
781
|
-
config.lookbook.ui_favicon = "/path/to/my/favicon.png"
|
810
|
+
config.lookbook.ui_favicon = "/path/to/my/favicon.png"
|
782
811
|
```
|
783
812
|
|
784
813
|
> To disable the favicon entirely, set the value to `false`.
|
@@ -788,7 +817,7 @@ config.lookbook.ui_favicon = "/path/to/my/favicon.png"
|
|
788
817
|
Specify a project name to display in the top left of the UI (instead of the default "Lookbook"):
|
789
818
|
|
790
819
|
```ruby
|
791
|
-
config.lookbook.project_name = "My Project"
|
820
|
+
config.lookbook.project_name = "My Project"
|
792
821
|
```
|
793
822
|
|
794
823
|
> If you don't want to display a project name at all, set the value to `false`.
|
@@ -20,6 +20,7 @@ import copy from "./components/copy";
|
|
20
20
|
import code from "./components/code";
|
21
21
|
import sizes from "./components/sizes";
|
22
22
|
import embed from "./components/embed";
|
23
|
+
import pageTabs from "./components/page-tabs";
|
23
24
|
|
24
25
|
import initFilterStore from "./stores/filter";
|
25
26
|
import initLayoutStore from "./stores/layout";
|
@@ -61,6 +62,7 @@ Alpine.data("tabs", tabs);
|
|
61
62
|
Alpine.data("navItem", navItem);
|
62
63
|
Alpine.data("navGroup", navGroup);
|
63
64
|
Alpine.data("embed", embed);
|
65
|
+
Alpine.data("pageTabs", pageTabs);
|
64
66
|
|
65
67
|
// Init
|
66
68
|
|
@@ -1,5 +1,7 @@
|
|
1
1
|
module Lookbook
|
2
2
|
class PagesController < ApplicationController
|
3
|
+
helper_method :page_controller
|
4
|
+
|
3
5
|
def self.controller_path
|
4
6
|
"lookbook/pages"
|
5
7
|
end
|
@@ -7,7 +9,7 @@ module Lookbook
|
|
7
9
|
def index
|
8
10
|
landing = Lookbook.pages.find(&:landing) || Lookbook.pages.first
|
9
11
|
if landing.present?
|
10
|
-
redirect_to
|
12
|
+
redirect_to lookbook_page_path landing.lookup_path
|
11
13
|
else
|
12
14
|
@title = "Not found"
|
13
15
|
render "not_found"
|
@@ -45,11 +45,11 @@ module Lookbook
|
|
45
45
|
if @example
|
46
46
|
@preview = @example.preview
|
47
47
|
if params[:path] == @preview&.lookup_path
|
48
|
-
redirect_to
|
48
|
+
redirect_to lookbook_inspect_path "#{params[:path]}/#{@preview.default_example.name}"
|
49
49
|
end
|
50
50
|
else
|
51
51
|
first_example = Lookbook.previews.find(params[:path])&.examples&.first
|
52
|
-
redirect_to
|
52
|
+
redirect_to lookbook_inspect_path(first_example.lookup_path) if first_example
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
@@ -1,14 +1,14 @@
|
|
1
|
-
<div id="<%= id %>" x-data="embed" class="not-prose embed border border-gray-300 rounded-md overflow-hidden" @page:morphed.window="recaclulateIframeHeight">
|
1
|
+
<div id="<%= id %>" x-data="embed" class="not-prose embed border border-gray-300 rounded-md overflow-hidden" @page:morphed.window="recaclulateIframeHeight" @tab-switch.window="recaclulateIframeHeight">
|
2
2
|
<header class="px-3 py-2 flex items-center text-xs text-gray-400 bg-white border-b border-gray-300">
|
3
3
|
<div class="text-gray-500">
|
4
4
|
<%= example.preview.label %> (<%= example.label %>)
|
5
5
|
</div>
|
6
6
|
<div class="ml-auto flex items-center space-x-3">
|
7
|
-
<a href="<%=
|
7
|
+
<a href="<%= lookbook_inspect_path(example.path, params) %>" class="" x-tooltip.theme.lookbook="`View in Inspector`">
|
8
8
|
<%= icon "eye", size: 4, class: "hover:text-indigo-800" %>
|
9
9
|
</a>
|
10
10
|
<a
|
11
|
-
href="<%=
|
11
|
+
href="<%= lookbook_preview_path(example.path, params) %>"
|
12
12
|
target="_blank"
|
13
13
|
class="-top-px relative"
|
14
14
|
x-tooltip.theme.lookbook="`Open in new window`">
|
@@ -21,7 +21,7 @@
|
|
21
21
|
<iframe seamless
|
22
22
|
id="<%= id %>-iframe"
|
23
23
|
x-ref="iframe"
|
24
|
-
src="<%=
|
24
|
+
src="<%= lookbook_preview_path(example.path, params.merge(lookbook_embed: true)) %>"
|
25
25
|
class="min-w-full h-full w-px"
|
26
26
|
:class="{ 'pointer-events-none': reflowing }"
|
27
27
|
@load="recaclulateIframeHeight">
|
@@ -1,6 +1,6 @@
|
|
1
|
-
<nav id="nav" x-data="nav(<%= filterable %>)">
|
1
|
+
<nav id="nav-<%= items.class.describe_as %>" x-data="nav(<%= filterable %>)">
|
2
2
|
<% if items.any? %>
|
3
|
-
<ul x-ref="items" id="nav-<%= items.class.describe_as
|
3
|
+
<ul x-ref="items" id="nav-<%= items.class.describe_as %>-items">
|
4
4
|
<% items.each do |item| %>
|
5
5
|
<%= component "nav_#{item.type}", node: item %>
|
6
6
|
<% end %>
|
@@ -1,6 +1,6 @@
|
|
1
1
|
<% examples = node.examples.reject(&:hidden?) %>
|
2
2
|
<% if examples.many? %>
|
3
|
-
<%= component "nav_group", node: node, path:
|
3
|
+
<%= component "nav_group", node: node, path: lookbook_inspect_path(examples.first.path) do %>
|
4
4
|
<% examples.each do |example| %>
|
5
5
|
<%= component "nav_item", item: example, depth: example.hierarchy_depth + 1 %>
|
6
6
|
<% end %>
|
@@ -43,6 +43,32 @@
|
|
43
43
|
<div id="page-main-<%= @page.id %>" data-morph-strategy="replace">
|
44
44
|
<div class="prose max-w-none prose-a:text-indigo-900">
|
45
45
|
<%= @page_content %>
|
46
|
+
|
47
|
+
<% if @page.tabs.any? %>
|
48
|
+
<div
|
49
|
+
id="page-tabs"
|
50
|
+
x-data="pageTabs"
|
51
|
+
x-init="active = '<%= @page.tabs.first.tab %>'"
|
52
|
+
class="">
|
53
|
+
<nav class="flex border-b border-gray-300">
|
54
|
+
<% @page.tabs.each do |tab| %>
|
55
|
+
<button
|
56
|
+
class="px-5 py-2 font-bold border-b-2 hover:border-gray-500"
|
57
|
+
:class="active === '<%= tab.tab %>' ? '!border-gray-500 !cursor-default' : 'border-gray-50'"
|
58
|
+
x-on:click="changeTab('<%= tab.tab %>');$dispatch('tab-switch')">
|
59
|
+
<%= tab.label %>
|
60
|
+
</button>
|
61
|
+
<% end %>
|
62
|
+
</nav>
|
63
|
+
|
64
|
+
<% @page.tabs.each do |tab| %>
|
65
|
+
<div id="tab-<%= tab.tab %>" x-show="active === '<%= tab.tab %>'">
|
66
|
+
<%= page_controller.render_page(tab) %>
|
67
|
+
</div>
|
68
|
+
<% end %>
|
69
|
+
</div>
|
70
|
+
<% end %>
|
71
|
+
|
46
72
|
</div>
|
47
73
|
</div>
|
48
74
|
<% if @page.footer? %>
|
@@ -1 +1 @@
|
|
1
|
-
<iframe id="error-iframe" src="<%= url_for
|
1
|
+
<iframe id="error-iframe" src="<%= url_for lookbook_preview_path %>" frameborder="0" class=" h-screen w-full" seamless></iframe>
|
@@ -9,7 +9,7 @@
|
|
9
9
|
<iframe seamless
|
10
10
|
class="h-full w-full border border-gray-300"
|
11
11
|
:class="{ 'pointer-events-none': $store.layout.reflowing }"
|
12
|
-
src="<%=
|
12
|
+
src="<%= lookbook_preview_path(request.query_parameters.merge(lookbook_timestamp: Time.now)) %>"
|
13
13
|
<% if config.preview_srcdoc %>srcdoc="<%== srcdoc %>"<% end %>
|
14
14
|
frameborder="0"
|
15
15
|
x-data="sizes"
|
data/config/routes.rb
CHANGED
@@ -3,13 +3,13 @@ Lookbook::Engine.routes.draw do
|
|
3
3
|
mount Lookbook::Engine.websocket => Lookbook.config.cable_mount_path
|
4
4
|
end
|
5
5
|
|
6
|
-
root to: "application#index", as: :
|
6
|
+
root to: "application#index", as: :lookbook_home
|
7
7
|
|
8
8
|
if Lookbook::Features.enabled?(:pages)
|
9
|
-
get "/#{Lookbook.config.page_route}", to: "pages#index", as: :
|
10
|
-
get "/#{Lookbook.config.page_route}/*path", to: "pages#show", as: :
|
9
|
+
get "/#{Lookbook.config.page_route}", to: "pages#index", as: :lookbook_page_index
|
10
|
+
get "/#{Lookbook.config.page_route}/*path", to: "pages#show", as: :lookbook_page
|
11
11
|
end
|
12
12
|
|
13
|
-
get "/preview/*path", to: "previews#preview", as: :
|
14
|
-
get "/*path", to: "previews#show", as: :
|
13
|
+
get "/preview/*path", to: "previews#preview", as: :lookbook_preview
|
14
|
+
get "/*path", to: "previews#show", as: :lookbook_inspect
|
15
15
|
end
|
data/lib/lookbook/page.rb
CHANGED
@@ -16,17 +16,22 @@ module Lookbook
|
|
16
16
|
]
|
17
17
|
|
18
18
|
attr_reader :errors
|
19
|
+
attr_accessor :tabs
|
19
20
|
|
20
21
|
def initialize(path, base_path)
|
21
22
|
@pathname = Pathname.new path
|
22
23
|
@base_path = Pathname.new base_path
|
23
24
|
@options = nil
|
24
25
|
@errors = []
|
26
|
+
@tabs = []
|
25
27
|
end
|
26
28
|
|
27
29
|
def path
|
28
30
|
rel_path = @pathname.relative_path_from(@base_path)
|
29
|
-
|
31
|
+
|
32
|
+
_path = (rel_path.dirname.to_s == "." ? name : "#{rel_path.dirname}/#{name}")
|
33
|
+
_path.gsub!("[#{tab}]", "") if tab?
|
34
|
+
_path
|
30
35
|
end
|
31
36
|
|
32
37
|
def lookup_path
|
@@ -78,7 +83,16 @@ module Lookbook
|
|
78
83
|
end
|
79
84
|
|
80
85
|
def type
|
81
|
-
:page
|
86
|
+
tab? ? :tab : :page
|
87
|
+
end
|
88
|
+
|
89
|
+
def tab
|
90
|
+
matches = full_path.to_s.match(%r{\[(?<tab>\w+)\]})
|
91
|
+
matches ? remove_position_prefix(matches[:tab]) : nil
|
92
|
+
end
|
93
|
+
|
94
|
+
def tab?
|
95
|
+
tab.present?
|
82
96
|
end
|
83
97
|
|
84
98
|
def method_missing(method_name, *args, &block)
|
@@ -114,7 +128,7 @@ module Lookbook
|
|
114
128
|
end
|
115
129
|
@options = Lookbook.config.page_options.deep_merge(frontmatter).with_indifferent_access
|
116
130
|
@options[:id] = @options[:id] ? generate_id(@options[:id]) : generate_id(lookup_path)
|
117
|
-
@options[:label] ||= name.titleize
|
131
|
+
@options[:label] ||= (tab? ? tab : name).titleize
|
118
132
|
@options[:title] ||= @options[:label]
|
119
133
|
@options[:hidden] ||= false
|
120
134
|
@options[:landing] ||= false
|
@@ -143,12 +157,24 @@ module Lookbook
|
|
143
157
|
end
|
144
158
|
|
145
159
|
def all
|
146
|
-
pages =
|
147
|
-
|
148
|
-
|
149
|
-
|
160
|
+
pages, tabs =
|
161
|
+
Array(page_paths).flat_map do |dir|
|
162
|
+
Dir["#{dir}/**/*.html.*", "#{dir}/**/*.md.*"].sort.map do |page|
|
163
|
+
page = Lookbook::Page.new(page, dir)
|
164
|
+
end
|
165
|
+
end.partition { |page| page.type == :page }
|
166
|
+
|
167
|
+
sorted_pages = pages
|
168
|
+
.uniq { |page| page.path }
|
169
|
+
.sort_by { |page| [page.position, page.label] }
|
170
|
+
|
171
|
+
page_dict = sorted_pages.index_by(&:path)
|
172
|
+
sorted_tabs = tabs.sort_by { |tab| [tab.position, tab.label] }
|
173
|
+
|
174
|
+
sorted_tabs.each do |tab|
|
175
|
+
page_dict[tab.path].tabs << tab
|
150
176
|
end
|
151
|
-
|
177
|
+
|
152
178
|
PageCollection.new(sorted_pages)
|
153
179
|
end
|
154
180
|
|
data/lib/lookbook/utils.rb
CHANGED
@@ -6,7 +6,7 @@ module Lookbook
|
|
6
6
|
protected
|
7
7
|
|
8
8
|
def generate_id(*args)
|
9
|
-
parts = args.map { |arg| arg.to_s.parameterize.underscore }
|
9
|
+
parts = args.map { |arg| arg.to_s.force_encoding("UTF-8").parameterize.underscore }
|
10
10
|
parts.join("-").tr("/", "-").tr("_", "-").delete_prefix("-").delete_suffix("-").gsub("--", "-")
|
11
11
|
end
|
12
12
|
|
data/lib/lookbook/version.rb
CHANGED