lookbook 0.8.0 → 1.0.0.beta.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 +43 -830
- data/app/assets/lookbook/css/lookbook.css +55 -0
- data/app/assets/lookbook/css/themes/blue.css +42 -0
- data/app/assets/lookbook/css/themes/indigo.css +42 -0
- data/app/assets/lookbook/css/themes/zinc.css +42 -0
- data/app/assets/lookbook/css/{tooltip_theme.css → tooltip.css} +14 -8
- data/app/assets/lookbook/js/app.js +64 -61
- data/app/assets/lookbook/js/components/clipboard.js +47 -0
- data/app/assets/lookbook/js/components/tooltip.js +30 -0
- data/app/assets/lookbook/js/config.js +7 -4
- data/app/assets/lookbook/js/helpers/build.js +22 -0
- data/app/assets/lookbook/js/helpers/dom.js +45 -0
- data/app/assets/lookbook/js/helpers/layout.js +21 -0
- data/app/assets/lookbook/js/helpers/request.js +16 -0
- data/app/assets/lookbook/js/helpers/string.js +11 -0
- data/app/assets/lookbook/js/lib/socket.js +4 -3
- data/app/assets/lookbook/js/lib/tippy.js +8 -0
- data/app/assets/lookbook/js/lookbook.js +61 -0
- data/app/assets/lookbook/js/plugins/logger.js +39 -0
- data/app/assets/lookbook/js/stores/filter.js +2 -2
- data/app/assets/lookbook/js/stores/inspector.js +22 -16
- data/app/assets/lookbook/js/stores/layout.js +101 -5
- data/app/assets/lookbook/js/stores/nav.js +17 -16
- data/app/assets/lookbook/js/stores/pages.js +4 -2
- data/app/assets/lookbook/js/stores/settings.js +7 -0
- data/app/assets/lookbook/js/stores/workbench.js +29 -0
- data/app/components/lookbook/button/component.html.erb +28 -0
- data/app/components/lookbook/button/component.js +55 -0
- data/app/components/lookbook/button/component.rb +39 -0
- data/app/components/lookbook/button_group/component.html.erb +3 -0
- data/app/components/lookbook/button_group/component.rb +18 -0
- data/app/components/lookbook/code/component.css +57 -0
- data/app/components/lookbook/code/component.html.erb +10 -0
- data/app/components/lookbook/code/component.js +3 -0
- data/app/components/lookbook/code/component.rb +56 -0
- data/app/components/lookbook/code/highlight_github_light.css +217 -0
- data/app/components/lookbook/component.rb +41 -0
- data/app/components/lookbook/copy_button/component.html.erb +11 -0
- data/app/components/lookbook/copy_button/component.js +16 -0
- data/app/components/lookbook/copy_button/component.rb +23 -0
- data/app/components/lookbook/dimensions_display/component.html.erb +10 -0
- data/app/components/lookbook/dimensions_display/component.js +30 -0
- data/app/components/lookbook/dimensions_display/component.rb +18 -0
- data/app/components/lookbook/embed/component.html.erb +50 -0
- data/app/components/lookbook/embed/component.js +39 -0
- data/app/components/lookbook/embed/component.rb +22 -0
- data/app/components/lookbook/filter/component.html.erb +17 -0
- data/app/components/lookbook/filter/component.js +21 -0
- data/app/components/lookbook/filter/component.rb +15 -0
- data/app/components/lookbook/header/component.html.erb +79 -0
- data/app/components/lookbook/header/component.rb +9 -0
- data/app/components/lookbook/icon/component.css +11 -0
- data/app/components/lookbook/icon/component.html.erb +5 -0
- data/app/components/lookbook/icon/component.js +5 -0
- data/app/components/lookbook/icon/component.rb +23 -0
- data/app/components/lookbook/nav/component.html.erb +33 -0
- data/app/components/lookbook/nav/component.js +52 -0
- data/app/components/lookbook/nav/component.rb +37 -0
- data/app/components/lookbook/nav/item/component.html.erb +23 -0
- data/app/components/lookbook/nav/item/component.js +66 -0
- data/app/components/lookbook/nav/item/component.rb +84 -0
- data/app/components/lookbook/params_editor/component.html.erb +3 -0
- data/app/components/lookbook/params_editor/component.js +12 -0
- data/app/components/lookbook/params_editor/component.rb +11 -0
- data/app/components/lookbook/params_editor/field/component.html.erb +50 -0
- data/app/components/lookbook/params_editor/field/component.js +36 -0
- data/app/components/lookbook/params_editor/field/component.rb +41 -0
- data/app/components/lookbook/prose/component.css +12 -0
- data/app/components/lookbook/prose/component.html.erb +3 -0
- data/app/components/lookbook/prose/component.rb +26 -0
- data/app/components/lookbook/split_layout/component.html.erb +13 -0
- data/app/components/lookbook/split_layout/component.js +151 -0
- data/app/components/lookbook/split_layout/component.rb +11 -0
- data/app/components/lookbook/tabbed_content/component.html.erb +5 -0
- data/app/components/lookbook/tabbed_content/component.js +21 -0
- data/app/components/lookbook/tabbed_content/component.rb +20 -0
- data/app/components/lookbook/tabbed_content/section/component.html.erb +8 -0
- data/app/components/lookbook/tabbed_content/section/component.rb +9 -0
- data/app/components/lookbook/tabs/component.css +8 -0
- data/app/components/lookbook/tabs/component.html.erb +14 -0
- data/app/components/lookbook/tabs/component.js +107 -0
- data/app/components/lookbook/tabs/component.rb +30 -0
- data/app/components/lookbook/tabs/dropdown_tab/component.html.erb +14 -0
- data/app/components/lookbook/tabs/dropdown_tab/component.rb +16 -0
- data/app/components/lookbook/tabs/tab/component.html.erb +18 -0
- data/app/components/lookbook/tabs/tab/component.rb +16 -0
- data/app/components/lookbook/tag_component.rb +29 -0
- data/app/components/lookbook/toolbar/component.css +16 -0
- data/app/components/lookbook/toolbar/component.html.erb +5 -0
- data/app/components/lookbook/toolbar/component.rb +26 -0
- data/app/components/lookbook/viewport/component.css +11 -0
- data/app/components/lookbook/viewport/component.html.erb +57 -0
- data/app/{assets/lookbook/js/components/preview-window.js → components/lookbook/viewport/component.js} +57 -14
- data/app/components/lookbook/viewport/component.rb +21 -0
- data/app/controllers/lookbook/application_controller.rb +16 -5
- data/app/controllers/lookbook/pages_controller.rb +18 -8
- data/app/controllers/lookbook/previews_controller.rb +60 -23
- data/app/helpers/lookbook/application_helper.rb +5 -1
- data/app/helpers/lookbook/component_helper.rb +22 -10
- data/app/helpers/lookbook/output_helper.rb +8 -4
- data/app/helpers/lookbook/page_helper.rb +13 -21
- data/app/views/layouts/lookbook/application.html.erb +76 -28
- data/app/views/layouts/lookbook/inspector.html.erb +7 -0
- data/app/views/layouts/lookbook/page.html.erb +53 -0
- data/app/views/layouts/lookbook/shell.html.erb +64 -0
- data/app/views/layouts/lookbook/skeleton.html.erb +27 -10
- data/app/views/layouts/lookbook/standalone.html.erb +5 -0
- data/app/views/lookbook/404.html.erb +15 -0
- data/app/views/lookbook/error.html.erb +34 -34
- data/app/views/lookbook/index.html.erb +11 -6
- data/app/views/lookbook/pages/show.html.erb +29 -67
- data/app/views/{layouts/lookbook → lookbook}/preview.html.erb +3 -5
- data/app/views/lookbook/previews/panels/_notes.html.erb +19 -25
- data/app/views/lookbook/previews/panels/_output.html.erb +7 -18
- data/app/views/lookbook/previews/panels/_params.html.erb +13 -15
- data/app/views/lookbook/previews/panels/_preview.html.erb +6 -52
- data/app/views/lookbook/previews/panels/_source.html.erb +7 -16
- data/app/views/lookbook/previews/show.html.erb +130 -24
- data/config/routes.rb +5 -5
- data/lib/lookbook/code_formatter.rb +37 -13
- data/lib/lookbook/collection.rb +19 -16
- data/lib/lookbook/config.rb +125 -0
- data/lib/lookbook/engine.rb +79 -74
- data/lib/lookbook/entity.rb +47 -0
- data/lib/lookbook/error.rb +1 -2
- data/lib/lookbook/features.rb +1 -1
- data/lib/lookbook/markdown.rb +3 -4
- data/lib/lookbook/page.rb +21 -12
- data/lib/lookbook/page_collection.rb +8 -0
- data/lib/lookbook/params.rb +15 -4
- data/lib/lookbook/preview.rb +15 -6
- data/lib/lookbook/preview_collection.rb +8 -0
- data/lib/lookbook/preview_controller.rb +6 -2
- data/lib/lookbook/preview_example.rb +5 -6
- data/lib/lookbook/preview_group.rb +4 -9
- data/lib/lookbook/{code_inspector.rb → source_inspector.rb} +2 -2
- data/lib/lookbook/theme.rb +22 -0
- data/lib/lookbook/utils.rb +10 -2
- data/lib/lookbook/version.rb +1 -1
- data/lib/lookbook.rb +4 -1
- data/lib/tasks/lookbook_tasks.rake +12 -0
- data/public/lookbook-assets/css/app.css +2340 -1
- data/public/lookbook-assets/css/app.css.map +11 -1
- data/public/lookbook-assets/css/lookbook.css +3040 -0
- data/public/lookbook-assets/css/lookbook.css.map +1 -0
- data/public/lookbook-assets/css/themes/blue.css +44 -0
- data/public/lookbook-assets/css/themes/blue.css.map +1 -0
- data/public/lookbook-assets/css/themes/indigo.css +44 -0
- data/public/lookbook-assets/css/themes/indigo.css.map +1 -0
- data/public/lookbook-assets/css/themes/zinc.css +44 -0
- data/public/lookbook-assets/css/themes/zinc.css.map +1 -0
- data/public/lookbook-assets/js/app.js +10861 -1
- data/public/lookbook-assets/js/app.js.map +2571 -1
- data/public/lookbook-assets/js/embed.js +895 -1
- data/public/lookbook-assets/js/embed.js.map +1 -1
- data/public/lookbook-assets/js/lookbook.js +13529 -0
- data/public/lookbook-assets/js/lookbook.js.map +1 -0
- metadata +127 -114
- data/app/assets/lookbook/css/app.css +0 -161
- data/app/assets/lookbook/css/code_theme.css +0 -214
- data/app/assets/lookbook/js/components/app.js +0 -55
- data/app/assets/lookbook/js/components/code.js +0 -5
- data/app/assets/lookbook/js/components/copy.js +0 -20
- data/app/assets/lookbook/js/components/embed.js +0 -89
- data/app/assets/lookbook/js/components/filter.js +0 -35
- data/app/assets/lookbook/js/components/inspector.js +0 -66
- data/app/assets/lookbook/js/components/nav-group.js +0 -47
- data/app/assets/lookbook/js/components/nav-item.js +0 -29
- data/app/assets/lookbook/js/components/nav.js +0 -28
- data/app/assets/lookbook/js/components/page.js +0 -25
- data/app/assets/lookbook/js/components/param.js +0 -34
- data/app/assets/lookbook/js/components/sidebar.js +0 -18
- data/app/assets/lookbook/js/components/sizes.js +0 -16
- data/app/assets/lookbook/js/components/splitter.js +0 -25
- data/app/assets/lookbook/js/components/tabs.js +0 -52
- data/app/assets/lookbook/js/lib/split.js +0 -15
- data/app/assets/lookbook/js/stores/sidebar.js +0 -26
- data/app/views/layouts/lookbook/basic.html.erb +0 -7
- data/app/views/lookbook/components/_branding.html.erb +0 -8
- data/app/views/lookbook/components/_code.html.erb +0 -17
- data/app/views/lookbook/components/_copy_button.html.erb +0 -11
- data/app/views/lookbook/components/_drawer.html.erb +0 -112
- data/app/views/lookbook/components/_embed.html.erb +0 -39
- data/app/views/lookbook/components/_errors.html.erb +0 -13
- data/app/views/lookbook/components/_filter.html.erb +0 -18
- data/app/views/lookbook/components/_header.html.erb +0 -6
- data/app/views/lookbook/components/_icon.html.erb +0 -5
- data/app/views/lookbook/components/_nav.html.erb +0 -16
- data/app/views/lookbook/components/_nav_collection.html.erb +0 -5
- data/app/views/lookbook/components/_nav_group.html.erb +0 -14
- data/app/views/lookbook/components/_nav_item.html.erb +0 -24
- data/app/views/lookbook/components/_nav_page.html.erb +0 -22
- data/app/views/lookbook/components/_nav_preview.html.erb +0 -13
- data/app/views/lookbook/components/_not_found.html.erb +0 -11
- data/app/views/lookbook/components/_param.html.erb +0 -21
- data/app/views/lookbook/components/_preview.html.erb +0 -77
- data/app/views/lookbook/components/_sidebar.html.erb +0 -69
- data/app/views/lookbook/pages/not_found.html.erb +0 -15
- data/app/views/lookbook/previews/error.html.erb +0 -1
- data/app/views/lookbook/previews/inputs/_select.html.erb +0 -7
- data/app/views/lookbook/previews/inputs/_text.html.erb +0 -8
- data/app/views/lookbook/previews/inputs/_textarea.html.erb +0 -8
- data/app/views/lookbook/previews/inputs/_toggle.html.erb +0 -13
- 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,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,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
|
+
}
|