coveragebook_components 0.7.10 → 0.8.0.beta.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/build/coco/app.css +1065 -148
- data/app/assets/build/coco/app.js +255 -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 +43 -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 +65 -18
- data/app/components/coco/app/elements/alert/alert.html.erb +4 -4
- data/app/components/coco/app/elements/alert/alert.js +4 -3
- data/app/components/coco/app/elements/alert/alert.rb +10 -0
- data/app/components/coco/app/elements/button/button.css +58 -0
- data/app/components/coco/app/elements/button/button.rb +1 -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 +1 -0
- 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,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(md) {
|
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(md) {
|
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(md) {
|
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
|