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.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/build/coco/app.css +1134 -165
  3. data/app/assets/build/coco/app.js +307 -49
  4. data/app/assets/build/coco/book.css +55 -9
  5. data/app/assets/build/coco/book.js +24 -2
  6. data/app/assets/css/app/tippy.css +4 -0
  7. data/app/assets/css/base/base.css +12 -0
  8. data/app/assets/css/base/components/coco.css +0 -3
  9. data/app/assets/js/app/setup.js +22 -0
  10. data/app/assets/js/app.js +2 -0
  11. data/app/assets/js/helpers/location.js +9 -0
  12. data/app/assets/js/libs/tippy/index.js +7 -2
  13. data/app/components/coco/app/blocks/header/header.css +43 -0
  14. data/app/components/coco/app/blocks/header/header.html.erb +30 -0
  15. data/app/components/coco/app/blocks/header/header.js +11 -0
  16. data/app/components/coco/app/blocks/header/header.rb +35 -0
  17. data/app/components/coco/app/blocks/nav_drawer/nav_drawer.css +48 -3
  18. data/app/components/coco/app/blocks/nav_drawer/nav_drawer.html.erb +14 -6
  19. data/app/components/coco/app/blocks/nav_drawer/nav_drawer.js +18 -1
  20. data/app/components/coco/app/blocks/nav_drawer/nav_drawer.rb +26 -1
  21. data/app/components/coco/app/blocks/sidebar_nav/sidebar_nav.css +104 -0
  22. data/app/components/coco/app/blocks/sidebar_nav/sidebar_nav.html.erb +42 -0
  23. data/app/components/coco/app/blocks/sidebar_nav/sidebar_nav.js +28 -0
  24. data/app/components/coco/app/blocks/sidebar_nav/sidebar_nav.rb +28 -0
  25. data/app/components/coco/app/blocks/sidebar_nav_item/sidebar_nav_item.css +165 -0
  26. data/app/components/coco/app/blocks/sidebar_nav_item/sidebar_nav_item.html.erb +43 -0
  27. data/app/components/coco/app/blocks/sidebar_nav_item/sidebar_nav_item.js +41 -0
  28. data/app/components/coco/app/blocks/sidebar_nav_item/sidebar_nav_item.rb +98 -0
  29. data/app/components/coco/app/elements/alert/alert.css +65 -18
  30. data/app/components/coco/app/elements/alert/alert.html.erb +20 -5
  31. data/app/components/coco/app/elements/alert/alert.js +4 -3
  32. data/app/components/coco/app/elements/alert/alert.rb +16 -6
  33. data/app/components/coco/app/elements/button/button.css +87 -5
  34. data/app/components/coco/app/elements/button/button.rb +3 -1
  35. data/app/components/coco/app/elements/button_group/button_group.rb +4 -0
  36. data/app/components/coco/app/elements/button_to/button_to.css +5 -1
  37. data/app/components/coco/app/elements/button_to/button_to.rb +8 -1
  38. data/app/components/coco/app/elements/color_picker/color_picker.rb +1 -1
  39. data/app/components/coco/app/elements/menu/menu.css +5 -0
  40. data/app/components/coco/app/elements/menu/menu.html.erb +1 -1
  41. data/app/components/coco/app/elements/menu/menu.rb +2 -1
  42. data/app/components/coco/app/elements/menu_button/menu_button.html.erb +6 -0
  43. data/app/components/coco/app/elements/menu_button/menu_button.rb +8 -9
  44. data/app/components/coco/app/elements/menu_items/user_profile/user_profile.css +22 -0
  45. data/app/components/coco/app/elements/menu_items/user_profile/user_profile.html.erb +17 -0
  46. data/app/components/coco/app/elements/menu_items/user_profile/user_profile.rb +20 -0
  47. data/app/components/coco/app/elements/notice/notice.css +4 -0
  48. data/app/components/coco/app/elements/notice/notice.rb +2 -2
  49. data/app/components/coco/app/elements/snackbar/snackbar.css +8 -1
  50. data/app/components/coco/app/elements/snackbar/snackbar.rb +2 -2
  51. data/app/components/coco/app/elements/system_banner/system_banner.html.erb +2 -1
  52. data/app/components/coco/app/elements/system_banner/system_banner.js +35 -2
  53. data/app/components/coco/app/elements/system_banner/system_banner.rb +47 -3
  54. data/app/components/coco/app/layouts/application/application.css +104 -4
  55. data/app/components/coco/app/layouts/application/application.html.erb +28 -7
  56. data/app/components/coco/app/layouts/application/application.js +16 -0
  57. data/app/components/coco/app/layouts/application/application.rb +11 -3
  58. data/app/components/coco/base/avatar/avatar.css +25 -0
  59. data/app/components/coco/base/avatar/avatar.rb +20 -0
  60. data/app/components/coco/base/icon/icon.css +6 -2
  61. data/app/components/coco/base/icon/icon.rb +1 -1
  62. data/app/components/coco/base/modal/modal.css +2 -1
  63. data/app/components/coco/base/modal/modal.html.erb +1 -1
  64. data/app/components/coco/base/modal/modal.js +2 -0
  65. data/app/components/coco/base/modal_lightbox/modal_lightbox.js +2 -2
  66. data/app/components/coco/base/placeholder/placeholder.css +15 -1
  67. data/app/components/coco/base/placeholder/placeholder.rb +2 -0
  68. data/app/components/coco/concerns/accepts_tag_attributes.rb +6 -2
  69. data/app/components/coco/concerns/acts_as_button_group.rb +30 -12
  70. data/app/helpers/coco/app_helper.rb +26 -2
  71. data/app/helpers/coco/base_helper.rb +6 -0
  72. data/app/helpers/coco/url_helper.rb +5 -1
  73. data/config/tailwind.base.config.cjs +3 -0
  74. data/config/tokens.cjs +6 -0
  75. data/lib/coco.rb +1 -1
  76. metadata +24 -10
  77. data/app/components/coco/app/blocks/banner/banner.css +0 -5
  78. data/app/components/coco/app/blocks/banner/banner.rb +0 -8
  79. data/app/components/coco/app/blocks/nav_bar/nav_bar.css +0 -51
  80. data/app/components/coco/app/blocks/nav_bar/nav_bar.html.erb +0 -23
  81. data/app/components/coco/app/blocks/nav_bar/nav_bar.js +0 -31
  82. data/app/components/coco/app/blocks/nav_bar/nav_bar.rb +0 -19
