coveragebook_components 0.7.10 → 0.8.0.beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/build/coco/app.css +1160 -151
- data/app/assets/build/coco/app.js +263 -47
- data/app/assets/build/coco/book.css +26 -0
- data/app/assets/css/app/tippy.css +4 -0
- data/app/components/coco/app/blocks/header/header.css +47 -0
- data/app/components/coco/app/blocks/header/header.html.erb +30 -0
- data/app/components/coco/app/blocks/header/header.js +11 -0
- data/app/components/coco/app/blocks/header/header.rb +35 -0
- data/app/components/coco/app/blocks/nav_drawer/nav_drawer.css +48 -3
- data/app/components/coco/app/blocks/nav_drawer/nav_drawer.html.erb +14 -6
- data/app/components/coco/app/blocks/nav_drawer/nav_drawer.js +18 -1
- data/app/components/coco/app/blocks/nav_drawer/nav_drawer.rb +26 -1
- data/app/components/coco/app/blocks/sidebar_nav/sidebar_nav.css +104 -0
- data/app/components/coco/app/blocks/sidebar_nav/sidebar_nav.html.erb +42 -0
- data/app/components/coco/app/blocks/sidebar_nav/sidebar_nav.js +28 -0
- data/app/components/coco/app/blocks/sidebar_nav/sidebar_nav.rb +28 -0
- data/app/components/coco/app/blocks/sidebar_nav_item/sidebar_nav_item.css +165 -0
- data/app/components/coco/app/blocks/sidebar_nav_item/sidebar_nav_item.html.erb +43 -0
- data/app/components/coco/app/blocks/sidebar_nav_item/sidebar_nav_item.js +41 -0
- data/app/components/coco/app/blocks/sidebar_nav_item/sidebar_nav_item.rb +98 -0
- data/app/components/coco/app/elements/alert/alert.css +114 -18
- data/app/components/coco/app/elements/alert/alert.html.erb +5 -4
- data/app/components/coco/app/elements/alert/alert.js +13 -3
- data/app/components/coco/app/elements/alert/alert.rb +10 -0
- data/app/components/coco/app/elements/button/button.css +59 -0
- data/app/components/coco/app/elements/button/button.rb +2 -1
- data/app/components/coco/app/elements/button_group/button_group.rb +4 -0
- data/app/components/coco/app/elements/color_picker/color_picker.rb +1 -1
- data/app/components/coco/app/elements/menu/menu.css +3 -1
- data/app/components/coco/app/elements/menu/menu.html.erb +1 -1
- data/app/components/coco/app/elements/menu/menu.rb +2 -1
- data/app/components/coco/app/elements/menu_items/user_profile/user_profile.css +22 -0
- data/app/components/coco/app/elements/menu_items/user_profile/user_profile.html.erb +17 -0
- data/app/components/coco/app/elements/menu_items/user_profile/user_profile.rb +20 -0
- data/app/components/coco/app/elements/notice/notice.css +4 -0
- data/app/components/coco/app/elements/snackbar/snackbar.css +8 -1
- data/app/components/coco/app/elements/snackbar/snackbar.rb +2 -2
- data/app/components/coco/app/elements/system_banner/system_banner.html.erb +2 -1
- data/app/components/coco/app/elements/system_banner/system_banner.js +35 -2
- data/app/components/coco/app/elements/system_banner/system_banner.rb +47 -3
- data/app/components/coco/app/layouts/application/application.css +104 -4
- data/app/components/coco/app/layouts/application/application.html.erb +28 -7
- data/app/components/coco/app/layouts/application/application.js +16 -0
- data/app/components/coco/app/layouts/application/application.rb +11 -3
- data/app/components/coco/base/avatar/avatar.css +25 -0
- data/app/components/coco/base/avatar/avatar.rb +20 -0
- data/app/components/coco/base/modal/modal.html.erb +1 -1
- data/app/components/coco/concerns/accepts_tag_attributes.rb +6 -2
- data/app/components/coco/concerns/acts_as_button_group.rb +5 -0
- data/app/helpers/coco/app_helper.rb +16 -0
- data/app/helpers/coco/base_helper.rb +4 -0
- data/config/tokens.cjs +4 -1
- data/lib/coco.rb +1 -1
- metadata +22 -10
- data/app/components/coco/app/blocks/banner/banner.css +0 -5
- data/app/components/coco/app/blocks/banner/banner.rb +0 -8
- data/app/components/coco/app/blocks/nav_bar/nav_bar.css +0 -51
- data/app/components/coco/app/blocks/nav_bar/nav_bar.html.erb +0 -23
- data/app/components/coco/app/blocks/nav_bar/nav_bar.js +0 -31
- data/app/components/coco/app/blocks/nav_bar/nav_bar.rb +0 -19
@@ -2,6 +2,23 @@ import { CocoComponent } from "@js/coco";
|
|
2
2
|
|
3
3
|
export default CocoComponent("appNavDrawer", () => {
|
4
4
|
return {
|
5
|
-
|
5
|
+
active: false,
|
6
|
+
|
7
|
+
init() {
|
8
|
+
this.$watch("drawerOpen", (open) => {
|
9
|
+
if (open) {
|
10
|
+
this.$refs.content.scrollTop = 0;
|
11
|
+
setTimeout(() => {
|
12
|
+
this.active = true;
|
13
|
+
}, 200);
|
14
|
+
} else {
|
15
|
+
this.active = false;
|
16
|
+
}
|
17
|
+
});
|
18
|
+
},
|
19
|
+
|
20
|
+
close() {
|
21
|
+
this.drawerOpen = false;
|
22
|
+
},
|
6
23
|
};
|
7
24
|
});
|
@@ -2,7 +2,32 @@ module Coco
|
|
2
2
|
module App
|
3
3
|
module Blocks
|
4
4
|
class NavDrawer < Coco::Component
|
5
|
-
|
5
|
+
renders_many :items, types: {
|
6
|
+
html: ->(&block) { block.call },
|
7
|
+
divider: ->(&block) { tag.div class: "nav-drawer-divider" },
|
8
|
+
heading: ->(text, **kwargs, &block) do
|
9
|
+
tag.h4(text, class: "nav-drawer-heading")
|
10
|
+
end,
|
11
|
+
button: ->(*args, **kwargs, &block) do
|
12
|
+
coco_button(*args, **kwargs, theme: nil, size: :md, fit: :full, class: "nav-drawer-button", &block)
|
13
|
+
end
|
14
|
+
}
|
15
|
+
|
16
|
+
def with_divider(...)
|
17
|
+
with_item_divider(...)
|
18
|
+
end
|
19
|
+
|
20
|
+
def with_html(...)
|
21
|
+
with_item_html(...)
|
22
|
+
end
|
23
|
+
|
24
|
+
def with_button(...)
|
25
|
+
with_item_button(...)
|
26
|
+
end
|
27
|
+
|
28
|
+
def with_heading(...)
|
29
|
+
with_item_heading(...)
|
30
|
+
end
|
6
31
|
end
|
7
32
|
end
|
8
33
|
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
@layer components {
|
2
|
+
[data-coco][data-component="app-sidebar-nav"] {
|
3
|
+
@apply bg-background-dark-2 antialiased;
|
4
|
+
@apply w-full h-14 grid grid-rows-1;
|
5
|
+
grid-template-columns: repeat(3, minmax(0, 1fr)) minmax(0, 1fr);
|
6
|
+
|
7
|
+
.nav-action {
|
8
|
+
.nav-item-label {
|
9
|
+
@apply hidden !text-content-primary-inverse-vivid;
|
10
|
+
}
|
11
|
+
}
|
12
|
+
|
13
|
+
.nav-actions-button {
|
14
|
+
@apply bg-content-primary-inverse-vivid transition-all text-content-light-1;
|
15
|
+
@apply h-10 w-10 flex items-center justify-center mx-auto rounded-full cursor-pointer;
|
16
|
+
|
17
|
+
&:hover {
|
18
|
+
transform: scale(1.05);
|
19
|
+
}
|
20
|
+
|
21
|
+
.coco-icon {
|
22
|
+
@apply h-6 w-6;
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
.nav-item {
|
27
|
+
@apply hidden sm:contents h-full justify-center w-full;
|
28
|
+
}
|
29
|
+
|
30
|
+
.mobile-nav-item {
|
31
|
+
@apply flex sm:contents;
|
32
|
+
}
|
33
|
+
|
34
|
+
@media screen(sm) {
|
35
|
+
@apply sidebar-nav-vertical-condensed;
|
36
|
+
}
|
37
|
+
|
38
|
+
@media screen(lg) {
|
39
|
+
@apply sidebar-nav-vertical;
|
40
|
+
}
|
41
|
+
|
42
|
+
@media screen(letterbox) {
|
43
|
+
@apply sidebar-nav-vertical-condensed;
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
.sidebar-nav-action {
|
48
|
+
@apply flex items-start p-1;
|
49
|
+
|
50
|
+
.sidebar-nav-action-icon {
|
51
|
+
@apply flex-none mr-3 text-content-light-1;
|
52
|
+
}
|
53
|
+
|
54
|
+
.sidebar-nav-action-detail {
|
55
|
+
@apply w-full text-left;
|
56
|
+
}
|
57
|
+
|
58
|
+
.sidebar-nav-action-label {
|
59
|
+
@apply mb-0.5 font-semibold text-content-light-1;
|
60
|
+
}
|
61
|
+
|
62
|
+
.sidebar-nav-action-description {
|
63
|
+
@apply text-para-xs;
|
64
|
+
}
|
65
|
+
}
|
66
|
+
|
67
|
+
.sidebar-nav-menu a.sidebar-nav-actions-item {
|
68
|
+
width: 320px;
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
@layer utilities {
|
73
|
+
.sidebar-nav-vertical-condensed {
|
74
|
+
@apply block w-18 h-full;
|
75
|
+
|
76
|
+
.nav-action .nav-item-label {
|
77
|
+
@apply block;
|
78
|
+
}
|
79
|
+
|
80
|
+
.nav-actions-button {
|
81
|
+
@apply h-14 w-14 mb-2;
|
82
|
+
|
83
|
+
.coco-icon {
|
84
|
+
@apply w-8 h-8;
|
85
|
+
}
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
.sidebar-nav-vertical {
|
90
|
+
@apply block w-24 h-full;
|
91
|
+
|
92
|
+
.nav-action .nav-item-label {
|
93
|
+
@apply block;
|
94
|
+
}
|
95
|
+
|
96
|
+
.nav-actions-button {
|
97
|
+
@apply h-[72px] w-[72px];
|
98
|
+
|
99
|
+
.coco-icon {
|
100
|
+
@apply h-10 w-10;
|
101
|
+
}
|
102
|
+
}
|
103
|
+
}
|
104
|
+
}
|
@@ -0,0 +1,42 @@
|
|
1
|
+
<%= render component_tag(:nav, x: {data: "appSidebarNav"}) do %>
|
2
|
+
<% if actions? %>
|
3
|
+
<div class="nav-item mobile-nav-item nav-action">
|
4
|
+
<%= render Coco::App::Blocks::SidebarNavItem.new(label: "Add", emphasise: true) do |item| %>
|
5
|
+
<% item.with_icon do %>
|
6
|
+
<span class="nav-actions-button">
|
7
|
+
<%= coco_icon :plus, size: :xl %>
|
8
|
+
</span>
|
9
|
+
<% end %>
|
10
|
+
|
11
|
+
<% item.with_menu do %>
|
12
|
+
<% actions_data.each do |action| %>
|
13
|
+
<%= coco_link(action[:href],
|
14
|
+
**action.except(:label, :description, :href, :icon),
|
15
|
+
theme: nil,
|
16
|
+
class: "sidebar-nav-menu-item sidebar-nav-actions-item") do %>
|
17
|
+
<div class="sidebar-nav-action">
|
18
|
+
<div class="sidebar-nav-action-icon">
|
19
|
+
<%= coco_icon(action[:icon], size: :md) %>
|
20
|
+
</div>
|
21
|
+
<div class="sidebar-nav-action-detail">
|
22
|
+
<h4 class="sidebar-nav-action-label">
|
23
|
+
<%= action[:label] %>
|
24
|
+
</h4>
|
25
|
+
<% if action.key?(:description) %>
|
26
|
+
<div class="sidebar-nav-action-description">
|
27
|
+
<%= raw action[:description] %>
|
28
|
+
</div>
|
29
|
+
<% end %>
|
30
|
+
</div>
|
31
|
+
</div>
|
32
|
+
<% end %>
|
33
|
+
<% end %>
|
34
|
+
<% end %>
|
35
|
+
<% end %>
|
36
|
+
</div>
|
37
|
+
<% end %>
|
38
|
+
|
39
|
+
<% items.each do |item| %>
|
40
|
+
<%= item %>
|
41
|
+
<% end %>
|
42
|
+
<% end %>
|
@@ -0,0 +1,28 @@
|
|
1
|
+
import tokens from "@config/tokens.cjs";
|
2
|
+
import { CocoComponent } from "@js/coco";
|
3
|
+
|
4
|
+
const mobileMaxWidth = parseInt(tokens.app.screens.sm, 10);
|
5
|
+
|
6
|
+
export default CocoComponent("appSidebarNav", () => {
|
7
|
+
return {
|
8
|
+
sizeObserver: null,
|
9
|
+
mobileLayout: true,
|
10
|
+
|
11
|
+
init() {
|
12
|
+
this.sizeObserver = new ResizeObserver(
|
13
|
+
Alpine.throttle((entries) => {
|
14
|
+
this.$nextTick(() => {
|
15
|
+
const bodyWidth = entries[0].contentRect.width;
|
16
|
+
this.mobileLayout = bodyWidth < mobileMaxWidth;
|
17
|
+
});
|
18
|
+
}, 20)
|
19
|
+
);
|
20
|
+
|
21
|
+
this.sizeObserver.observe(document.documentElement);
|
22
|
+
},
|
23
|
+
|
24
|
+
destroy() {
|
25
|
+
this.sizeObserver && this.sizeObserver.disconnect();
|
26
|
+
},
|
27
|
+
};
|
28
|
+
});
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Coco
|
2
|
+
module App
|
3
|
+
module Blocks
|
4
|
+
class SidebarNav < Coco::Component
|
5
|
+
renders_many :actions, ->(label, href, icon:, **kwargs) do
|
6
|
+
@actions_data << {label: label, href: href, icon: icon, **kwargs}
|
7
|
+
end
|
8
|
+
|
9
|
+
renders_many :items, ->(label, href, show_on_mobile: true, **kwargs, &block) do
|
10
|
+
tag.div class: ["nav-item", ("mobile-nav-item" if show_on_mobile)] do
|
11
|
+
render Coco::App::Blocks::SidebarNavItem.new(
|
12
|
+
label: label,
|
13
|
+
href: href,
|
14
|
+
active: helpers.current_page?(href),
|
15
|
+
**kwargs
|
16
|
+
), &block
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_reader :actions_data
|
21
|
+
|
22
|
+
def initialize(**)
|
23
|
+
@actions_data = []
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,165 @@
|
|
1
|
+
@layer components {
|
2
|
+
[data-coco][data-component="app-sidebar-nav-item"] {
|
3
|
+
@apply bg-background-dark-2 text-content-dark-muted text-center no-underline transition-colors flex-none;
|
4
|
+
@apply flex items-center justify-center px-4 w-full flex-col;
|
5
|
+
|
6
|
+
&[href] {
|
7
|
+
@apply hover:text-content-light-1;
|
8
|
+
}
|
9
|
+
|
10
|
+
.nav-item-icon {
|
11
|
+
@apply block mx-auto transition-colors;
|
12
|
+
@apply w-6 h-6;
|
13
|
+
}
|
14
|
+
|
15
|
+
.nav-item-label {
|
16
|
+
@apply block font-semibold text-label-xxs transition-colors mt-0.5;
|
17
|
+
}
|
18
|
+
|
19
|
+
&.emphasised {
|
20
|
+
.nav-item-icon {
|
21
|
+
@apply sm:text-content-primary-inverse-vivid;
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
&.active {
|
26
|
+
@apply text-content-light-1;
|
27
|
+
}
|
28
|
+
|
29
|
+
&:hover {
|
30
|
+
.nav-item-icon {
|
31
|
+
@apply text-content-light-1;
|
32
|
+
}
|
33
|
+
|
34
|
+
&.emphasised .nav-item-icon {
|
35
|
+
@apply sm:text-content-primary-inverse-vivid;
|
36
|
+
}
|
37
|
+
|
38
|
+
.nav-item-label {
|
39
|
+
@apply text-content-light-1;
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
@media screen(sm) {
|
44
|
+
@apply sidebar-nav-item-vertical-condensed;
|
45
|
+
}
|
46
|
+
|
47
|
+
@media screen(lg) {
|
48
|
+
@apply sidebar-nav-item-vertical;
|
49
|
+
}
|
50
|
+
|
51
|
+
@media screen(letterbox) {
|
52
|
+
@apply sidebar-nav-item-vertical-condensed;
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
.sidebar-nav-menu {
|
57
|
+
@apply bg-content-dark-2 shadow-md sm:rounded-r-md overflow-hidden divide-y divide-content-dark-muted/20;
|
58
|
+
|
59
|
+
[data-placement="bottom"] & {
|
60
|
+
@apply rounded-b-md;
|
61
|
+
}
|
62
|
+
|
63
|
+
[data-placement="top"] & {
|
64
|
+
@apply rounded-t-md;
|
65
|
+
}
|
66
|
+
|
67
|
+
.sidebar-nav-menu-select {
|
68
|
+
@apply focus:ring-0 bg-transparent hover:bg-content-dark-1 active:bg-content-dark-1 border-0 text-content-light-2 w-full font-semibold;
|
69
|
+
}
|
70
|
+
|
71
|
+
.sidebar-nav-menu-item {
|
72
|
+
@apply flex w-full items-center p-3 text-center no-underline bg-content-dark-2 text-content-dark-muted transition;
|
73
|
+
}
|
74
|
+
|
75
|
+
.coco-link.sidebar-nav-menu-item {
|
76
|
+
@apply hover:bg-content-dark-1;
|
77
|
+
}
|
78
|
+
|
79
|
+
.sidebar-nav-menu-item-text {
|
80
|
+
@apply truncate min-w-0 font-semibold text-content-light-1 transition-colors;
|
81
|
+
}
|
82
|
+
|
83
|
+
.sidebar-nav-menu-item-qualifier {
|
84
|
+
@apply ml-auto text-label-sm flex-none pl-4;
|
85
|
+
}
|
86
|
+
|
87
|
+
@apply sidebar-nav-menu-large;
|
88
|
+
|
89
|
+
@media screen(sm) {
|
90
|
+
@apply sidebar-nav-menu-small;
|
91
|
+
}
|
92
|
+
|
93
|
+
@media screen(lg) {
|
94
|
+
@apply sidebar-nav-menu-large;
|
95
|
+
}
|
96
|
+
|
97
|
+
@media screen(letterbox) {
|
98
|
+
@apply sidebar-nav-menu-small;
|
99
|
+
}
|
100
|
+
}
|
101
|
+
}
|
102
|
+
|
103
|
+
@layer utilities {
|
104
|
+
.sidebar-nav-item-vertical-condensed {
|
105
|
+
@apply block px-2 py-4;
|
106
|
+
|
107
|
+
&[href] {
|
108
|
+
@apply hover:bg-content-dark-1;
|
109
|
+
}
|
110
|
+
|
111
|
+
.nav-item-icon {
|
112
|
+
@apply w-7 h-7;
|
113
|
+
}
|
114
|
+
|
115
|
+
.nav-item-label {
|
116
|
+
@apply mt-1 text-label-xxs;
|
117
|
+
}
|
118
|
+
|
119
|
+
&.active {
|
120
|
+
@apply bg-background-dark-3 hover:bg-background-dark-3 text-content-light-1;
|
121
|
+
}
|
122
|
+
}
|
123
|
+
|
124
|
+
.sidebar-nav-item-vertical {
|
125
|
+
@apply py-5;
|
126
|
+
|
127
|
+
&[href] {
|
128
|
+
@apply hover:bg-content-dark-1;
|
129
|
+
}
|
130
|
+
|
131
|
+
.nav-item-icon {
|
132
|
+
@apply w-8 h-8;
|
133
|
+
}
|
134
|
+
|
135
|
+
.nav-item-label {
|
136
|
+
@apply text-label-xs;
|
137
|
+
}
|
138
|
+
|
139
|
+
&.active {
|
140
|
+
@apply bg-background-dark-3 hover:bg-background-dark-3 text-content-light-1;
|
141
|
+
}
|
142
|
+
}
|
143
|
+
|
144
|
+
.sidebar-nav-menu-small {
|
145
|
+
.sidebar-nav-menu-select {
|
146
|
+
@apply text-sm;
|
147
|
+
}
|
148
|
+
|
149
|
+
.sidebar-nav-menu-item {
|
150
|
+
@apply text-sm;
|
151
|
+
width: 240px;
|
152
|
+
}
|
153
|
+
}
|
154
|
+
|
155
|
+
.sidebar-nav-menu-large {
|
156
|
+
.sidebar-nav-menu-select {
|
157
|
+
@apply text-base;
|
158
|
+
}
|
159
|
+
|
160
|
+
.sidebar-nav-menu-item {
|
161
|
+
@apply text-base;
|
162
|
+
width: 280px;
|
163
|
+
}
|
164
|
+
}
|
165
|
+
}
|
@@ -0,0 +1,43 @@
|
|
1
|
+
<%= render component_tag(
|
2
|
+
x: {
|
3
|
+
data: "appSidebarNavItem",
|
4
|
+
"on:click": "if (menu) $event.preventDefault()"
|
5
|
+
},
|
6
|
+
class: {
|
7
|
+
active: active?,
|
8
|
+
emphasised: emphasise?
|
9
|
+
}) do %>
|
10
|
+
<%= icon %>
|
11
|
+
<label class="nav-item-label">
|
12
|
+
<%= label %>
|
13
|
+
</label>
|
14
|
+
<% if menu? || menu_items? %>
|
15
|
+
<template x-ref="menu">
|
16
|
+
<div class="sidebar-nav-menu" x-cloak>
|
17
|
+
<% if menu? %>
|
18
|
+
<%= menu %>
|
19
|
+
<% else %>
|
20
|
+
<%= safe_join(menu_items) %>
|
21
|
+
|
22
|
+
<% if dropdown_menu_items.any? %>
|
23
|
+
<select
|
24
|
+
x-data
|
25
|
+
class="sidebar-nav-menu-select"
|
26
|
+
@change="$dispatch('navigate', {url: $el.value})">
|
27
|
+
<% if menu_select_placeholder.present? %>
|
28
|
+
<option disabled="disabled" selected="selected"><%= menu_select_placeholder %></option>
|
29
|
+
<% end %>
|
30
|
+
<% dropdown_menu_items.each do |item| %>
|
31
|
+
<option value="<%= item[:href] %>">
|
32
|
+
<%= item[:label] %> <%= "(#{item[:qualifier]})" if item[:qualifier].present? %>
|
33
|
+
</option>
|
34
|
+
<% end %>
|
35
|
+
</select>
|
36
|
+
<% end %>
|
37
|
+
|
38
|
+
<%= menu_action %>
|
39
|
+
<% end %>
|
40
|
+
</div>
|
41
|
+
</template>
|
42
|
+
<% end %>
|
43
|
+
<% end %>
|
@@ -0,0 +1,41 @@
|
|
1
|
+
import tippy from "@libs/tippy";
|
2
|
+
import { CocoComponent } from "@js/coco";
|
3
|
+
|
4
|
+
export default CocoComponent("appSidebarNavItem", () => {
|
5
|
+
return {
|
6
|
+
menu: null,
|
7
|
+
|
8
|
+
init() {
|
9
|
+
if (this.$refs.menu) {
|
10
|
+
this.menu = tippy(this.$el, {
|
11
|
+
theme: "coco-naked-dropdown",
|
12
|
+
placement: this.menuPlacement,
|
13
|
+
arrow: false,
|
14
|
+
offset: [0, 0],
|
15
|
+
trigger: "click",
|
16
|
+
interactive: true,
|
17
|
+
maxWidth: null,
|
18
|
+
content: () => {
|
19
|
+
return this.$refs.menu.innerHTML;
|
20
|
+
},
|
21
|
+
});
|
22
|
+
}
|
23
|
+
|
24
|
+
this.$watch("mobileLayout", () => {
|
25
|
+
this.onOrientationChange();
|
26
|
+
});
|
27
|
+
},
|
28
|
+
|
29
|
+
onOrientationChange() {
|
30
|
+
if (this.menu) {
|
31
|
+
this.menu.setProps({
|
32
|
+
placement: this.menuPlacement,
|
33
|
+
});
|
34
|
+
}
|
35
|
+
},
|
36
|
+
|
37
|
+
get menuPlacement() {
|
38
|
+
return this.mobileLayout ? "top" : "right-start";
|
39
|
+
},
|
40
|
+
};
|
41
|
+
});
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module Coco
|
2
|
+
module App
|
3
|
+
module Blocks
|
4
|
+
class SidebarNavItem < Coco::Component
|
5
|
+
tag_name :a
|
6
|
+
tag_attr :href
|
7
|
+
|
8
|
+
renders_one :icon
|
9
|
+
renders_one :menu
|
10
|
+
|
11
|
+
renders_many :menu_items, ->(label, href, **kwargs) do
|
12
|
+
data = {label: label, href: href, **kwargs}
|
13
|
+
if menu_items.size < max_menu_items
|
14
|
+
SidebarNavMenuItem.new(**data)
|
15
|
+
else
|
16
|
+
dropdown_menu_items << data
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
renders_one :menu_action, ->(*args, **kwargs, &block) do
|
22
|
+
tag.div class: "sidebar-nav-menu-item" do
|
23
|
+
coco_button(*args, theme: :primary, size: :sm, fit: :full, **kwargs, &block)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
before_render do
|
28
|
+
if @icon && !icon?
|
29
|
+
with_icon do
|
30
|
+
tag.span(class: "nav-item-icon") do
|
31
|
+
coco_icon(@icon, size: :full)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
attr_reader :label, :tooltip, :dropdown_menu_items, :max_menu_items
|
38
|
+
|
39
|
+
def initialize(label:, icon: nil, emphasise: false, active: false, tooltip: nil, menu_select_placeholder: nil, max_menu_items: 6, **)
|
40
|
+
@label = label
|
41
|
+
@icon = icon
|
42
|
+
@emphasise = emphasise
|
43
|
+
@tooltip = tooltip
|
44
|
+
@active = active
|
45
|
+
@max_menu_items = max_menu_items
|
46
|
+
@menu_select_placeholder = menu_select_placeholder
|
47
|
+
@dropdown_menu_items = []
|
48
|
+
end
|
49
|
+
|
50
|
+
def tooltip?
|
51
|
+
tooltip.present?
|
52
|
+
end
|
53
|
+
|
54
|
+
def active?
|
55
|
+
@active == true
|
56
|
+
end
|
57
|
+
|
58
|
+
def emphasise?
|
59
|
+
@emphasise == true
|
60
|
+
end
|
61
|
+
|
62
|
+
def menu_select_placeholder
|
63
|
+
@menu_select_placeholder || "More items..."
|
64
|
+
end
|
65
|
+
|
66
|
+
class SidebarNavMenuItem < Coco::Component
|
67
|
+
attr_reader :icon, :href, :modal
|
68
|
+
|
69
|
+
def initialize(label:, href:, icon: nil, modal: nil, qualifier: nil, **)
|
70
|
+
@label = label
|
71
|
+
@href = href
|
72
|
+
@icon = icon
|
73
|
+
@modal = modal
|
74
|
+
@qualifier = qualifier
|
75
|
+
end
|
76
|
+
|
77
|
+
def call
|
78
|
+
coco_link(href, theme: nil, modal: modal, class: "sidebar-nav-menu-item") do
|
79
|
+
label
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def label
|
84
|
+
tag.span(@label, class: "sidebar-nav-menu-item-text") + qualifier
|
85
|
+
end
|
86
|
+
|
87
|
+
def qualifier
|
88
|
+
if @icon || @qualifier
|
89
|
+
tag.span(class: "sidebar-nav-menu-item-qualifier") do
|
90
|
+
@icon ? coco_icon(icon, size: :sm) : @qualifier
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|