aerogel-admin 1.4.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +13 -0
  6. data/Rakefile +1 -0
  7. data/aerogel-admin.gemspec +31 -0
  8. data/app/helpers/admin.rb +54 -0
  9. data/app/helpers/decorators.rb +29 -0
  10. data/app/helpers/icons.rb +11 -0
  11. data/app/helpers/table_builder.rb +8 -0
  12. data/app/helpers/tabs_builder.rb +7 -0
  13. data/app/routes/admin.rb +37 -0
  14. data/app/routes/users.rb +71 -0
  15. data/app/routes/users_access.rb +54 -0
  16. data/app/routes/users_roles.rb +53 -0
  17. data/assets/fonts/aerogel-icons.css +28 -0
  18. data/assets/fonts/aerogel-icons.eot +0 -0
  19. data/assets/fonts/aerogel-icons.svg +11 -0
  20. data/assets/fonts/aerogel-icons.ttf +0 -0
  21. data/assets/fonts/aerogel-icons.woff +0 -0
  22. data/assets/javascripts/.gitkeep +0 -0
  23. data/assets/javascripts/controllers/admin-modal.js.coffee +7 -0
  24. data/assets/javascripts/controllers/admin-modal/admin-modal-form-buttons.js.coffee +56 -0
  25. data/assets/javascripts/controllers/admin.js.coffee +13 -0
  26. data/assets/javascripts/controllers/admin/selectize-inputs.js.coffee +7 -0
  27. data/assets/javascripts/controllers/admin/top-menu-shadow.js.coffee +9 -0
  28. data/assets/javascripts/utils/ajax-spinner.js.coffee +26 -0
  29. data/assets/javascripts/utils/ajax-watcher.js.coffee +18 -0
  30. data/assets/javascripts/utils/bootstrap-modal-reload.js.coffee +8 -0
  31. data/assets/javascripts/utils/form-data-async.js.coffee +27 -0
  32. data/assets/javascripts/utils/i18n.js.coffee +27 -0
  33. data/assets/javascripts/utils/on-future-elements.js.coffee +15 -0
  34. data/assets/stylesheets/admin/bootstrap-settings.css.scss +33 -0
  35. data/assets/stylesheets/admin/global.css.scss +61 -0
  36. data/assets/stylesheets/admin/styles/ajax-indicator.css.scss +26 -0
  37. data/assets/stylesheets/admin/styles/bootstrap-modal.css.scss +24 -0
  38. data/assets/stylesheets/admin/styles/language-selector.css.scss +5 -0
  39. data/assets/stylesheets/admin/styles/page-header.css.scss +7 -0
  40. data/assets/stylesheets/admin/styles/sticky-footer-navbar.css.scss +34 -0
  41. data/assets/stylesheets/admin/styles/table.css.scss +3 -0
  42. data/assets/stylesheets/admin/styles/top-menu.css.scss +3 -0
  43. data/assets/stylesheets/admin/utils/center-absolutely.css.scss +5 -0
  44. data/assets/stylesheets/controllers/admin.css.scss +14 -0
  45. data/assets/vendor/bootstrap-datetimepicker.css.scss +1 -0
  46. data/assets/vendor/bootstrap-datetimepicker.js.coffee +1 -0
  47. data/assets/vendor/bootstrap-datetimepicker/bootstrap-datetimepicker.min.css +5 -0
  48. data/assets/vendor/bootstrap-datetimepicker/bootstrap-datetimepicker.min.js +1 -0
  49. data/assets/vendor/bootstrap-datetimepicker/bootstrap-datetimepicker.ru.js +163 -0
  50. data/assets/vendor/moment.js.coffee +1 -0
  51. data/assets/vendor/momentjs/moment-with-langs.min.js +9 -0
  52. data/assets/vendor/selectize.css.scss +2 -0
  53. data/assets/vendor/selectize.js.coffee +1 -0
  54. data/assets/vendor/selectize/selectize.bootstrap3.css +385 -0
  55. data/assets/vendor/selectize/selectize.css +311 -0
  56. data/assets/vendor/selectize/selectize.default.css +381 -0
  57. data/assets/vendor/selectize/selectize.js +3345 -0
  58. data/assets/vendor/smart-list-table.css.scss +42 -0
  59. data/assets/vendor/smart-list-table.js.coffee +1 -0
  60. data/assets/vendor/smart-list-table/smart-list-table-row.js.coffee +63 -0
  61. data/assets/vendor/smart-list-table/smart-list-table.css.scss +54 -0
  62. data/assets/vendor/smart-list-table/smart-list-table.js.coffee +133 -0
  63. data/assets/vendor/smart-tree-table.css.scss +42 -0
  64. data/assets/vendor/smart-tree-table.js.coffee +1 -0
  65. data/assets/vendor/smart-tree-table/smart-tree-table-drag-n-drop.js.coffee +190 -0
  66. data/assets/vendor/smart-tree-table/smart-tree-table-row.js.coffee +78 -0
  67. data/assets/vendor/smart-tree-table/smart-tree-table.css.scss +54 -0
  68. data/assets/vendor/smart-tree-table/smart-tree-table.js.coffee +267 -0
  69. data/assets/vendor/spin.js +353 -0
  70. data/config/README.md +3 -0
  71. data/config/development/.keep +0 -0
  72. data/config/production/.keep +0 -0
  73. data/db/model/README.md +1 -0
  74. data/db/model/admin/user_new_form.rb +40 -0
  75. data/db/model/user.rb +26 -0
  76. data/db/seed/01_admin_roles.seed +8 -0
  77. data/db/seed/02_admin_access.seed +24 -0
  78. data/db/seed/development/.keep +0 -0
  79. data/db/seed/development/20_users.seed +45 -0
  80. data/db/seed/development/admin_users.seed +38 -0
  81. data/db/seed/production/.keep +0 -0
  82. data/lib/aerogel/admin.rb +25 -0
  83. data/lib/aerogel/admin/core.rb +14 -0
  84. data/lib/aerogel/admin/menu.rb +38 -0
  85. data/lib/aerogel/admin/table_builder.rb +100 -0
  86. data/lib/aerogel/admin/tabs_builder.rb +69 -0
  87. data/lib/aerogel/admin/version.rb +5 -0
  88. data/locales/actions.en.yml +27 -0
  89. data/locales/actions.ru.yml +28 -0
  90. data/locales/admin.en.yml +14 -0
  91. data/locales/admin.ru.yml +14 -0
  92. data/locales/models.en.yml +8 -0
  93. data/locales/models.ru.yml +8 -0
  94. data/locales/views.en.yml +46 -0
  95. data/locales/views.ru.yml +46 -0
  96. data/public/README.md +1 -0
  97. data/rake/README.md +3 -0
  98. data/views/admin/index.html.erb +3 -0
  99. data/views/admin/table_builder/standard/_table_column.html.erb +3 -0
  100. data/views/admin/table_builder/standard/_table_row.html.erb +7 -0
  101. data/views/admin/table_builder/standard/table.html.erb +10 -0
  102. data/views/admin/tabs_builder/standard/_tab.html.erb +3 -0
  103. data/views/admin/tabs_builder/standard/tabs.html.erb +3 -0
  104. data/views/admin/users/_tabs.html.erb +8 -0
  105. data/views/admin/users/access/delete.html.erb +12 -0
  106. data/views/admin/users/access/edit.html.erb +9 -0
  107. data/views/admin/users/access/index.html.erb +23 -0
  108. data/views/admin/users/access/new.html.erb +9 -0
  109. data/views/admin/users/delete.html.erb +12 -0
  110. data/views/admin/users/edit.html.erb +46 -0
  111. data/views/admin/users/index.html.erb +31 -0
  112. data/views/admin/users/new.html.erb +11 -0
  113. data/views/admin/users/roles/delete.html.erb +12 -0
  114. data/views/admin/users/roles/edit.html.erb +9 -0
  115. data/views/admin/users/roles/index.html.erb +21 -0
  116. data/views/admin/users/roles/new.html.erb +7 -0
  117. data/views/form_builder/standard/field_multiselect.erb +14 -0
  118. data/views/form_builder/standard/field_select.erb +17 -0
  119. data/views/layouts/admin.html.erb +63 -0
  120. data/views/layouts/admin/_ajax_indicator.html.erb +4 -0
  121. data/views/layouts/admin/_alerts.html.erb +22 -0
  122. data/views/layouts/admin/_menu.html.erb +50 -0
  123. data/views/layouts/admin/_menu_item.html.erb +5 -0
  124. data/views/layouts/admin/_modals.html.erb +8 -0
  125. data/views/layouts/admin/modal.html.erb +38 -0
  126. metadata +280 -0