@@ -12,4 +12,8 @@
12
12
  .tippy-box[data-theme~="coco-app-menu"] {
13
13
  @apply tippy-dropdown-box;
14
14
  }
15
+
16
+ .tippy-box[data-theme~="coco-naked-dropdown"] {
17
+ width: min-content;
18
+ }
15
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
  }
@@ -2,9 +2,6 @@
2
2
  [data-coco] {
3
3
  @apply text-content-dark-1 font-body;
4
4
 
5
- -webkit-font-smoothing: antialiased;
6
- -moz-osx-font-smoothing: grayscale;
7
-
8
5
  h1,
9
6
  h2,
10
7
  h3,
@@ -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
@@ -5,6 +5,8 @@ console.info("Initializing Coco JS", packageJSON.version);
5
5
  import "container-query-polyfill";
6
6
  import Alpine from "@libs/alpine";
7
7
 
8
+ import "./app/setup";
9
+
8
10
  import "./base/components";
9
11
  import "./book/components";
10
12
  import "./app/components";
@@ -0,0 +1,9 @@
1
+ function navigateTo(url, options = {}) {
2
+ if (window.Turbo && options.turbo === true) {
3
+ window.Turbo.visit(url, { action: options.action || "advance" });
4
+ } else {
5
+ location.assign(url);
6
+ }
7
+ }
8
+
9
+ export { navigateTo };
@@ -1,4 +1,9 @@
1
- import tippy, { createSingleton, followCursor, roundArrow } from "tippy.js";
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,11 @@
1
+ import { CocoComponent } from "@js/coco";
2
+
3
+ export default CocoComponent("appHeader", () => {
4
+ return {
5
+ drawerOpen: false,
6
+
7
+ toggleDrawer() {
8
+ this.drawerOpen = !this.drawerOpen;
9
+ },
10
+ };
11
+ });
@@ -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-0 left-0 bottom-0 h-screen w-[340px] bg-white shadow-2xl overflow-hidden;
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-inner {
6
- @apply p-4;
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(x: { data: "appNavDrawer" }) do %>
2
- <div class="nav-inner">
3
- <div class="nav-header">
4
- <%= coco_button(icon: :x, theme: nil) %>
5
- </div>
6
- <%= content %>
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
- open: false,
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
- include Coco::AppHelper
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