matestack-ui-bootstrap 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +8 -0
  3. data/README.md +26 -0
  4. data/Rakefile +43 -0
  5. data/app/assets/images/avatar-placeholder.png +0 -0
  6. data/app/assets/images/icons/bootstrap-icons.svg +1 -0
  7. data/app/concepts/matestack/ui/bootstrap/apps/admin_template.rb +85 -0
  8. data/app/concepts/matestack/ui/bootstrap/components/accordion.rb +53 -0
  9. data/app/concepts/matestack/ui/bootstrap/components/alert.js +53 -0
  10. data/app/concepts/matestack/ui/bootstrap/components/alert.rb +34 -0
  11. data/app/concepts/matestack/ui/bootstrap/components/avatar.rb +27 -0
  12. data/app/concepts/matestack/ui/bootstrap/components/badge.rb +30 -0
  13. data/app/concepts/matestack/ui/bootstrap/components/breadcrumb.rb +46 -0
  14. data/app/concepts/matestack/ui/bootstrap/components/button.rb +54 -0
  15. data/app/concepts/matestack/ui/bootstrap/components/button_group.rb +36 -0
  16. data/app/concepts/matestack/ui/bootstrap/components/card.rb +100 -0
  17. data/app/concepts/matestack/ui/bootstrap/components/carousel.js +79 -0
  18. data/app/concepts/matestack/ui/bootstrap/components/carousel.rb +85 -0
  19. data/app/concepts/matestack/ui/bootstrap/components/chart.js +232 -0
  20. data/app/concepts/matestack/ui/bootstrap/components/chart.rb +71 -0
  21. data/app/concepts/matestack/ui/bootstrap/components/close.rb +30 -0
  22. data/app/concepts/matestack/ui/bootstrap/components/collapse.js +84 -0
  23. data/app/concepts/matestack/ui/bootstrap/components/collapse.rb +43 -0
  24. data/app/concepts/matestack/ui/bootstrap/components/dropdown.js +14 -0
  25. data/app/concepts/matestack/ui/bootstrap/components/dropdown.rb +116 -0
  26. data/app/concepts/matestack/ui/bootstrap/components/icon.rb +19 -0
  27. data/app/concepts/matestack/ui/bootstrap/components/list_group.rb +83 -0
  28. data/app/concepts/matestack/ui/bootstrap/components/modal.js +90 -0
  29. data/app/concepts/matestack/ui/bootstrap/components/modal.rb +106 -0
  30. data/app/concepts/matestack/ui/bootstrap/components/navbar.rb +120 -0
  31. data/app/concepts/matestack/ui/bootstrap/components/page_heading.rb +28 -0
  32. data/app/concepts/matestack/ui/bootstrap/components/pagination.rb +40 -0
  33. data/app/concepts/matestack/ui/bootstrap/components/popover.js +26 -0
  34. data/app/concepts/matestack/ui/bootstrap/components/popover.rb +92 -0
  35. data/app/concepts/matestack/ui/bootstrap/components/progress.rb +65 -0
  36. data/app/concepts/matestack/ui/bootstrap/components/scrollspy.rb +33 -0
  37. data/app/concepts/matestack/ui/bootstrap/components/section_card.rb +31 -0
  38. data/app/concepts/matestack/ui/bootstrap/components/spinner.rb +31 -0
  39. data/app/concepts/matestack/ui/bootstrap/components/tab_nav.rb +81 -0
  40. data/app/concepts/matestack/ui/bootstrap/components/tab_nav_content.rb +32 -0
  41. data/app/concepts/matestack/ui/bootstrap/components/toast.js +79 -0
  42. data/app/concepts/matestack/ui/bootstrap/components/toast.rb +99 -0
  43. data/app/concepts/matestack/ui/bootstrap/components/tooltip.js +26 -0
  44. data/app/concepts/matestack/ui/bootstrap/components/tooltip.rb +82 -0
  45. data/app/concepts/matestack/ui/bootstrap/content/collection/collection.rb +112 -0
  46. data/app/concepts/matestack/ui/bootstrap/content/collection/collection.scss +10 -0
  47. data/app/concepts/matestack/ui/bootstrap/content/collection/content.rb +101 -0
  48. data/app/concepts/matestack/ui/bootstrap/content/collection/filter.rb +33 -0
  49. data/app/concepts/matestack/ui/bootstrap/content/collection/paginate.rb +92 -0
  50. data/app/concepts/matestack/ui/bootstrap/content/figure.rb +7 -0
  51. data/app/concepts/matestack/ui/bootstrap/form/checkbox.rb +90 -0
  52. data/app/concepts/matestack/ui/bootstrap/form/date.js +38 -0
  53. data/app/concepts/matestack/ui/bootstrap/form/date.rb +98 -0
  54. data/app/concepts/matestack/ui/bootstrap/form/input.rb +123 -0
  55. data/app/concepts/matestack/ui/bootstrap/form/radio.rb +65 -0
  56. data/app/concepts/matestack/ui/bootstrap/form/select.haml +11 -0
  57. data/app/concepts/matestack/ui/bootstrap/form/select.rb +74 -0
  58. data/app/concepts/matestack/ui/bootstrap/form/submit.rb +20 -0
  59. data/app/concepts/matestack/ui/bootstrap/form/switch.rb +90 -0
  60. data/app/concepts/matestack/ui/bootstrap/layout/column.rb +47 -0
  61. data/app/concepts/matestack/ui/bootstrap/layout/container.rb +25 -0
  62. data/app/concepts/matestack/ui/bootstrap/layout/row.rb +15 -0
  63. data/app/concepts/matestack/ui/bootstrap/layout/sidebar.js +64 -0
  64. data/app/concepts/matestack/ui/bootstrap/layout/sidebar.rb +45 -0
  65. data/app/concepts/matestack/ui/bootstrap/layout/sidebar.scss +57 -0
  66. data/app/concepts/matestack/ui/bootstrap/pages/devise/sign_in.rb +40 -0
  67. data/app/concepts/matestack/ui/bootstrap/registry.rb +63 -0
  68. data/app/helpers/matestack/ui/bootstrap/application_helper.rb +13 -0
  69. data/app/javascript/matestack-ui-bootstrap/index.js +26 -0
  70. data/app/javascript/matestack-ui-bootstrap/stylesheets/matestack-ui-bootstrap.scss +65 -0
  71. data/app/javascript/packs/matestack-ui-bootstrap.js +2 -0
  72. data/config/routes.rb +2 -0
  73. data/config/webpack/development.js +5 -0
  74. data/config/webpack/environment.js +29 -0
  75. data/config/webpack/production.js +33 -0
  76. data/config/webpack/test.js +5 -0
  77. data/config/webpacker.yml +96 -0
  78. data/lib/matestack/ui/bootstrap.rb +27 -0
  79. data/lib/matestack/ui/bootstrap/engine.rb +26 -0
  80. data/lib/matestack/ui/bootstrap/version.rb +7 -0
  81. data/lib/tasks/matestack/ui/bootstrap_tasks.rake +66 -0
  82. metadata +137 -0