@@ -0,0 +1,11 @@
1
+ <?xml version="1.0" standalone="no"?>
2
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
3
+ <svg xmlns="http://www.w3.org/2000/svg">
4
+ <metadata>Generated by IcoMoon</metadata>
5
+ <defs>
6
+ <font id="aerogel-icons" horiz-adv-x="512">
7
+ <font-face units-per-em="512" ascent="480" descent="-32" />
8
+ <missing-glyph horiz-adv-x="512" />
9
+ <glyph unicode="&#x20;" d="" horiz-adv-x="256" />
10
+ <glyph unicode="&#xe001;" d="M19 475.5h474q5.5 0 9.5-4t4-9.5v-474q0-5.5-4-9.5t-9.5-4h-474q-5.5 0-9.5 4t-4 9.5v474q0 5.5 4 9.5t9.5 4zM256 232l228.5 228.5h-457zM491.5-4v457.5l-228.5-228.5zM20.5 453.5v-457l228.5 228.5zM27.5-10.5h456.5l-228 228.5z" />
11
+ </font></defs></svg>
File without changes
@@ -0,0 +1,7 @@
1
+ #= require utils/form-data-async
2
+ #= require_tree ./admin-modal
3
+
4
+ $ ->
5
+ # console?.log "/admin/admin-modal enabling async forms: data-target: .modal-content"
6
+ form_data_async_enable $(".modal-content FORM"), ".modal-content"
7
+ console?.log "** admin/modal loaded"
@@ -0,0 +1,56 @@
1
+ #
2
+ # Move 'submit' and 'cancel' buttons from Bootstrap modal's body to footer
3
+ #
4
+
5
+ admin_modal_replace_buttons = (el, target) ->
6
+ # console?.log "Moving buttons around: #{$(el).size()}"
7
+ $(el).each ->
8
+ button = $(this)
9
+ form = button.closest "form"
10
+ target = form.closest('.modal-content').find target
11
+ if button.attr('type') == 'submit'
12
+ admin_modal_replace_submit_button button, form, target
13
+ if button.attr('type') == 'cancel'
14
+ admin_modal_replace_cancel_button button, form, target
15
+ if button.attr('type') == 'select'
16
+ admin_modal_replace_other_button button, form, target
17
+
18
+
19
+ # Process 'submit' button
20
+ #
21
+ admin_modal_replace_submit_button = (button, form, target) ->
22
+ button.click ->
23
+ form.submit()
24
+ button.appendTo target
25
+ enable_form_submit_on_enter form
26
+
27
+ # Process 'cancel' button
28
+ #
29
+ admin_modal_replace_cancel_button = (button, form, target) ->
30
+ button.attr 'data-dismiss', 'modal'
31
+ button.appendTo target
32
+
33
+ # Process 'cancel' button
34
+ #
35
+ admin_modal_replace_other_button = (button, form, target) ->
36
+ # button.attr 'data-dismiss', 'modal'
37
+ button.appendTo target
38
+
39
+
40
+
41
+ enable_form_submit_on_enter = (form) ->
42
+ unless form.attr 'form-submit-on-enter-enabled'
43
+ form.keypress (e) ->
44
+ if e.keyCode == 13 && ( e.target.type != 'textarea' )
45
+ e.preventDefault()
46
+ $(this).submit()
47
+ form.attr 'form-submit-on-enter-enabled', true
48
+ # console?.log "Enabled form keypress"
49
+
50
+
51
+ $ ->
52
+ admin_modal_replace_buttons(
53
+ ".modal-body .btn[type=submit], .modal-body .btn[type=cancel], .modal-body .btn[type=select]",
54
+ ".modal-footer"
55
+ )
56
+
@@ -0,0 +1,13 @@
1
+ #= require bootstrap
2
+ #= require utils/bootstrap-modal-reload
3
+ #= require utils/ajax-watcher
4
+ #= require utils/ajax-spinner
5
+ #= require utils/on-future-elements
6
+ #= require utils/i18n
7
+ #= require spin
8
+ #= require selectize
9
+
10
+
11
+ #= require_tree ./admin
12
+
13
+ console?.log "** admin/ loaded"
@@ -0,0 +1,7 @@
1
+ $ ->
2
+ # console?.log "** selectize-inputs: initialized"
3
+
4
+ on_future_elements 'select.selectize:not(.selectize-applied)', (e) ->
5
+ console?.log "** selectize-inputs: element observed:", $(e).get(0).tagName
6
+ $(e).addClass('selectize-applied')
7
+ $(e).selectize();
@@ -0,0 +1,9 @@
1
+
2
+ $ ->
3
+ $(window).scroll ->
4
+ y = $(window).scrollTop()
5
+ if y > 0
6
+ $("#top-menu").addClass "has-shadow"
7
+ else
8
+ $("#top-menu").removeClass "has-shadow"
9
+ # console?.log "admin/top-menu-shadow loaded"
@@ -0,0 +1,26 @@
1
+ ajax_spinner = null
2
+
3
+ ajax_spinner_opts =
4
+ lines: 13 # The number of lines to draw
5
+ length: 7 # The length of each line
6
+ width: 3 # The line thickness
7
+ radius: 10 # The radius of the inner circle
8
+ corners: 1 # Corner roundness (0..1)
9
+ rotate: 0 # The rotation offset
10
+ direction: 1 # 1: clockwise, -1: counterclockwise
11
+ color: '#fff' # #rgb or #rrggbb or array of colors
12
+ speed: 1 # Rounds per second
13
+ trail: 60 # Afterglow percentage
14
+ shadow: false # Whether to render a shadow
15
+ hwaccel: false # Whether to use hardware acceleration
16
+
17
+ # Shows ajax spinner in a +target+ element specified by selector.
18
+ #
19
+ ( exports ? this ).ajax_spinner_show = (target) ->
20
+ target = $(target).get( 0 )
21
+ ajax_spinner = new Spinner( ajax_spinner_opts ).spin target
22
+
23
+ # Hides current ajax spinner.
24
+ #
25
+ ( exports ? this ).ajax_spinner_hide = ->
26
+ ajax_spinner.stop()
@@ -0,0 +1,18 @@
1
+
2
+ show_global_ajax_indicator = ->
3
+ $("#ajax-indicator").show()
4
+ ajax_spinner_show "#ajax-indicator .ajax-indicator-inner"
5
+
6
+ hide_global_ajax_indicator = ->
7
+ ajax_spinner_hide()
8
+ $("#ajax-indicator").hide()
9
+
10
+
11
+ $ ->
12
+ $(document).bind "ajaxStart", ->
13
+ console?.log "** ajax-watcher: start"
14
+ show_global_ajax_indicator()
15
+ $(document).bind "ajaxStop", ->
16
+ console?.log "** ajax-watcher: stop"
17
+ hide_global_ajax_indicator()
18
+ # console?.log "** ajax-watcher: initialized"
@@ -0,0 +1,8 @@
1
+ # Forces to reload Bootstrap modal on each access.
2
+ # Otherwise the modal contains the same content after it is invoked once.
3
+ #
4
+ $ ->
5
+ $(document).on 'hidden.bs.modal', (e) ->
6
+ # console?.log "bootstrap modal hidden:", e.target
7
+ $(e.target).removeData 'bs.modal'
8
+ $(e.target).find(".modal-content").empty()
@@ -0,0 +1,27 @@
1
+ # Redefines submit behaviour for forms specified by +el+ selector.
2
+ #
3
+ # On submit handler composes and sends AJAX request, renders result
4
+ # in an element specified by form's +target+ attribute.
5
+ #
6
+ ( exports ? this ).form_data_async_enable = (el, target) ->
7
+ $(el).on 'submit', (event)->
8
+ form = $(this)
9
+ $.ajax
10
+ type: form.attr 'method'
11
+ url: form.attr 'action'
12
+ data: form.serialize()
13
+ error: (x, e, status ) ->
14
+ console?.log "form-data-async submit error: #{e}, status: #{status}"
15
+ success: (data, status, xhr) ->
16
+ content_type = xhr.getResponseHeader 'content-type'
17
+ if /^text\/html/.test content_type
18
+ $(target).empty()
19
+ $(target).html data
20
+ else
21
+ console?.log "form-data-async ignoring content: #{content_type}"
22
+
23
+ event.preventDefault()
24
+ console?.log "form-data-async enabled for #{el}, target:#{target}"
25
+
26
+ $ ->
27
+ console?.log "form-data-async loaded"
@@ -0,0 +1,27 @@
1
+ #
2
+ log = (msg) ->
3
+ console?.log "** admin/i18n: #{msg}"
4
+
5
+
6
+ class I18nProcessor
7
+ # @default_locale: 'en'
8
+
9
+ constructor: ( @default_locale = 'en', @options = {} ) ->
10
+ # ...
11
+ log "locale processor initialized: #{@default_locale}"
12
+ @set @default_locale
13
+
14
+ # Sets new locale
15
+ #
16
+ set: (locale) ->
17
+ @current_locale = locale
18
+ log "locale set to: #{locale}"
19
+
20
+ # Returns current locale
21
+ #
22
+ locale: ->
23
+ @current_locale
24
+
25
+ @I18n = new I18nProcessor
26
+
27
+
@@ -0,0 +1,15 @@
1
+ # Applies +func+ to elements selected by +el+ on _each_ DOM insertion.
2
+ #
3
+ # Example:
4
+ # on_future_elements "select.selectize:not(.selectize-applied)", (e) ->
5
+ # $(e).selectize()
6
+ # $(e).addClass "selectize-applied"
7
+ #
8
+ ( exports ? this ).on_future_elements = (el, func) ->
9
+ $(document).on 'DOMNodeInserted', (e) ->
10
+ $(el).each ->
11
+ func( this )
12
+
13
+
14
+ #$(document).on 'DOMNodeInserted', 'input', (e) ->
15
+ # console?.log "** select2ify: element loaded"
@@ -0,0 +1,33 @@
1
+
2
+ // This is the place for customizing your bootstrap installation
3
+ //
4
+
5
+ $component-active-bg: $item-selected-bg;
6
+ $component-active-fg: $item-selected-fg;
7
+
8
+ // modals
9
+ $modal-title-padding: 7px;
10
+ $modal-inner-padding: 7px;
11
+ $modal-backdrop-bg: rgba(0,0,0,0.3); // #fff;
12
+ // $modal-header-bg: #eee;
13
+ $modal-footer-bg: #eee;
14
+ $modal-header-border-color: transparent;
15
+ $modal-footer-border-color: #ccc;
16
+ $modal-content-border-color: #888;
17
+ $modal-vertical-pos: 30%;
18
+ $modal-radius: 6px;
19
+
20
+ // navbar settings
21
+ $navbar-height: $header-height;
22
+ $navbar-inverse-bg: $top-menu-bg;
23
+ $navbar-inverse-link-color: $top-menu-fg;
24
+
25
+
26
+ // base colors:
27
+ $brand-danger: $item-with-error-fg;
28
+
29
+ // inputs
30
+ $input-color-placeholder: #ddd;
31
+ $input-border-focus: $input-border-focus-color;
32
+ // $input-border-radius:
33
+ $input-border: $input-border-color;
@@ -0,0 +1,61 @@
1
+ /*
2
+ * Global styles
3
+ */
4
+ $body-bg: white;
5
+ $text-color: black;
6
+ $text-disabled-color: #d8d8d8;
7
+ $text-secondary-color: #d8d8d8;
8
+ $link-color: #9ac2e7;
9
+ $link-hover-color: darken($link-color, 15%);
10
+ $link-js-color: #d8d8d8;
11
+ $link-js-hover-color: darken($link-js-color, 30%);
12
+
13
+ $item-selected-bg: #428bca;
14
+ $item-selected-fg: white;
15
+ $item-hover-bg: #f5f5f5;
16
+ $item-hover-fg: inherit;
17
+ $item-disabled-fg: #afafaf;
18
+ $item-disabled-bg: inherit;
19
+ $item-nodata-fg: #d8d8d8;
20
+ $item-nodata-bg: inherit;
21
+ $item-with-error-fg: #a94442;
22
+ $item-with-error-bg: inherit;
23
+
24
+ /*
25
+ * Inputs styling
26
+ */
27
+ $input-placeholder-fg: #ddd;
28
+ $input-border-focus-color: #66afe9;
29
+ $input-border-radius: 3px;
30
+ $input-border-color: #d8d8d8;
31
+
32
+ /*
33
+ * Grid layout main column width
34
+ */
35
+ $layout-width: 800px;
36
+
37
+
38
+ /*
39
+ * Header settings
40
+ */
41
+ $header-height: 40px;
42
+ $top-menu-bg: #4a484c;
43
+ $top-menu-fg: #e4e4e4;
44
+
45
+ /*
46
+ * Footer settings
47
+ */
48
+ $footer-bg: #4a484c;
49
+ $footer-fg: #848484;
50
+ $footer-link-color: #9ac2e7;
51
+ $footer-height: 50px;
52
+
53
+
54
+ // Smart Tree Table settings
55
+ $stt-selected-bg: $item-selected-bg;
56
+ $stt-selected-fg: $item-selected-fg;
57
+ $stt-hover-bg: $item-hover-bg;
58
+ $stt-hover-fg: $item-hover-fg;
59
+ $stt-drag-over-bg: $item-hover-bg;
60
+ $stt-drag-over-fg: $item-hover-fg;
61
+
@@ -0,0 +1,26 @@
1
+ #ajax-indicator {
2
+ display: none;
3
+ position: fixed;
4
+ top: 0;
5
+ left: 0;
6
+ right: 0;
7
+ bottom: 0;
8
+ z-index: 2000;
9
+ // width: 50%;
10
+ // height: 50%;
11
+
12
+ .ajax-indicator-inner {
13
+ // font-size: 36px;
14
+ height: 72px;
15
+ width: 72px;
16
+ background: #111;
17
+ opacity: 0.7;
18
+ color: white;
19
+ text-align: center;
20
+ border-radius: 5px 5px 5px 5px;
21
+ @extend .center-absolutely;
22
+ // top: 50%;
23
+
24
+ }
25
+ }
26
+
@@ -0,0 +1,24 @@
1
+ $modal-header-bg: transparent !default;
2
+ $modal-footer-bg: transparent !default;
3
+
4
+
5
+ div.modal-header {
6
+ background-color: $modal-header-bg;
7
+ border-radius: $modal-radius $modal-radius 0 0;
8
+ }
9
+ div.modal-footer {
10
+ background-color: $modal-footer-bg;
11
+ border-radius: 0 0 $modal-radius $modal-radius;
12
+ margin-top: 0;
13
+ }
14
+
15
+ $modal-vertical-pos: 50% !default;
16
+ .modal-dialog {
17
+ // margin-top:$modal-vertical-pos;
18
+ }
19
+ .modal-content {
20
+ // margin-top:-$modal-vertical-pos;
21
+
22
+ // FIXME get rid of border around empty modal during loading of remote content
23
+ border: none;
24
+ }
@@ -0,0 +1,5 @@
1
+ .language-selector {
2
+ .dropdown-menu {
3
+ min-width: 0px !important;
4
+ }
5
+ }
@@ -0,0 +1,7 @@
1
+ .page-header {
2
+ margin: 0 0 10px;
3
+ padding-bottom: 0;
4
+ h1 {
5
+ margin: 10px 0 10px;
6
+ }
7
+ }
@@ -0,0 +1,34 @@
1
+ /* Sticky footer styles
2
+ -------------------------------------------------- */
3
+ html,
4
+ body {min-height:100%; padding:0; margin:0;}
5
+ body {
6
+ padding: $header-height 0 $footer-height 0;
7
+ position:absolute;
8
+ top:0; bottom:0; left:0; right:0;
9
+ }
10
+
11
+ #page-content {
12
+ min-height:100%;
13
+ padding: $padding-large-vertical 15px $padding-large-vertical;
14
+ }
15
+
16
+
17
+ #footer {
18
+ margin-bottom: -$footer-height;
19
+ height: $footer-height;
20
+ width: 100%;
21
+ color: $footer-fg;
22
+ background-color: $footer-bg;
23
+
24
+ #footer-contents {
25
+ padding-right: 15px;
26
+ padding-left: 15px;
27
+ vertical-align: middle;
28
+ line-height: $footer-height;
29
+ A {
30
+ color: $footer-link-color;
31
+ }
32
+ }
33
+ }
34
+