epages-essence 0.1.0 → 0.2.0

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 (107) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/README.md +4 -3
  4. data/app/assets/images/essence/icon_component/arrow_right.svg +1 -0
  5. data/app/assets/images/essence/icon_component/chevron_up_down.svg +3 -0
  6. data/app/assets/images/essence/icon_component/power_off.svg +1 -0
  7. data/app/assets/images/essence/icon_component/sparkles.svg +1 -0
  8. data/app/assets/images/essence/icon_component/x_mark.svg +3 -0
  9. data/app/assets/stylesheets/essence/beyond/{_base.scss → layout/base.css} +0 -5
  10. data/app/assets/stylesheets/essence/beyond/layout/{_content.scss → content.css} +1 -1
  11. data/app/assets/stylesheets/essence/beyond/simple_form/control.css +249 -0
  12. data/app/assets/stylesheets/essence/beyond/simple_form/error.css +29 -0
  13. data/app/assets/stylesheets/essence/beyond/simple_form/fieldset.css +32 -0
  14. data/app/assets/stylesheets/essence/beyond/simple_form/group.css +21 -0
  15. data/app/assets/stylesheets/essence/beyond/simple_form/hint.css +6 -0
  16. data/app/assets/stylesheets/essence/beyond/simple_form/label.css +38 -0
  17. data/app/assets/stylesheets/essence/beyond/simple_form/row.css +5 -0
  18. data/app/assets/stylesheets/essence/beyond/simple_form/wrapper.css +3 -0
  19. data/app/assets/stylesheets/essence/beyond/utils/margin.css +15 -0
  20. data/app/assets/stylesheets/essence/beyond/variables.css +281 -0
  21. data/app/assets/stylesheets/essence/beyond.css +39 -0
  22. data/app/components/essence/action_bar_component/action_bar_component.css +23 -0
  23. data/app/components/essence/action_bar_component.rb +2 -1
  24. data/app/components/essence/app_info_component/app_info_component.css +45 -0
  25. data/app/components/essence/application_component.rb +1 -3
  26. data/app/components/essence/breadcrumb_component/breadcrumb_component.css +35 -0
  27. data/app/components/essence/button_component/button_component.css +140 -0
  28. data/app/components/essence/button_component/button_component.html.erb +2 -0
  29. data/app/components/essence/button_component/button_component_controller.js +27 -0
  30. data/app/components/essence/button_component.rb +27 -2
  31. data/app/components/essence/button_group_component/button_group_component.css +21 -0
  32. data/app/components/essence/button_group_component/button_group_component.html.erb +5 -0
  33. data/app/components/essence/button_group_component.rb +28 -0
  34. data/app/components/essence/card_component/card_component.css +66 -0
  35. data/app/components/essence/card_component/card_component.html.erb +6 -0
  36. data/app/components/essence/card_component/ribbon_component.html.erb +3 -0
  37. data/app/components/essence/card_component.rb +38 -4
  38. data/app/components/essence/clipboard_copy_component/{clipboard_copy_component.scss → clipboard_copy_component.css} +4 -4
  39. data/app/components/essence/empty_state_component/empty_state_component.css +42 -0
  40. data/app/components/essence/expandable_component/expandable_component.css +36 -0
  41. data/app/components/essence/expandable_component/expandable_component.html.erb +8 -0
  42. data/app/components/essence/expandable_component/expandable_component_controller.js +32 -0
  43. data/app/components/essence/expandable_component.rb +30 -0
  44. data/app/components/essence/expandable_toggle_component/expandable_toggle_component.css +7 -0
  45. data/app/components/essence/expandable_toggle_component/expandable_toggle_component.html.erb +3 -0
  46. data/app/components/essence/expandable_toggle_component/expandable_toggle_component.yml +4 -0
  47. data/app/components/essence/expandable_toggle_component/expandable_toggle_component_controller.js +52 -0
  48. data/app/components/essence/expandable_toggle_component.rb +38 -0
  49. data/app/components/essence/flash_component/container_component.html.erb +7 -0
  50. data/app/components/essence/flash_component/flash_component.css +101 -0
  51. data/app/components/essence/flash_component/flash_component.html.erb +11 -0
  52. data/app/components/essence/flash_component/flash_component_controller.js +24 -0
  53. data/app/components/essence/flash_component.rb +29 -0
  54. data/app/components/essence/link_component/link_component.css +49 -0
  55. data/app/components/essence/notification_component/notification_component.css +55 -0
  56. data/app/components/essence/notification_component.rb +6 -2
  57. data/app/components/essence/paragraph_component/{paragraph_component.scss → paragraph_component.css} +0 -5
  58. data/app/components/essence/scroll_shadow_component/{scroll_shadow_component.scss → scroll_shadow_component.css} +4 -0
  59. data/app/components/essence/spinner_component/{spinner_component.scss → spinner_component.css} +5 -12
  60. data/app/components/essence/spinner_component/spinner_component.html.erb +1 -1
  61. data/app/components/essence/spinner_component.rb +4 -2
  62. data/app/components/essence/status_component/status_component.css +64 -0
  63. data/app/components/essence/status_component.rb +1 -1
  64. data/app/components/essence/step_list_component/step_list_component.css +72 -0
  65. data/app/components/essence/step_list_component/step_list_component.html.erb +3 -1
  66. data/app/components/essence/step_list_component.rb +7 -1
  67. data/app/components/essence/table_component/{table_component.scss → table_component.css} +5 -8
  68. data/app/components/essence/title_component/{title_component.scss → title_component.css} +0 -4
  69. data/app/components/essence/tooltip_component/tooltip_component.css +55 -0
  70. data/app/inputs/file_input.rb +73 -0
  71. data/app/javascript/essence/application.js +2 -2
  72. data/app/javascript/essence/controllers/file_input_controller.js +41 -0
  73. data/app/javascript/essence/controllers/index.js +18 -3
  74. data/app/views/essence/beyond/body.html.erb +1 -0
  75. data/config/importmap.rb +3 -0
  76. data/config/initializers/essence/inline_svg.rb +5 -0
  77. data/config/initializers/essence/simple_form.rb +29 -8
  78. data/config/locales/essence.en.yml +3 -0
  79. data/lib/components/input_group.rb +19 -0
  80. data/lib/essence/engine.rb +20 -5
  81. data/lib/essence/version.rb +1 -1
  82. data/lib/essence.rb +1 -1
  83. data/vendor/assets/stylesheets/essence/flexboxgrid.css +824 -0
  84. metadata +78 -53
  85. data/app/assets/config/essence_manifest.js +0 -5
  86. data/app/assets/stylesheets/essence/beyond/components/_index.scss +0 -17
  87. data/app/assets/stylesheets/essence/beyond/layout/_index.scss +0 -1
  88. data/app/assets/stylesheets/essence/beyond/simple_form/_control.scss +0 -172
  89. data/app/assets/stylesheets/essence/beyond/simple_form/_error.scss +0 -27
  90. data/app/assets/stylesheets/essence/beyond/simple_form/_fieldset.scss +0 -34
  91. data/app/assets/stylesheets/essence/beyond/simple_form/_group.scss +0 -6
  92. data/app/assets/stylesheets/essence/beyond/simple_form/_hint.scss +0 -8
  93. data/app/assets/stylesheets/essence/beyond/simple_form/_index.scss +0 -43
  94. data/app/assets/stylesheets/essence/beyond/simple_form/_label.scss +0 -26
  95. data/app/assets/stylesheets/essence/beyond/simple_form/_wrapper.scss +0 -5
  96. data/app/assets/stylesheets/essence/beyond.scss +0 -4
  97. data/app/components/essence/action_bar_component/action_bar_component.scss +0 -29
  98. data/app/components/essence/app_info_component/app_info_component.scss +0 -45
  99. data/app/components/essence/breadcrumb_component/breadcrumb_component.scss +0 -39
  100. data/app/components/essence/button_component/button_component.scss +0 -105
  101. data/app/components/essence/card_component/card_component.scss +0 -21
  102. data/app/components/essence/empty_state_component/empty_state_component.scss +0 -50
  103. data/app/components/essence/link_component/link_component.scss +0 -58
  104. data/app/components/essence/notification_component/notification_component.scss +0 -63
  105. data/app/components/essence/status_component/status_component.scss +0 -80
  106. data/app/components/essence/step_list_component/step_list_component.scss +0 -79
  107. data/app/components/essence/tooltip_component/tooltip_component.scss +0 -63