@@ -0,0 +1,65 @@
1
+ class Matestack::Ui::Bootstrap::Components::Progress < Matestack::Ui::Component
2
+
3
+ optional class: { as: :bs_class }
4
+ optional :text, :valuemin, :valuemax
5
+ # progress expects a number or a list containing hashes with at least a :value
6
+ # other options are :text, :class, :variant, :striped, :animated, :aria_valuenow
7
+ optional :progress
8
+ # :value
9
+ optional :variant, :striped, :animated, :height
10
+
11
+ def response
12
+ div progress_attributes do
13
+ progress = self.progress.is_a?(Array) ? self.progress : [{ value: self.progress || value, text: self.text }]
14
+ progress.each do |prog|
15
+ progress_bar(prog[:value], valuemin, valuemax,
16
+ text: prog[:text], klass: prog[:class], variant: prog[:variant] || variant,
17
+ striped: prog[:striped] || striped, animated: prog[:animated] || animated,
18
+ aria_valuenow: prog[:aria_valuenow]
19
+ )
20
+ end
21
+ yield_components
22
+ end
23
+ end
24
+
25
+ protected
26
+
27
+ def progress_attributes
28
+ attributes = {}.tap do |hash|
29
+ hash[:class] = "progress #{bs_class}".strip
30
+ hash[:attributes] = { style: "height: #{height}px;" } if height
31
+ end
32
+ html_attributes.merge(
33
+ attributes
34
+ )
35
+ end
36
+
37
+ def progress_bar(value, min, max, text: nil, klass: nil, variant: :primary, striped: false, animated: false, aria_valuenow: nil)
38
+ div progress_bar_attributes(value, klass, variant, striped, animated, aria_valuenow) do
39
+ plain text if text
40
+ end
41
+ end
42
+
43
+ def progress_bar_attributes(value, klass, variant, striped, animated, aria_valuenow)
44
+ {
45
+ class: progress_bar_classes(klass, variant, striped, animated),
46
+ attributes: {
47
+ role: :progressbar,
48
+ style: "width: #{value.to_i > 0 ? value : 0}%;",
49
+ 'aria-valuenow': aria_valuenow || value || 0,
50
+ 'aria-valuemin': valuemin || 0,
51
+ 'aria-valuemax': valuemax || 100
52
+ }
53
+ }
54
+ end
55
+
56
+ def progress_bar_classes(klass, variant, striped, animated)
57
+ [].tap do |classes|
58
+ classes << 'progress-bar'
59
+ classes << "bg-#{variant || :primary}"
60
+ classes << "progress-bar-striped" if striped
61
+ classes << "progress-bar-animated" if animated
62
+ classes << klass
63
+ end.join(' ').strip
64
+ end
65
+ end
@@ -0,0 +1,33 @@
1
+ class Matestack::Ui::Bootstrap::Components::Scrollspy < Matestack::Ui::Component
2
+
3
+ optional :offset # pixel to offset from top, by default 10
4
+ optional method: { as: :bs_method} # find which section, by default auto
5
+ optional :target # scroll target id
6
+ optional class: { as: :bs_class} # adding custom class to scrollspy
7
+
8
+ def response
9
+ div scrollspy_attributes do
10
+ yield_components
11
+ end
12
+ end
13
+
14
+ protected
15
+
16
+ def scrollspy_attributes
17
+ attributes = {}.tap do |hash|
18
+ hash[:class] = scrollspy_classes
19
+ hash[:data] = { "bs-spy": "scroll", "bs-target": "#{target}" }
20
+ hash[:data].merge!("bs-offset": offset) if offset.present?
21
+ hash[:data].merge!("bs-method": :"#{bs_method}") if bs_method.present?
22
+ end
23
+ html_attributes.merge(
24
+ attributes
25
+ )
26
+ end
27
+
28
+ def scrollspy_classes
29
+ [].tap do |classes|
30
+ classes << bs_class
31
+ end.join(' ').strip
32
+ end
33
+ end
@@ -0,0 +1,31 @@
1
+ class Matestack::Ui::Bootstrap::Components::SectionCard < Matestack::Ui::Component
2
+
3
+ optional :id, :title, :subtitle, :icon, :slots, :content_padding
4
+
5
+ def response
6
+ section id: :id, class: "section-card rounded shadow-sm mb-4 bg-white" do
7
+ div class: "d-flex flex-row justify-content-between" do
8
+ if title.present? || subtitle.present?
9
+ div class: "section-card-heading p-4" do
10
+ heading size: 5, class: "mb-0" do
11
+ bs_icon name: icon, size: "35" if icon.present?
12
+ plain title
13
+ end
14
+ small class: "text-muted" do
15
+ plain subtitle
16
+ end
17
+ end
18
+ end
19
+ if slots.present? && slots[:actions].present?
20
+ div class: "section-card-actions p-4" do
21
+ slot slots[:actions]
22
+ end
23
+ end
24
+ end
25
+ div class: "section-card-content #{'p-4' unless content_padding == false} #{'pt-1' if title || subtitle}" do
26
+ yield_components
27
+ end
28
+ end
29
+ end
30
+
31
+ end
@@ -0,0 +1,31 @@
1
+ class Matestack::Ui::Bootstrap::Components::Spinner < Matestack::Ui::Component
2
+
3
+ optional class: { as: :bs_class }
4
+ optional :kind, :variant, :size, :sr_only
5
+
6
+ def response
7
+ div spinner_attributes do
8
+ span class: "sr-only", text: sr_only
9
+ end
10
+ end
11
+
12
+ protected
13
+
14
+ def spinner_attributes
15
+ html_attributes.merge(
16
+ class: spinner_class,
17
+ attributes: { 'role': "status" }
18
+ )
19
+ end
20
+
21
+ def spinner_class
22
+ [].tap do |classes|
23
+ spinner_kind = kind || :border
24
+ classes << "spinner-#{spinner_kind}"
25
+ classes << "text-#{variant || 'primary'}"
26
+ classes << "spinner-#{spinner_kind}-sm" if size
27
+ #optional classes
28
+ classes << bs_class
29
+ end.join(' ').strip
30
+ end
31
+ end
@@ -0,0 +1,81 @@
1
+ class Matestack::Ui::Bootstrap::Components::TabNav < Matestack::Ui::Component
2
+
3
+ requires :id
4
+
5
+ optional :items, :variant, :fill, :justified, :vertical, :vertical_up_to_sm,
6
+ :vertical_up_to_md, :vertical_up_to_xl, :horizontal,
7
+ class: { as: :bs_class }, attributes: { as: :bs_attrs}
8
+
9
+ def response
10
+ ul nav_attributes do
11
+ nav_items_partial if items.present?
12
+ end
13
+ div class: "tab-content", id: "#{id}Content" do
14
+ yield_components
15
+ end
16
+ end
17
+
18
+ protected
19
+
20
+ def nav_items_partial
21
+ items.each do |item|
22
+ li class: "nav-item", attributes: { role: "presentation" } do
23
+ # '<a class="nav-link active" id="pills-home-tab" data-toggle="pill" href="#pills-home" role="tab" aria-controls="pills-home" aria-selected="true">Home</a>'
24
+ link class: "nav-link #{'active' if item[:active]}",
25
+ id: "tab-#{item[:id]}",
26
+ path: "#tab-#{item[:id]}-content",
27
+ attributes: {
28
+ role: "tab",
29
+ "aria-controls": "tab-#{item[:id]}",
30
+ "aria-selected": "#{'true' if item[:active]}",
31
+ "data-bs-toggle": "tab"
32
+ } do
33
+ bs_icon name: item[:icon], size: 20 if item[:icon]
34
+ span class: "#{'ps-3' if item[:icon]}", text: item[:text] if item[:text]
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ def link_attrs path, active, disabled, delay=nil
41
+ {}.tap do |hash|
42
+ hash[:class] = "nav-link #{'active' if path == request.fullpath } #{'disabled' if disabled}"
43
+
44
+ hash[:attributes] = {}.tap do |hash|
45
+ hash[:'aria-selected'] = path == request.fullpath ? 'true' : 'false'
46
+ hash[:'aria-current'] = 'page' if active == true
47
+ hash[:'aria-disabled'] = 'true' if disabled
48
+ hash[:role] = "tab" if toggle.present?
49
+ hash[:'aria-controls'] = "#{path.gsub('#','')}" if toggle.present?
50
+ end
51
+
52
+ hash[:data] = { "bs-toggle": "pill" } if pills
53
+ hash[:data] = { "bs-toggle": "tab" } if tabs
54
+ hash[:path] = path
55
+ end
56
+ end
57
+
58
+ def nav_attributes
59
+ html_attributes.merge(
60
+ id: id,
61
+ class: nav_classes,
62
+ attributes: { role: "tablist"}
63
+ )
64
+ end
65
+
66
+ def nav_classes
67
+ [].tap do |classes|
68
+ classes << 'nav'
69
+ classes << 'nav-tabs' if variant == :tabs || variant.nil?
70
+ classes << 'nav-pills' if variant == :pills
71
+ classes << 'nav-fill' if fill
72
+ classes << 'nav-justified' if justified
73
+ classes << 'flex-column' if vertical
74
+ classes << 'flex-column flex-sm-column flex-md-row' if vertical_up_to_sm
75
+ classes << 'flex-column flex-sm-column flex-md-column flex-lg-row' if vertical_up_to_md
76
+ classes << 'flex-column flex-sm-column flex-md-column flex-lg-column flex-xl-row' if vertical_up_to_xl
77
+ classes << "justify-content-#{horizontal}" if horizontal.present?
78
+ classes << bs_class
79
+ end.join(' ').strip
80
+ end
81
+ end
@@ -0,0 +1,32 @@
1
+ class Matestack::Ui::Bootstrap::Components::TabNavContent < Matestack::Ui::Component
2
+
3
+ requires :id
4
+
5
+ optional :tabs, :pills, :active, class: { as: :bs_class }, attributes: { as: :bs_attrs}
6
+
7
+ def response
8
+ div tab_content_attributes do
9
+ yield_components
10
+ end
11
+ end
12
+
13
+ protected
14
+
15
+ def tab_content_attributes
16
+ html_attributes.merge(
17
+ id: "tab-#{id}-content",
18
+ class: tab_content_classes,
19
+ attributes: { role: "tabpanel", "aria-labelledby": "tab-#{id}" }
20
+ )
21
+ end
22
+
23
+ def tab_content_classes
24
+ [].tap do |classes|
25
+ classes << 'tab-pane'
26
+ classes << 'fade'
27
+ classes << 'show ' if active
28
+ classes << 'active' if active
29
+ classes << bs_class
30
+ end.join(' ').strip
31
+ end
32
+ end
@@ -0,0 +1,79 @@
1
+ import * as bootstrap from 'bootstrap'
2
+
3
+ MatestackUiCore.Vue.component('matestack-ui-bootstrap-toast', {
4
+
5
+ mixins: [MatestackUiCore.componentMixin],
6
+ data() {
7
+ return {
8
+ toastsInstance: undefined,
9
+ eventData: {},
10
+ showing: false,
11
+ };
12
+ },
13
+ methods: {
14
+ show: function(event){
15
+ const self = this;
16
+ if(this.componentConfig["autohide"]){
17
+ setTimeout(function () {
18
+ self.showing = false;
19
+ }, 5000);
20
+ }
21
+ this.showing = true
22
+ this.eventData = event
23
+ },
24
+ hide: function(event){
25
+ const self = this;
26
+ this.showing = false
27
+ setTimeout(function () {
28
+ self.eventData = false;
29
+ }, 500);
30
+ },
31
+ dispose: function(){
32
+ const self = this;
33
+ self.toastsInstance.dispose()
34
+ self.toastsInstance = new bootstrap.Toast(self.$el)
35
+ }
36
+ },
37
+ mounted: function() {
38
+ const self = this;
39
+ var myToasts = self.$el
40
+ self.toastsInstance = new bootstrap.Toast(myToasts)
41
+ },
42
+ created: function() {
43
+ const self = this
44
+
45
+ if(this.componentConfig["show_on"] != undefined){
46
+ var show_events = this.componentConfig["show_on"].split(",")
47
+ show_events.forEach(show_event => MatestackUiCore.matestackEventHub.$on(show_event.trim(), self.show));
48
+ }
49
+
50
+ if(this.componentConfig["hide_on"] != undefined){
51
+ var show_events = this.componentConfig["hide_on"].split(",")
52
+ show_events.forEach(show_event => MatestackUiCore.matestackEventHub.$on(show_event.trim(), self.hide));
53
+ }
54
+
55
+ if(this.componentConfig["dispose_on"] != undefined){
56
+ var show_events = this.componentConfig["dispose_on"].split(",")
57
+ show_events.forEach(show_event => MatestackUiCore.matestackEventHub.$on(show_event.trim(), self.dispose));
58
+ }
59
+ },
60
+
61
+ beforeDestroy: function() {
62
+ const self = this
63
+ MatestackUiCore.matestackEventHub.$off(this.componentConfig["show_on"], self.show);
64
+ MatestackUiCore.matestackEventHub.$off(this.componentConfig["hide_on"], self.hide);
65
+ MatestackUiCore.matestackEventHub.$off(this.componentConfig["dispose_on"], self.hide);
66
+ if(this.componentConfig["show_on"] != undefined){
67
+ var shown_events = this.componentConfig["show_on"].split(",")
68
+ shown_events.forEach(show_event => MatestackUiCore.matestackEventHub.$off(show_event.trim(), self.show));
69
+ }
70
+ if(this.componentConfig["hide_on"] != undefined){
71
+ var hiden_events = this.componentConfig["hide_on"].split(",")
72
+ hiden_events.forEach(hide_event => MatestackUiCore.matestackEventHub.$off(hide_event.trim(), self.hide));
73
+ }
74
+ if(this.componentConfig["dispose_on"] != undefined){
75
+ var hiden_events = this.componentConfig["dispose_on"].split(",")
76
+ hiden_events.forEach(hide_event => MatestackUiCore.matestackEventHub.$off(hide_event.trim(), self.dispose));
77
+ }
78
+ },
79
+ });
@@ -0,0 +1,99 @@
1
+ class Matestack::Ui::Bootstrap::Components::Toast < Matestack::Ui::VueJsComponent
2
+ vue_js_component_name "matestack-ui-bootstrap-toast"
3
+
4
+ # header attributes, expects a hash or string
5
+ # possible keys `:icon_class, :icon, :title, :subtitle`
6
+ optional :header
7
+ # body expects a string as message inside toast
8
+ optional :body
9
+ # placement attributes, expects a hash wiht possible keys: position, min-height
10
+ optional :placement # for adding custom css style
11
+ optional :important, :delay, :autohide, :animation
12
+ optional class: { as: :bs_class }, attributes: { as: :bs_attrs }, data: { as: :bs_data }
13
+ optional :slots
14
+
15
+ def response
16
+ standard_placement_partial
17
+ # standard_placement_partial unless placement.present?
18
+ # custom_placement_partial if placement.present?
19
+ end
20
+
21
+ protected
22
+
23
+ def custom_placement_partial
24
+ div attributes: placement_attrs do
25
+ standard_placement_partial
26
+ end
27
+ end
28
+
29
+ def standard_placement_partial
30
+ div toast_attributes do
31
+ header_partial if header || slots && slots[:header]
32
+ body_partial
33
+ end
34
+ end
35
+
36
+ def header_partial
37
+ header = self.header.is_a?(Hash) ? self.header : { title: self.header }
38
+ div class: "toast-header" do
39
+ img class: "#{'rounded me-2' || header[:icon_class]}", path: header[:icon] if header[:icon].present?
40
+ strong class: "me-auto", text: header[:title] if header[:title].present?
41
+ small text: header[:subtitle] if header[:subtitle].present?
42
+
43
+ slot slots[:header] if slots && slots[:header]
44
+ bs_close dismiss: 'toast', class: "ms-2 mb-1", attributes: { "@click": "hide()"}
45
+ end
46
+
47
+ end
48
+
49
+ def body_partial
50
+ div class: "toast-body" do
51
+ plain body if body
52
+ end
53
+ unless header || slots && slots[:header]
54
+ bs_close dismiss: 'toast', class: "ms-auto me-2 btn-close-white", attributes: { "@click": "hide()"}
55
+ end
56
+ end
57
+
58
+ def toast_attributes
59
+ html_attributes.merge(
60
+ class: toast_classes,
61
+ attributes: toast_attrs,
62
+ data: toast_data
63
+ )
64
+ end
65
+
66
+ def toast_data
67
+ (bs_data || {}).tap do |hash|
68
+ hash["bs-delay"] = delay.nil? ? 5000 : delay
69
+ hash["bs-autohide"] = autohide.nil? ? "true" : "#{autohide}"
70
+ hash["bs-animation"] = animation.nil? ? "true" : "#{animation}"
71
+ end
72
+ end
73
+
74
+ def toast_attrs
75
+ (bs_attrs || {}).tap do |hash|
76
+ hash[:role] = (important == false ? 'status' : 'alert')
77
+ hash[:'aria-live'] = (important ? 'assertive' : 'polite') if important.present? && !placement.present?
78
+ hash[:'aria-live'] = 'assertive' unless important.present?
79
+ hash[:'aria-atomic'] = 'true' unless placement.present?
80
+ hash[:style] = "z-index: 10000; position: fixed; #{placement[:position] || 'top: 0; right: 0;' }" if placement.present?
81
+ hash["v-bind:class"] = "{'show' : showing }"
82
+ end
83
+ end
84
+
85
+ def toast_classes
86
+ [].tap do |classes|
87
+ classes << 'toast p-0 fade d-flex align-items-center border-0'
88
+ classes << bs_class
89
+ end.join(' ').strip
90
+ end
91
+
92
+ def placement_attrs
93
+ {}.tap do |hash|
94
+ hash[:'aria-live'] = (important ? 'assertive' : 'polite') if important.present?
95
+ hash[:'aria-atomic'] = 'true'
96
+ hash[:style] = "position: relative; min-height: #{placement[:height]};"
97
+ end
98
+ end
99
+ end