coveragebook_components 0.7.9 → 0.8.0.beta.1
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 +1134 -165
- data/app/assets/build/coco/app.js +307 -49
- data/app/assets/build/coco/book.css +55 -9
- data/app/assets/build/coco/book.js +24 -2
- data/app/assets/css/app/tippy.css +4 -0
- data/app/assets/css/base/base.css +12 -0
- data/app/assets/css/base/components/coco.css +0 -3
- data/app/assets/js/app/setup.js +22 -0
- data/app/assets/js/app.js +2 -0
- data/app/assets/js/helpers/location.js +9 -0
- data/app/assets/js/libs/tippy/index.js +7 -2
- 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 +20 -5
- data/app/components/coco/app/elements/alert/alert.js +4 -3
- data/app/components/coco/app/elements/alert/alert.rb +16 -6
- data/app/components/coco/app/elements/button/button.css +87 -5
- data/app/components/coco/app/elements/button/button.rb +3 -1
- data/app/components/coco/app/elements/button_group/button_group.rb +4 -0
- data/app/components/coco/app/elements/button_to/button_to.css +5 -1
- data/app/components/coco/app/elements/button_to/button_to.rb +8 -1
- data/app/components/coco/app/elements/color_picker/color_picker.rb +1 -1
- data/app/components/coco/app/elements/menu/menu.css +5 -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_button/menu_button.html.erb +6 -0
- data/app/components/coco/app/elements/menu_button/menu_button.rb +8 -9
- 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/notice/notice.rb +2 -2
- 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/icon/icon.css +6 -2
- data/app/components/coco/base/icon/icon.rb +1 -1
- data/app/components/coco/base/modal/modal.css +2 -1
- data/app/components/coco/base/modal/modal.html.erb +1 -1
- data/app/components/coco/base/modal/modal.js +2 -0
- data/app/components/coco/base/modal_lightbox/modal_lightbox.js +2 -2
- data/app/components/coco/base/placeholder/placeholder.css +15 -1
- data/app/components/coco/base/placeholder/placeholder.rb +2 -0
- data/app/components/coco/concerns/accepts_tag_attributes.rb +6 -2
- data/app/components/coco/concerns/acts_as_button_group.rb +30 -12
- data/app/helpers/coco/app_helper.rb +26 -2
- data/app/helpers/coco/base_helper.rb +6 -0
- data/app/helpers/coco/url_helper.rb +5 -1
- data/config/tailwind.base.config.cjs +3 -0
- data/config/tokens.cjs +6 -0
- data/lib/coco.rb +1 -1
- metadata +24 -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
|
@@ -10,10 +10,22 @@
|
|
|
10
10
|
@import "./components/coco";
|
|
11
11
|
|
|
12
12
|
@layer base {
|
|
13
|
+
:root {
|
|
14
|
+
--app-height: 100%;
|
|
15
|
+
}
|
|
16
|
+
|
|
13
17
|
html {
|
|
14
18
|
@apply font-body scroll-smooth motion-safe:scroll-auto text-content-dark-1;
|
|
15
19
|
}
|
|
16
20
|
|
|
21
|
+
html.app-layout,
|
|
22
|
+
html.app-layout body {
|
|
23
|
+
width: 100vw;
|
|
24
|
+
height: 100vh;
|
|
25
|
+
height: var(—-app-height);
|
|
26
|
+
overflow: hidden;
|
|
27
|
+
}
|
|
28
|
+
|
|
17
29
|
a {
|
|
18
30
|
@apply text-current underline underline-offset-2;
|
|
19
31
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { navigateTo } from "@helpers/location";
|
|
2
|
+
|
|
3
|
+
// Global JS navigation handler.
|
|
4
|
+
// Optionally uses Turbo for the page navigation.
|
|
5
|
+
window.addEventListener("navigate", (event) => {
|
|
6
|
+
const { url, turbo, action } = event.detail;
|
|
7
|
+
if (url) {
|
|
8
|
+
navigateTo(url, { turbo, action });
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
// Uodate the value of the `--app-height` css variable
|
|
13
|
+
// when the viewport size changes. To help work around the
|
|
14
|
+
// issues when using 100vh on mobile safari (https://medium.com/quick-code/100vh-problem-with-ios-safari-92ab23c852a8)
|
|
15
|
+
function setAppHeightProperty() {
|
|
16
|
+
document.documentElement.style.setProperty(
|
|
17
|
+
"--app-height",
|
|
18
|
+
`${window.innerHeight}px`
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
window.addEventListener("resize", setAppHeightProperty);
|
|
22
|
+
setAppHeightProperty();
|
data/app/assets/js/app.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import tippy, {
|
|
1
|
+
import tippy, {
|
|
2
|
+
createSingleton,
|
|
3
|
+
followCursor,
|
|
4
|
+
roundArrow,
|
|
5
|
+
hideAll,
|
|
6
|
+
} from "tippy.js";
|
|
2
7
|
import hideOnEsc from "./plugins/hide_on_esc";
|
|
3
8
|
|
|
4
9
|
tippy.setDefaultProps({
|
|
@@ -9,4 +14,4 @@ tippy.setDefaultProps({
|
|
|
9
14
|
});
|
|
10
15
|
|
|
11
16
|
export default tippy;
|
|
12
|
-
export { tippy, createSingleton, hideOnEsc, followCursor };
|
|
17
|
+
export { tippy, createSingleton, hideOnEsc, followCursor, hideAll };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
@layer components {
|
|
2
|
+
[data-coco][data-component="app-header"] {
|
|
3
|
+
@apply @container;
|
|
4
|
+
|
|
5
|
+
.header-content {
|
|
6
|
+
@apply h-14 flex items-center bg-background-header px-app;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
.header-logo {
|
|
10
|
+
@apply flex-none mr-6;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.header-logo-no-wordmark {
|
|
14
|
+
@apply h-7 xs:hidden translate-x-1;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.header-logo-full {
|
|
18
|
+
@apply hidden xs:block h-7;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.header-links {
|
|
22
|
+
@apply flex items-center w-full;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.header-link-group {
|
|
26
|
+
@apply items-center gap-x-6;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.header-secondary {
|
|
30
|
+
@apply ml-auto translate-x-2 sm:translate-x-[17px];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.header-mobile-controls {
|
|
34
|
+
@apply flex @4xl:hidden items-center ml-auto translate-x-2 sm:translate-x-4 md:translate-x-6;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
&.with-nav-drawer {
|
|
38
|
+
.header-link-group {
|
|
39
|
+
@apply hidden @4xl:flex;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<%= render component_tag(
|
|
2
|
+
x: {data: "appHeader", "bind:class": "{'drawer-open': drawerOpen}"},
|
|
3
|
+
class: {"with-nav-drawer": mobile_nav?}
|
|
4
|
+
) do %>
|
|
5
|
+
<div class="header-content">
|
|
6
|
+
<%= tag.send(home_path ? :a : :div, class: "header-logo", href: home_path) do %>
|
|
7
|
+
<%= image_tag asset_url("coco/img/coveragebook-logomark-white.svg"),
|
|
8
|
+
alt: "CoverageBook logomark",
|
|
9
|
+
class: "header-logo-no-wordmark" %>
|
|
10
|
+
<%= image_tag asset_url("coco/img/coveragebook-landscape-white.svg"),
|
|
11
|
+
alt: "CoverageBook full logo",
|
|
12
|
+
class: "header-logo-full" %>
|
|
13
|
+
<% end %>
|
|
14
|
+
<nav class="header-links" x-ref="links">
|
|
15
|
+
<div class="header-link-group header-primary" x-ref="primaryLinks">
|
|
16
|
+
<%= primary_nav %>
|
|
17
|
+
</div>
|
|
18
|
+
<div class="header-link-group header-secondary" x-ref="secondaryLinks">
|
|
19
|
+
<%= secondary_nav %>
|
|
20
|
+
</div>
|
|
21
|
+
<% if mobile_nav? %>
|
|
22
|
+
<div class="header-mobile-controls">
|
|
23
|
+
<%= coco_button(icon: :menu, theme: :text_neutral_light, size: :md, click: "toggleDrawer", x: {show: "!drawerOpen"}) %>
|
|
24
|
+
<%= coco_button(icon: :x, theme: :text_neutral_light, size: :md, click: "toggleDrawer", x: {show: "drawerOpen", cloak: true}) %>
|
|
25
|
+
</div>
|
|
26
|
+
<% end %>
|
|
27
|
+
</nav>
|
|
28
|
+
</div>
|
|
29
|
+
<%= mobile_nav %>
|
|
30
|
+
<% end %>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module Coco
|
|
2
|
+
module App
|
|
3
|
+
module Blocks
|
|
4
|
+
class Header < Coco::Component
|
|
5
|
+
renders_one :primary_nav, ->(**kwargs) do
|
|
6
|
+
Coco::App::Elements::ButtonGroup.new(
|
|
7
|
+
theme: :text_neutral_light,
|
|
8
|
+
collapsible: false,
|
|
9
|
+
size: :sm,
|
|
10
|
+
**kwargs
|
|
11
|
+
)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
renders_one :secondary_nav, ->(**kwargs) do
|
|
15
|
+
Coco::App::Elements::ButtonGroup.new(
|
|
16
|
+
theme: :text_neutral_light,
|
|
17
|
+
collapsible: false,
|
|
18
|
+
size: :sm,
|
|
19
|
+
**kwargs
|
|
20
|
+
)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
renders_one :mobile_nav, ->(**kwargs) do
|
|
24
|
+
Coco::App::Blocks::NavDrawer.new(**kwargs)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
attr_reader :home_path
|
|
28
|
+
|
|
29
|
+
def initialize(home_path: nil, **)
|
|
30
|
+
@home_path = home_path
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -1,9 +1,54 @@
|
|
|
1
1
|
@layer components {
|
|
2
2
|
[data-coco][data-component="app-nav-drawer"] {
|
|
3
|
-
@apply fixed top-
|
|
3
|
+
@apply pointer-events-none fixed top-14 left-0 bottom-0 w-screen overflow-hidden;
|
|
4
|
+
height: var(--app-height);
|
|
4
5
|
|
|
5
|
-
.nav-
|
|
6
|
-
@apply
|
|
6
|
+
.nav-drawer-overlay {
|
|
7
|
+
@apply pointer-events-none absolute inset-0 bg-black opacity-0 transition-opacity;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.nav-drawer-content {
|
|
11
|
+
@apply absolute top-0 right-0 bottom-0 bg-white overflow-auto translate-x-full transition-transform py-4;
|
|
12
|
+
max-width: 340px;
|
|
13
|
+
min-width: 280px;
|
|
14
|
+
width: fit-content;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.nav-drawer-item:last-child {
|
|
18
|
+
@apply mb-10;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.nav-drawer-button {
|
|
22
|
+
@apply w-full text-content-dark-2 hover:text-content-dark-1 hover:bg-background-light-3;
|
|
23
|
+
|
|
24
|
+
.button-inner {
|
|
25
|
+
@apply mx-0 px-4 py-3;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.nav-drawer-heading {
|
|
30
|
+
@apply mt-4 mb-2 mx-4 border-b text-content-dark-1/50 border-gray-300 pb-3;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.nav-drawer-divider {
|
|
34
|
+
@apply h-0 border-t border-gray-300 my-3;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
[data-component="app-notice"] {
|
|
38
|
+
@apply mb-4;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.drawer-open & {
|
|
42
|
+
@apply pointer-events-auto;
|
|
43
|
+
|
|
44
|
+
.nav-drawer-overlay {
|
|
45
|
+
@apply pointer-events-auto opacity-60;
|
|
46
|
+
backdrop-filter: blur(2px);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.nav-drawer-content {
|
|
50
|
+
@apply pointer-events-auto translate-x-0 shadow-2xl;
|
|
51
|
+
}
|
|
7
52
|
}
|
|
8
53
|
}
|
|
9
54
|
}
|
|
@@ -1,8 +1,16 @@
|
|
|
1
|
-
<%= render component_tag(
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
<%= render component_tag(
|
|
2
|
+
x: {
|
|
3
|
+
data: "appNavDrawer",
|
|
4
|
+
"@keydown.escape.document": "close",
|
|
5
|
+
"@resize.window": "close"
|
|
6
|
+
}
|
|
7
|
+
) do %>
|
|
8
|
+
<div class="nav-drawer-overlay" @click="close"></div>
|
|
9
|
+
<div class="nav-drawer-content" x-ref="content" x-trap.noscroll.inert.noreturn="active">
|
|
10
|
+
<% items.each do |item| %>
|
|
11
|
+
<div class="nav-drawer-item">
|
|
12
|
+
<%= item %>
|
|
13
|
+
</div>
|
|
14
|
+
<% end %>
|
|
7
15
|
</div>
|
|
8
16
|
<% end %>
|
|
@@ -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(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
|