@@ -0,0 +1,21 @@
1
+ .button-group {
2
+ display: flex;
3
+
4
+ & > .button {
5
+ border-radius: 0;
6
+
7
+ &:not(:first-child) {
8
+ border-left: 0;
9
+ }
10
+
11
+ &:first-child {
12
+ border-top-left-radius: var(--button-borderRadius);
13
+ border-bottom-left-radius: var(--button-borderRadius);
14
+ }
15
+
16
+ &:last-child {
17
+ border-top-right-radius: var(--button-borderRadius);
18
+ border-bottom-right-radius: var(--button-borderRadius);
19
+ }
20
+ }
21
+ }
@@ -0,0 +1,5 @@
1
+ <div <%= tag.attributes **html_options %>>
2
+ <% button_group_elements.each do |button_group_element| %>
3
+ <%= button_group_element %>
4
+ <% end %>
5
+ </div>
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Essence
4
+ class ButtonGroupComponent < ApplicationComponent
5
+ attr_reader :html_options
6
+
7
+ renders_many :group, types: {
8
+ button: lambda { |**args|
9
+ ButtonComponent.new(size: 16, **args.merge(display_as: :button))
10
+ },
11
+ link: lambda { |**args|
12
+ LinkComponent.new(size: 16, **args.merge(display_as: :button))
13
+ }
14
+ }
15
+
16
+ def initialize(**html_options)
17
+ @html_options = html_options
18
+ end
19
+
20
+ alias button_group_elements group
21
+
22
+ private
23
+
24
+ def before_render
25
+ set_base_html_options('button-group')
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,66 @@
1
+ :root {
2
+ --ribbon-text: #ffffff;
3
+ --ribbon-light-background: #a6a6a6;
4
+ --ribbon-light-shadow: #808080;
5
+ }
6
+
7
+ .card {
8
+ background-color: var(--card-background);
9
+ border-radius: var(--card-borderRadius);
10
+ box-shadow: var(--card-shadow);
11
+ padding: var(--card-padding);
12
+ position: relative;
13
+ }
14
+
15
+ .card-ribbon {
16
+ position: absolute;
17
+ top: -8px;
18
+ right: 40px;
19
+ display: inline-block;
20
+ padding: 6px 10px;
21
+ font-size: 12px;
22
+ font-weight: 700;
23
+ border-bottom-left-radius: 3px;
24
+ border-bottom-right-radius: 3px;
25
+ color: var(--ribbon-text);
26
+ }
27
+
28
+ .card-ribbon-light {
29
+ background-color: var(--ribbon-light-background);
30
+
31
+ .card-ribbon-text::after {
32
+ border-bottom: 8px solid var(--ribbon-light-shadow);
33
+ }
34
+ }
35
+
36
+ .card-ribbon-dark {
37
+ background-color: var(--ribbon-dark-background);
38
+
39
+ .card-ribbon-text::after {
40
+ border-bottom: 8px solid var(--ribbon-dark-shadow);
41
+ }
42
+ }
43
+
44
+ .card-ribbon-text {
45
+ position: relative;
46
+
47
+ &::after {
48
+ content: "";
49
+ border-right: 7px solid transparent;
50
+ position: absolute;
51
+ top: -7px;
52
+ right: -17px;
53
+ }
54
+ }
55
+
56
+ .card-headline {
57
+ color: var(--card-headline);
58
+ font-size: 140%;
59
+ margin: -10px 0 0.83em;
60
+ }
61
+
62
+ .card-sub-headline {
63
+ color: var(--formGroup-label);
64
+ font-size: 13px;
65
+ margin: 0 0 20px;
66
+ }
@@ -1,7 +1,13 @@
1
1
  <div <%= tag.attributes **html_options %>>
