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
@@ -13,7 +13,7 @@
13
13
 
14
14
  &[data-theme="primary"],
15
15
  &[data-theme="positive"] {
16
- @apply bg-background-primary text-content-light-1 hover:bg-primary-600 active:bg-primary-700;
16
+ @apply bg-background-primary text-content-light-1 hover:bg-primary-600 active:bg-primary-700 antialiased;
17
17
 
18
18
  &[data-state="loading"] {
19
19
  @apply bg-background-primary;
@@ -105,7 +105,7 @@
105
105
  }
106
106
 
107
107
  &[data-theme="negative"] {
108
- @apply bg-background-negative text-content-light-1 hover:bg-negative-700 active:bg-negative-800;
108
+ @apply bg-background-negative text-content-light-1 hover:bg-negative-700 active:bg-negative-800 antialiased;
109
109
 
110
110
  &[data-state="loading"] {
111
111
  @apply bg-background-negative;
@@ -145,7 +145,7 @@
145
145
  }
146
146
 
147
147
  &[data-theme="warning"] {
148
- @apply bg-background-warning text-content-light-1 hover:bg-warning-700 active:bg-warning-800;
148
+ @apply bg-background-warning text-content-light-1 hover:bg-warning-700 active:bg-warning-800 antialiased;
149
149
 
150
150
  &[data-state="loading"] {
151
151
  @apply bg-background-warning;
@@ -185,7 +185,7 @@
185
185
  }
186
186
 
187
187
  &[data-theme="info"] {
188
- @apply bg-background-info text-content-light-1 hover:bg-info-700 active:bg-info-800;
188
+ @apply bg-background-info text-content-light-1 hover:bg-info-700 active:bg-info-800 antialiased;
189
189
 
190
190
  &[data-state="loading"] {
191
191
  @apply bg-background-info;
@@ -225,7 +225,7 @@
225
225
  }
226
226
 
227
227
  &[data-theme="neutral-dark"] {
228
- @apply bg-background-dark-1 text-content-light-1 hover:bg-gray-700 active:bg-gray-600;
228
+ @apply bg-background-dark-1 text-content-light-1 hover:bg-gray-700 active:bg-gray-600 antialiased;
229
229
 
230
230
  &[data-state="loading"] {
231
231
  @apply bg-background-dark-1;
@@ -260,8 +260,36 @@
260
260
  }
261
261
  }
262
262
 
263
+ &[data-theme="text-neutral-light"] {
264
+ @apply bg-transparent text-content-light-1 hover:bg-content-light-1/10 antialiased;
265
+
266
+ &[data-state="active"] {
267
+ @apply bg-content-light-1/10;
268
+ }
269
+
270
+ &[data-disabled="true"] {
271
+ @apply opacity-30;
272
+ }
273
+ }
274
+
275
+ &[data-theme="text-neutral-dark"] {
276
+ @apply bg-transparent text-content-dark-1 hover:bg-content-dark-1/10;
277
+
278
+ &[data-state="active"] {
279
+ @apply bg-content-dark-1/10;
280
+ }
281
+
282
+ &[data-disabled="true"] {
283
+ @apply opacity-30;
284
+ }
285
+ }
286
+
263
287
  /* Responsive resizing */
264
288
 
289
+ &[data-size="xs"] {
290
+ @apply app-button-xs;
291
+ }
292
+
265
293
  &[data-size="sm"] {
266
294
  @apply app-button-sm;
267
295
  }
@@ -275,6 +303,10 @@
275
303
  }
276
304
 
277
305
  @media screen(md) {
306
+ &[data-size-md="xs"] {
307
+ @apply app-button-xs;
308
+ }
309
+
278
310
  &[data-size-md="sm"] {
279
311
  @apply app-button-sm;
280
312
  }
@@ -289,6 +321,10 @@
289
321
  }
290
322
 
291
323
  @media screen(lg) {
324
+ &[data-size-lg="xs"] {
325
+ @apply app-button-xs;
326
+ }
327
+
292
328
  &[data-size-lg="sm"] {
293
329
  @apply app-button-sm;
294
330
  }
@@ -303,6 +339,10 @@
303
339
  }
304
340
 
305
341
  @media screen(xl) {
342
+ &[data-size-xl="xs"] {
343
+ @apply app-button-xs;
344
+ }
345
+
306
346
  &[data-size-xl="sm"] {
307
347
  @apply app-button-sm;
308
348
  }
@@ -317,6 +357,11 @@
317
357
  }
318
358
 
319
359
  @media screen(2xl) {
360
+ &[data-size-xxl="xs"],
361
+ &[data-size-2xl="xs"] {
362
+ @apply app-button-xs;
363
+ }
364
+
320
365
  &[data-size-xxl="sm"],
321
366
  &[data-size-2xl="sm"] {
322
367
  @apply app-button-sm;
@@ -334,6 +379,10 @@
334
379
  }
335
380
 
336
381
  @media screen(max) {
382
+ &[data-size-max="xs"] {
383
+ @apply app-button-xs;
384
+ }
385
+
337
386
  &[data-size-max="sm"] {
338
387
  @apply app-button-sm;
339
388
  }
@@ -350,6 +399,39 @@
350
399
  }
351
400
 
352
401
  @layer utilities {
402
+ .app-button-xs {
403
+ .button-content {
404
+ @apply text-label-xs;
405
+ }
406
+
407
+ .button-icon [data-component="icon"],
408
+ .button-toggle {
409
+ @apply w-3.5 h-3.5;
410
+ }
411
+
412
+ &[data-theme] {
413
+ .button-element {
414
+ @apply py-2 px-3;
415
+ }
416
+
417
+ &.icon-only > .button-element .button-icon,
418
+ &[data-collapsed="true"] > .button-element .button-icon {
419
+ @apply -ml-1.5 -mr-1.5;
420
+ }
421
+ }
422
+
423
+ &[data-theme|="text"] {
424
+ .button-element {
425
+ @apply px-1;
426
+ }
427
+
428
+ &.icon-only > .button-element .button-icon,
429
+ &[data-collapsed="true"] > .button-element .button-icon {
430
+ @apply px-2;
431
+ }
432
+ }
433
+ }
434
+
353
435
  .app-button-sm {
354
436
  .button-content {
355
437
  @apply text-label-sm;
@@ -2,7 +2,7 @@ module Coco
2
2
  module App
3
3
  module Elements
4
4
  class Button < Coco::Button
5
- SIZES = [:sm, :md, :lg, nil]
5
+ SIZES = [:xs, :sm, :md, :lg, nil]
6
6
 
7
7
  SIZE_ALIASES = {
8
8
  default: [:sm, {xl: :md}]
@@ -26,6 +26,8 @@ module Coco
26
26
  "text-toolbar",
27
27
  "neutral-dark",
28
28
  "neutral-light",
29
+ "text-neutral-light",
30
+ "text-neutral-dark",
29
31
  "blank",
30
32
  nil
31
33
  ]
@@ -26,6 +26,10 @@ module Coco
26
26
  **kwargs
27
27
  }
28
28
 
29
+ if component_args.key?(:resize)
30
+ args[:resize] = component_args[:resize]
31
+ end
32
+
29
33
  if get_option_value(:collapsible) == false
30
34
  args[:collapsible] = false
31
35
  end
@@ -1,10 +1,14 @@
1
1
  @layer components {
2
2
  [data-coco][data-component="app-button-to"] {
3
- @apply inline-flex;
3
+ @apply flex;
4
4
  width: max-content;
5
5
 
6
6
  form {
7
7
  @apply w-full;
8
8
  }
9
+
10
+ &[data-fit="full"] {
11
+ @apply w-full;
12
+ }
9
13
  }
10
14
  }
@@ -3,9 +3,16 @@ module Coco
3
3
  module Elements
4
4
  class ButtonTo < Coco::Component
5
5
  include Concerns::WrapsComponent
6
+ include Concerns::AcceptsOptions
7
+
8
+ accepts_option :fit, from: [:auto, :full]
6
9
 
7
10
  wraps_component :button do |args|
8
- Coco::App::Elements::Button.new(type: :submit, **args)
11
+ Coco::App::Elements::Button.new(
12
+ type: :submit,
13
+ fit: get_option_value(:fit) || :auto,
14
+ **args
15
+ )
9
16
  end
10
17
 
11
18
  %i[confirmation].each do |slot_name|
@@ -20,7 +20,7 @@ module Coco
20
20
  {color: "#3A2D86"}
21
21
  ]
22
22
 
23
- accepts_option :size, from: [:sm, :md, nil], default: :sm
23
+ accepts_option :size, from: [:xs, :sm, :md, nil], default: :sm
24
24
 
25
25
  before_render do
26
26
  content unless content_evaluated?
@@ -1,6 +1,7 @@
1
1
  @layer components {
2
2
  [data-coco][data-component="app-menu"] {
3
3
  width: fit-content;
4
+ max-width: 240px;
4
5
 
5
6
  .menu-item {
6
7
  > * {
@@ -20,6 +21,10 @@
20
21
  @apply !font-[400];
21
22
  }
22
23
  }
24
+
25
+ .divider {
26
+ @apply my-1.5;
27
+ }
23
28
  }
24
29
 
25
30
  &[data-size="sm"] {
@@ -1,6 +1,6 @@
1
1
  <%= render component_tag do %>
2
2
  <ol class="menu-items">
3
- <% items.each do |item| %>
3
+ <% items.compact.each do |item| %>
4
4
  <li class="menu-item">
5
5
  <%= item %>
6
6
  </li>
@@ -5,9 +5,10 @@ module Coco
5
5
  include Concerns::ActsAsButtonGroup
6
6
  include Concerns::AcceptsOptions
7
7
 
8
- accepts_option :size, from: [:sm, :md, nil], default: :sm
8
+ accepts_option :size, from: [:xs, :sm, :md, nil], default: :sm
9
9
 
10
10
  renders_many :htmls, ->(*args, **kwargs, &block) do
11
+ init_button_group
11
12
  items << block.call
12
13
  end
13
14
 
@@ -1,5 +1,11 @@
1
1
  <%= render component_tag(x: {data: "appMenuButton"}) do %>
2
2
  <%= render button do |btn| %>
3
+ <% if icon? %>
4
+ <% btn.with_icon do %>
5
+ <%= icon %>
6
+ <% end %>
7
+ <% end %>
8
+
3
9
  <% if menu? %>
4
10
  <% btn.with_dropdown do %>
5
11
  <%= menu %>
@@ -3,11 +3,17 @@ module Coco
3
3
  module Elements
4
4
  class MenuButton < Coco::Component
5
5
  include Concerns::AcceptsOptions
6
+ include Concerns::WithIcon
6
7
  include Concerns::WrapsComponent
7
8
  include Coco::AppHelper
8
9
 
9
- wraps_component :button do |args|
10
- Coco::App::Elements::Button.new(toggle: :vertical, fit: get_option_value(:fit) || :auto, **args)
10
+ wraps_component :button do |kwargs|
11
+ @size = kwargs.fetch(:size, :default)&.to_sym
12
+ if @size.in?(Coco::App::Elements::Button::SIZE_ALIASES.keys) && !kwargs.key?(:resize)
13
+ @size, @resize = Coco::App::Elements::Button::SIZE_ALIASES.fetch(@size)
14
+ end
15
+
16
+ Coco::App::Elements::Button.new(toggle: :vertical, fit: get_option_value(:fit) || :auto, **kwargs)
11
17
  end
12
18
 
13
19
  accepts_option :fit, from: [:auto, :full]
@@ -20,13 +26,6 @@ module Coco
20
26
 
21
27
  attr_reader :size, :resize
22
28
 
23
- def initialize(button: {}, **kwargs)
24
- @size = kwargs.fetch(:size, :default)&.to_sym
25
- if @size.in?(Coco::App::Elements::Button::SIZE_ALIASES.keys) && !kwargs.key?(:resize)
26
- @size, @resize = Coco::App::Elements::Button::SIZE_ALIASES.fetch(@size)
27
- end
28
- end
29
-
30
29
  def button_text
31
30
  text || content
32
31
  end
@@ -0,0 +1,22 @@
1
+ @layer components {
2
+ [data-coco][data-component="app-user-profile"] {
3
+ @apply px-4 py-1.5 grid grid-rows-1 gap-3;
4
+ grid-template-columns: min-content 1fr;
5
+
6
+ .user-profile-avatar {
7
+ @apply flex items-center;
8
+ }
9
+
10
+ .user-profile-details {
11
+ @apply space-y-1;
12
+ }
13
+
14
+ .user-profile-name {
15
+ @apply font-semibold truncate;
16
+ }
17
+
18
+ .user-profile-email {
19
+ @apply text-gray-500 text-label-sm italic truncate;
20
+ }
21
+ }
22
+ }
@@ -0,0 +1,17 @@
1
+ <%= render component_tag do %>
2
+ <div class="user-profile-avatar">
3
+ <%= avatar %>
4
+ </div>
5
+ <div class="user-profile-details">
6
+ <% if name.present? %>
7
+ <h5 class="user-profile-name">
8
+ <%= name %>
9
+ </h5>
10
+ <% end %>
11
+ <% if email.present? %>
12
+ <div class="user-profile-email">
13
+ <%= email %>
14
+ </div>
15
+ <% end %>
16
+ </div>
17
+ <% end %>
@@ -0,0 +1,20 @@
1
+ module Coco
2
+ module App
3
+ module Elements
4
+ module MenuItems
5
+ class UserProfile < Coco::Component
6
+ renders_one :avatar, ->(**kwargs) do
7
+ Coco::Avatar.new(name: name, **kwargs, size: :lg)
8
+ end
9
+
10
+ attr_reader :name, :email
11
+
12
+ def initialize(name:, email:, **)
13
+ @name = name
14
+ @email = email
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -1,5 +1,9 @@
1
1
  @layer components {
2
2
  [data-coco][data-component="app-notice"] {
3
3
  @apply rounded-xl overflow-hidden;
4
+
5
+ div[class="alert-container"] {
6
+ @apply py-4;
7
+ }
4
8
  }
5
9
  }
@@ -12,8 +12,8 @@ module Coco
12
12
  end
13
13
 
14
14
  %i[title action secondary_action link].each do |slot_name|
15
- renders_one slot_name, ->(**kwargs, &block) do
16
- alert.send("with_#{slot_name}".to_sym, **kwargs, &block)
15
+ renders_one slot_name, ->(*args, **kwargs, &block) do
16
+ alert.send("with_#{slot_name}".to_sym, *args, **kwargs, &block)
17
17
  end
18
18
  end
19
19
  end
@@ -1,3 +1,9 @@
1
+ @layer base {
2
+ :root {
3
+ --snackbar-bottom-offset: theme(spacing.8);
4
+ }
5
+ }
6
+
1
7
  @layer components {
2
8
  [data-coco][data-component="app-snackbar"] {
3
9
  @apply bg-background-dark-2 rounded-xl overflow-hidden shadow-xl w-full;
@@ -46,7 +52,8 @@
46
52
  }
47
53
 
48
54
  &[data-position="fixed"] {
49
- @apply fixed bottom-8 left-1/2 -translate-x-1/2;
55
+ @apply fixed left-1/2 -translate-x-1/2;
56
+ bottom: var(--snackbar-bottom-offset);
50
57
  z-index: 10001;
51
58
  }
52
59
 
@@ -14,8 +14,8 @@ module Coco
14
14
 
15
15
  accepts_option :theme, from: [:positive, :warning, :negative, :pending]
16
16
 
17
- renders_one :action, ->(**kwargs, &block) do
18
- Coco::App::Elements::Button.new(**kwargs, theme: :blank, size: :sm, icon: nil)
17
+ renders_one :action, ->(*args, **kwargs, &block) do
18
+ coco_button(*args, **kwargs, theme: :blank, size: :sm, icon: nil, &block)
19
19
  end
20
20
 
21
21
  before_render do
@@ -1,4 +1,5 @@
1
- <%= render component_tag(x: { data: "appSystemBanner" }) do %>
1
+ <%= render component_tag(
2
+ x: { data: x_data("appSystemBanner", alpine_data), bind: "root"}) do %>
2
3
  <%= render alert do %>
3
4
  <%= content %>
4
5
  <% end %>
@@ -1,5 +1,38 @@
1
1
  import { CocoComponent } from "@js/coco";
2
+ import Cookies from "js-cookie";
2
3
 
3
- export default CocoComponent("appSystemBanner", () => {
4
- return {};
4
+ export default CocoComponent("appSystemBanner", (opts = {}) => {
5
+ return {
6
+ cookieName: null,
7
+ cookieValue: null,
8
+ cookieExpiry: null,
9
+
10
+ init() {
11
+ this.cookieName = opts.cookieName;
12
+ this.cookieValue = opts.cookieValue;
13
+ this.cookieExpiry = opts.cookieExpiry;
14
+ },
15
+
16
+ onDismiss() {
17
+ this.$dispatch("banner:dismiss", { banner: this });
18
+ if (this.shouldSetCookie) {
19
+ Cookies.set(this.cookieName, this.cookieValue, {
20
+ expires: this.cookieExpiry,
21
+ });
22
+ }
23
+ },
24
+
25
+ remove() {
26
+ this.$root.remove();
27
+ },
28
+
29
+ get shouldSetCookie() {
30
+ return Number.isInteger(this.cookieExpiry);
31
+ },
32
+
33
+ root: {
34
+ "@alert:dismiss": "onDismiss",
35
+ "@alert:removed": "remove",
36
+ },
37
+ };
5
38
  });
@@ -5,17 +5,61 @@ module Coco
5
5
  include Concerns::AcceptsOptions
6
6
  include Concerns::WrapsComponent
7
7
 
8
+ accepts_option :dismissable, from: [true, false], default: false
9
+
8
10
  wraps_component :alert do |args|
9
11
  theme = vivid_theme_name(args.fetch(:theme, nil)) || :info_vivid
10
- Coco::App::Elements::Alert.new(**args, theme: theme, banner: true, single_line: true)
12
+ Coco::App::Elements::Alert.new(
13
+ **args,
14
+ theme: theme,
15
+ banner: true,
16
+ cloak: false,
17
+ single_line: true,
18
+ dismissable: dismissable?,
19
+ condensed: true
20
+ )
11
21
  end
12
22
 
13
23
  %i[title action secondary_action link].each do |slot_name|
14
- renders_one slot_name, ->(**kwargs, &block) do
15
- alert.send("with_#{slot_name}".to_sym, **kwargs, &block)
24
+ renders_one slot_name, ->(*args, **kwargs, &block) do
25
+ alert.send("with_#{slot_name}".to_sym, *args, **kwargs, &block)
26
+ end
27
+ end
28
+
29
+ before_render do
30
+ if dismissable? && id.blank?
31
+ raise ArgumentError, "Dismissable banners must be given an ID"
16
32
  end
17
33
  end
18
34
 
35
+ attr_reader :dismiss_for, :id
36
+
37
+ def initialize(id: nil, dismiss_for: nil, **)
38
+ @id = id
39
+ @dismiss_for = dismiss_for
40
+ set_tag_attr(:id, id)
41
+ end
42
+
43
+ def dismissable?
44
+ get_option_value(:dismissable) == true
45
+ end
46
+
47
+ def render?
48
+ helpers.cookies[dismiss_cookie_name] != "true"
49
+ end
50
+
51
+ def dismiss_cookie_name
52
+ "cb_system_banner_#{tag_attr(:id)&.underscore}_dismissed".to_sym
53
+ end
54
+
55
+ def alpine_data
56
+ dismissable? ? {
57
+ cookie_name: dismiss_cookie_name,
58
+ cookie_expiry: dismiss_for&.in_days&.to_i,
59
+ cookie_value: "true"
60
+ } : {}
61
+ end
62
+
19
63
  private
20
64
 
21
65
  def vivid_theme_name(theme)
@@ -1,9 +1,109 @@
1
1
  @layer components {
2
- [data-coco][data-component="app-application-layout"] {
3
- @apply grid grid-rows-[min-content_1fr] h-screen w-screen overflow-hidden;
2
+ [data-coco][data-component="application-layout"] {
3
+ @apply grid overflow-hidden absolute inset-0 w-screen;
4
+ height: var(--app-height);
4
5
 
5
- .app-main {
6
- @apply overflow-auto;
6
+ grid-template-areas: "body";
7
+ grid-template-rows: 1fr;
8
+ grid-template-columns: 1fr;
9
+
10
+ &.with-header {
11
+ grid-template-areas: "header" "body";
12
+ grid-template-rows: min-content 1fr;
13
+
14
+ &.with-banner {
15
+ grid-template-areas: "header" "body" "banner";
16
+ grid-template-rows: min-content 1fr min-content;
17
+
18
+ &.with-sidebar-nav {
19
+ grid-template-areas: "header" "body" "banner" "sidebar";
20
+ grid-template-rows: min-content 1fr min-content min-content;
21
+ }
22
+ }
23
+
24
+ &:not(.with-banner) {
25
+ &.with-sidebar-nav {
26
+ grid-template-areas: "header" "body" "sidebar";
27
+ grid-template-rows: min-content 1fr min-content;
28
+ }
29
+ }
30
+ }
31
+
32
+ &.with-sidebar-nav {
33
+ --snackbar-bottom-offset: theme(spacing.16);
34
+ }
35
+
36
+ &:not(.with-header).with-banner {
37
+ grid-template-areas: "body" "banner";
38
+ grid-template-rows: 1fr min-content;
39
+ }
40
+
41
+ .layout-banner {
42
+ @apply w-screen z-10;
43
+ grid-area: banner;
44
+ height: min-content;
45
+ }
46
+
47
+ .layout-header {
48
+ @apply w-screen z-10;
49
+ grid-area: header;
50
+ height: min-content;
51
+ }
52
+
53
+ .layout-body {
54
+ @apply relative z-0 h-full overflow-y-auto scroll-smooth;
55
+ grid-area: body;
56
+ }
57
+
58
+ .layout-sidebar-nav {
59
+ @apply scroll-smooth;
60
+ scrollbar-width: none;
61
+ grid-area: sidebar;
62
+ height: min-content;
63
+
64
+ &::-webkit-scrollbar {
65
+ display: none;
66
+ }
67
+ }
68
+
69
+ @media screen(sm) {
70
+ .layout-sidebar-nav {
71
+ @apply h-full overflow-auto;
72
+ width: min-content;
73
+
74
+ > * {
75
+ @apply h-full;
76
+ }
77
+ }
78
+
79
+ grid-template-areas: "body";
80
+ grid-template-rows: 1fr;
81
+
82
+ &.with-sidebar-nav {
83
+ --snackbar-bottom-offset: theme(spacing.10);
84
+ }
85
+
86
+ &.with-header {
87
+ &.with-banner {
88
+ grid-template-areas: "banner" "header" "body";
89
+ grid-template-rows: min-content min-content 1fr;
90
+ grid-template-columns: 1fr;
91
+
92
+ &.with-sidebar-nav {
93
+ grid-template-areas: "banner banner" "header header" "sidebar body";
94
+ grid-template-rows: min-content min-content 1fr;
95
+ grid-template-columns: min-content 1fr;
96
+ }
97
+ }
98
+
99
+ &:not(.with-banner) {
100
+ &.with-sidebar-nav {
101
+ grid-template-areas: "header header" "sidebar body";
102
+ grid-template-rows: min-content 1fr;
103
+ grid-template-columns: min-content 1fr;
104
+ }
105
+ }
106
+ }
7
107
  }
8
108
  }
9
109
  }