2
+ <% if ribbon? %>
3
+ <%= ribbon %>
4
+ <% end %>
2
5
  <% if headline? %>
3
6
  <h2 class="card-headline"><%= headline %></h2>
4
7
  <% end %>
8
+ <% if sub_headline? %>
9
+ <p class="card-sub-headline"><%= sub_headline %></p>
10
+ <% end %>
5
11
  <div class="card-content">
6
12
  <%= content %>
7
13
  </div>
@@ -0,0 +1,3 @@
1
+ <div <%= tag.attributes **html_options %>>
2
+ <span class="card-ribbon-text"><%= text %></span>
3
+ </div>
@@ -2,12 +2,46 @@
2
2
 
3
3
  module Essence
4
4
  class CardComponent < ApplicationComponent
5
- attr_reader :headline, :html_options
5
+ attr_reader :headline, :sub_headline, :html_options
6
+
7
+ renders_one :ribbon, 'RibbonComponent'
6
8
 
7
9
  def initialize(headline: nil,
10
+ sub_headline: nil,
8
11
  **html_options)
9
- @headline = headline
10
- @html_options = html_options
12
+ @headline = headline
13
+ @sub_headline = sub_headline
14
+ @html_options = html_options
15
+ end
16
+
17
+ class RibbonComponent < ApplicationComponent
18
+ attr_reader :text, :html_options
19
+
20
+ DEFAULT_VARIANT = :light
21
+
22
+ VARIANT_MAPPINGS = {
23
+ DEFAULT_VARIANT => 'card-ribbon-light',
24
+ :dark => 'card-ribbon-dark'
25
+ }.freeze
26
+
27
+ VARIANT_OPTIONS = VARIANT_MAPPINGS.keys.freeze
28
+
29
+ def initialize(text:,
30
+ variant: DEFAULT_VARIANT,
31
+ **html_options)
32
+ @text = text
33
+ @variant = fetch_or_fallback(VARIANT_OPTIONS, variant.to_sym, DEFAULT_VARIANT)
34
+ @html_options = html_options
35
+ end
36
+
37
+ private
38
+
39
+ def before_render
40
+ set_base_html_options(
41
+ 'card-ribbon',
42
+ VARIANT_MAPPINGS[@variant]
43
+ )
44
+ end
11
45
  end
12
46
 
13
47
  private
@@ -20,7 +54,7 @@ module Essence
20
54
  content?
21
55
  end
22
56
 
23
- [:headline].each do |method_name|
57
+ [:headline, :sub_headline].each do |method_name|
24
58
  define_method(:"#{method_name}?") do
25
59
  instance_variable_get(:"@#{method_name}").present?
26
60
  end
@@ -5,9 +5,9 @@
5
5
  > *:has(.clipboard-copy-input) {
6
6
  flex: 1;
7
7
  }
8
+ }
8
9
 
9
- &-link {
10
- margin-left: 30px;
11
- padding: 6px 0 !important;
12
- }
10
+ .clipboard-copy-link {
11
+ margin-left: 30px;
12
+ padding: 6px 0 !important;
13
13
  }
@@ -0,0 +1,42 @@
1
+ .empty-state {
2
+ align-items: center;
3
+ display: flex;
4
+ justify-content: center;
5
+ }
6
+
7
+ .empty-state-image {
8
+ flex-shrink: 0;
9
+ margin: 0 60px 0 0;
10
+ max-width: 200px;
11
+
12
+ .bubbles {
13
+ fill: var(--emptyState-bubbles);
14
+ }
15
+
16
+ .outline {
17
+ fill: var(--emptyState-outline);
18
+ }
19
+
20
+ .surface {
21
+ fill: var(--emptyState-surface);
22
+ }
23
+ }
24
+
25
+ .empty-state-text {
26
+ display: grid;
27
+ gap: 20px;
28
+ }
29
+
30
+ .empty-state-headline {
31
+ color: var(--emptyState-headline);
32
+ font-size: 300%;
33
+ font-weight: lighter;
34
+ line-height: 1;
35
+ margin-bottom: 0;
36
+ }
37
+
38
+ .empty-state-body {
39
+ color: var(--emptyState-help-text);
40
+ font-size: 125%;
41
+ margin: 0;
42
+ }
@@ -0,0 +1,36 @@
1
+ .expandable {
2
+ &[data-expandable-expanded-value="false"] {
3
+ .expandable-content {
4
+ height: 0;
5
+ }
6
+ }
7
+
8
+ &[data-expandable-expanded-value="true"] {
9
+ .button-icon {
10
+ transform: rotate(90deg);
11
+ }
12
+
13
+ .expandable-content {
14
+ margin-top: 10px;
15
+ }
16
+ }
17
+
18
+ .expandable-button {
19
+ font-weight: bold;
20
+
21
+ .button-icon {
22
+ fill: currentColor;
23
+ height: 10px;
24
+ width: 10px;
25
+ }
26
+ }
27
+
28
+ .expandable-content {
29
+ interpolate-size: allow-keywords;
30
+ height: auto;
31
+ margin-top: 0;
32
+ overflow: hidden;
33
+ padding-left: 20px;
34
+ transition: height 250ms, margin-top 250ms;
35
+ }
36
+ }
@@ -0,0 +1,8 @@
1
+ <div <%= tag.attributes **html_options %>>
2
+ <%= render Essence::ButtonComponent.new(name:, display_as: :link, type: :button, class: 'expandable-button', data: { action: 'expandable#toggle' }) do |button| %>
3
+ <% button.with_left_icon 'arrow_right' %>
4
+ <% end %>
5
+ <div class="expandable-content">
6
+ <%= content %>
7
+ </div>
8
+ </div>
@@ -0,0 +1,32 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+
3
+ export default class extends Controller {
4
+ static outlets = [
5
+ "expandable-toggle"
6
+ ]
7
+
8
+ static values = {
9
+ expanded: Boolean
10
+ }
11
+
12
+ toggle() {
13
+ this.#updateExpandedState(!this.expandedValue)
14
+ }
15
+
16
+ expand() {
17
+ this.#updateExpandedState(true)
18
+ }
19
+
20
+ collapse() {
21
+ this.#updateExpandedState(false)
22
+ }
23
+
24
+ #updateExpandedState(expandedState) {
25
+ this.expandedValue = expandedState
26
+ this.#triggerOutletsCheckExpandables()
27
+ }
28
+
29
+ #triggerOutletsCheckExpandables() {
30
+ this.expandableToggleOutlets.forEach(expandable => expandable.checkExpandables())
31
+ }
32
+ }
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Essence
4
+ class ExpandableComponent < ApplicationComponent
5
+ attr_reader :name, :html_options
6
+
7
+ DEFAULT_EXPANDED = false
8
+
9
+ def initialize(name:,
10
+ expanded: DEFAULT_EXPANDED,
11
+ **html_options)
12
+ @name = name
13
+ @expanded = fetch_or_fallback_boolean(expanded, fallback: DEFAULT_EXPANDED)
14
+ @html_options = html_options
15
+ end
16
+
17
+ private
18
+
19
+ def before_render
20
+ set_base_html_options(
21
+ 'expandable',
22
+ data: {
23
+ controller: 'expandable',
24
+ expandable_expanded_value: @expanded,
25
+ expandable_expand_all_button_outlet: '.expandable-toggle'
26
+ }
27
+ )
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,7 @@
1
+ .expandable-toggle {
2
+ .button-icon {
3
+ fill: currentColor;
4
+ height: 15px;
5
+ width: 15px;
6
+ }
7
+ }
@@ -0,0 +1,3 @@
1
+ <%= render Essence::ButtonComponent.new(name: expand_all_text, display_as: :link, type: :button, **html_options) do |button| %>
2
+ <% button.with_left_icon 'chevron_up_down' %>
3
+ <% end %>
@@ -0,0 +1,4 @@
1
+ ---
2
+ en:
3
+ expand_all_text: Expand all
4
+ collapse_all_text: Collapse all
@@ -0,0 +1,52 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+
3
+ export default class extends Controller {
4
+ static outlets = [
5
+ "expandable"
6
+ ]
7
+
8
+ static values = {
9
+ expandAllText: String,
10
+ collapseAllText: String,
11
+ allExpanded: Boolean
12
+ }
13
+
14
+ connect() {
15
+ this.checkExpandables()
16
+ }
17
+
18
+ toggleAll() {
19
+ this.#updateExpandablesState(!this.allExpandedValue)
20
+ }
21
+
22
+ collapseAll() {
23
+ this.#updateExpandablesState(false)
24
+ }
25
+
26
+ expandAll() {
27
+ this.#updateExpandablesState(true)
28
+ }
29
+
30
+ checkExpandables() {
31
+ if (this.expandableOutlets.length === 0) return
32
+
33
+ const allExpanded = this.expandableOutlets.every(expandable => expandable.expandedValue)
34
+ const allCollapsed = this.expandableOutlets.every(expandable => !expandable.expandedValue)
35
+
36
+ if (allExpanded) {
37
+ this.#updateExpandedState(true)
38
+ } else if (allCollapsed) {
39
+ this.#updateExpandedState(false)
40
+ }
41
+ }
42
+
43
+ #updateExpandablesState(expandedState) {
44
+ this.#updateExpandedState(expandedState)
45
+ this.expandableOutlets.forEach(expandable => expandedState ? expandable.expand() : expandable.collapse())
46
+ }
47
+
48
+ #updateExpandedState(expandedState) {
49
+ this.allExpandedValue = expandedState
50
+ this.element.querySelector("span").textContent = expandedState ? this.collapseAllTextValue : this.expandAllTextValue
51
+ }
52
+ }
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Essence
4
+ class ExpandableToggleComponent < ApplicationComponent
5
+ attr_reader :expand_all_text, :html_options
6
+
7
+ DEFAULT_TARGET = '.expandable'
8
+
9
+ def initialize(target: DEFAULT_TARGET,
10
+ expand_all_text: nil,
11
+ collapse_all_text: nil,
12
+ **html_options)
13
+ @target = target
14
+ @expand_all_text = expand_all_text
15
+ @collapse_all_text = collapse_all_text
16
+ @html_options = html_options
17
+ end
18
+
19
+ private
20
+
21
+ def before_render
22
+ @expand_all_text ||= t('.expand_all_text')
23
+ @collapse_all_text ||= t('.collapse_all_text')
24
+
25
+ set_base_html_options(
26
+ 'expandable-toggle',
27
+ data: {
28
+ controller: 'expandable-toggle',
29
+ action: 'expandable-toggle#toggleAll',
30
+ expandable_toggle_expandable_outlet: @target,
31
+ expandable_toggle_expand_all_text_value: @expand_all_text,
32
+ expandable_toggle_collapse_all_text_value: @collapse_all_text,
33
+ expandable_toggle_all_expanded_value: false
34
+ }
35
+ )
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,7 @@
1
+ <div class="flash-container" id="flash_container">
2
+ <% helpers.flash.each do |variant, message| %>
3
+ <%= render Essence::FlashComponent.new(variant:) do %>
4
+ <%= message %>
5
+ <% end %>
6
+ <% end %>
7
+ </div>
@@ -0,0 +1,101 @@
1
+ .flash {
2
+ background-color: var(--notification-background);
3
+ border-radius: var(--notification-borderRadius);
4
+ box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.2);
5
+ overflow: hidden;
6
+ display: inline-flex;
7
+ position: relative;
8
+ right: 25px;
9
+ top: 97px;
10
+ pointer-events: auto;
11
+ opacity: 1;
12
+ animation: show 700ms ease-out;
13
+ }
14
+
15
+ .flash-hide {
16
+ opacity: 0;
17
+ right: -250px;
18
+ transition: all 1.3s ease-out;
19
+ }
20
+
21
+ .flash-container {
22
+ position: fixed;
23
+ right: 0;
24
+ top: 0;
25
+ z-index: 1;
26
+ pointer-events: none;
27
+ }
28
+
29
+ .flash-body {
30
+ color: var(--notification-text);
31
+ padding: 8px 14px;
32
+
33
+ &::first-letter {
34
+ text-transform: uppercase;
35
+ }
36
+ }
37
+
38
+ .flash-close {
39
+ width: 40px;
40
+ text-align: center;
41
+ cursor: pointer;
42
+ display: flex;
43
+ align-items: center;
44
+ justify-content: center;
45
+ }
46
+
47
+ .flash-close-icon {
48
+ width: 8px;
49
+ height: 8px;
50
+ position: relative;
51
+ fill: gray;
52
+ }
53
+
54
+ .flash-danger,
55
+ .flash-alert {
56
+ .flash-indicator {
57
+ background-color: var(--notification-danger);
58
+ }
59
+ }
60
+
61
+ .flash-icon {
62
+ display: block;
63
+ fill: var(--notification-background);
64
+ height: 18px;
65
+ width: 18px;
66
+ }
67
+
68
+ .flash-indicator {
69
+ padding: 10px 8px;
70
+ }
71
+
72
+ .flash-info {
73
+ .flash-indicator {
74
+ background-color: var(--notification-info);
75
+ }
76
+ }
77
+
78
+ .flash-success,
79
+ .flash-notice {
80
+ .flash-indicator {
81
+ background-color: var(--notification-success);
82
+ }
83
+ }
84
+
85
+ .flash-warning {
86
+ .flash-indicator {
87
+ background-color: var(--notification-warning);
88
+ }
89
+ }
90
+
91
+ @keyframes show {
92
+ from {
93
+ opacity: 0;
94
+ right: -250px;
95
+ }
96
+
97
+ to {
98
+ opacity: 1;
99
+ right: 25px;
100
+ }
101
+ }
@@ -0,0 +1,11 @@
1
+ <div <%= tag.attributes **html_options %>>
2
+ <div class="flash-indicator">
3
+ <%= render Essence::IconComponent.new(name: icon, class: 'flash-icon') %>
4
+ </div>
5
+ <div class="flash-body">
6
+ <%= content %>
7
+ </div>
8
+ <div class="flash-close" data-action="click->flash#dismiss">
9
+ <%= render Essence::IconComponent.new(name: 'x_mark', class: 'flash-close-icon') %>
10
+ </div>
11
+ </div>
@@ -0,0 +1,24 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+
3
+ export default class extends Controller {
4
+ connect() {
5
+ const flash = this.element
6
+
7
+ if (flash.classList.contains("flash-success") ||
8
+ flash.classList.contains("flash-notice") ||
9
+ flash.classList.contains("flash-info")) {
10
+ setTimeout(() => {
11
+ this.dismiss()
12
+ }, 3300);
13
+ }
14
+ }
15
+
16
+ dismiss() {
17
+ const flash = this.element
18
+
19
+ flash.classList.add("flash-hide")
20
+ setTimeout(() => {
21
+ flash.remove()
22
+ }, 1300)
23
+ }
24
+ }
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Essence
4
+ class FlashComponent < NotificationComponent
5
+ class ContainerComponent < ApplicationComponent; end
6
+
7
+ VARIANT_MAPPINGS = {
8
+ :success => 'flash-success',
9
+ :notice => 'flash-notice',
10
+ DEFAULT_VARIANT => 'flash-info',
11
+ :warning => 'flash-warning',
12
+ :danger => 'flash-danger',
13
+ :alert => 'flash-danger'
14
+ }.freeze
15
+
16
+ private
17
+
18
+ def before_render
19
+ set_base_html_options(
20
+ 'flash',
21
+ VARIANT_MAPPINGS[@variant],
22
+ data: {
23
+ controller: 'flash'
24
+ }
25
+ )
26
+ set_icon
27
+ end
28
+ end
29
+ end