Commit 9ec2cf522eeec3b2fc6a098248e86eb2d7bcf423
1 parent
6e116602
Exists in
staging
and in
4 other branches
improve feature to add or move blocks
Showing
12 changed files
with
225 additions
and
92 deletions
Show diff stats
app/controllers/admin/environment_design_controller.rb
| 1 | class EnvironmentDesignController < BoxOrganizerController | 1 | class EnvironmentDesignController < BoxOrganizerController |
| 2 | - | 2 | + |
| 3 | protect 'edit_environment_design', :environment | 3 | protect 'edit_environment_design', :environment |
| 4 | 4 | ||
| 5 | def available_blocks | 5 | def available_blocks |
| 6 | # TODO EnvironmentStatisticsBlock is DEPRECATED and will be removed from | 6 | # TODO EnvironmentStatisticsBlock is DEPRECATED and will be removed from |
| 7 | # the Noosfero core soon, see ActionItem3045 | 7 | # the Noosfero core soon, see ActionItem3045 |
| 8 | - @available_blocks ||= [ ArticleBlock, LoginBlock, EnvironmentStatisticsBlock, RecentDocumentsBlock, EnterprisesBlock, CommunitiesBlock, SellersSearchBlock, LinkListBlock, FeedReaderBlock, SlideshowBlock, HighlightsBlock, FeaturedProductsBlock, CategoriesBlock, RawHTMLBlock, TagsBlock ] | ||
| 9 | - @available_blocks += plugins.dispatch(:extra_blocks, :type => Environment) | 8 | + @blocks ||= [ ArticleBlock, LoginBlock, EnvironmentStatisticsBlock, RecentDocumentsBlock, EnterprisesBlock, CommunitiesBlock, SellersSearchBlock, LinkListBlock, FeedReaderBlock, SlideshowBlock, HighlightsBlock, FeaturedProductsBlock, CategoriesBlock, RawHTMLBlock, TagsBlock ] |
| 9 | + @blocks += plugins.dispatch(:extra_blocks, :type => Environment) | ||
| 10 | + end | ||
| 11 | + | ||
| 12 | + def index | ||
| 13 | + available_blocks | ||
| 10 | end | 14 | end |
| 11 | 15 | ||
| 12 | end | 16 | end |
app/controllers/box_organizer_controller.rb
| @@ -5,10 +5,7 @@ class BoxOrganizerController < ApplicationController | @@ -5,10 +5,7 @@ class BoxOrganizerController < ApplicationController | ||
| 5 | def index | 5 | def index |
| 6 | end | 6 | end |
| 7 | 7 | ||
| 8 | - def move_block | ||
| 9 | - @block = boxes_holder.blocks.find(params[:id].gsub(/^block-/, '')) | ||
| 10 | - | ||
| 11 | - @source_box = @block.box | 8 | + def add_or_move_block |
| 12 | 9 | ||
| 13 | target_position = nil | 10 | target_position = nil |
| 14 | 11 | ||
| @@ -23,17 +20,26 @@ class BoxOrganizerController < ApplicationController | @@ -23,17 +20,26 @@ class BoxOrganizerController < ApplicationController | ||
| 23 | @target_box = boxes_holder.boxes.find($1) | 20 | @target_box = boxes_holder.boxes.find($1) |
| 24 | end | 21 | end |
| 25 | 22 | ||
| 26 | - if (@source_box != @target_box) | ||
| 27 | - @block.remove_from_list | 23 | + type = params[:id].gsub(/^block-/,'') |
| 24 | + | ||
| 25 | + if available_blocks.map(&:name).include?(type) | ||
| 26 | + @block = type.constantize.new | ||
| 28 | @block.box = @target_box | 27 | @block.box = @target_box |
| 28 | + @block.position = target_position | ||
| 29 | + else | ||
| 30 | + @block = boxes_holder.blocks.find(params[:id].gsub(/^block-/, '')) | ||
| 31 | + @source_box = @block.box | ||
| 32 | + | ||
| 33 | + if (@source_box != @target_box) | ||
| 34 | + @block.remove_from_list | ||
| 35 | + @block.box = @target_box | ||
| 36 | + end | ||
| 29 | end | 37 | end |
| 30 | 38 | ||
| 31 | if target_position.nil? | 39 | if target_position.nil? |
| 32 | - # insert in the end of the box | ||
| 33 | @block.insert_at(@target_box.blocks.size + 1) | 40 | @block.insert_at(@target_box.blocks.size + 1) |
| 34 | @block.move_to_bottom | 41 | @block.move_to_bottom |
| 35 | else | 42 | else |
| 36 | - # insert the block in the given position | ||
| 37 | @block.insert_at(@block.position && @block.position < target_position ? target_position - 1 : target_position) | 43 | @block.insert_at(@block.position && @block.position < target_position ? target_position - 1 : target_position) |
| 38 | end | 44 | end |
| 39 | 45 | ||
| @@ -41,9 +47,12 @@ class BoxOrganizerController < ApplicationController | @@ -41,9 +47,12 @@ class BoxOrganizerController < ApplicationController | ||
| 41 | 47 | ||
| 42 | @target_box.reload | 48 | @target_box.reload |
| 43 | 49 | ||
| 44 | - unless request.xhr? | ||
| 45 | - redirect_to :action => 'index' | 50 | + if available_blocks.map(&:name).include?(type) |
| 51 | + render :action => 'add_block' | ||
| 52 | + else | ||
| 53 | + render :action => 'move_block' | ||
| 46 | end | 54 | end |
| 55 | + | ||
| 47 | end | 56 | end |
| 48 | 57 | ||
| 49 | def move_block_down | 58 | def move_block_down |
| @@ -58,20 +67,17 @@ class BoxOrganizerController < ApplicationController | @@ -58,20 +67,17 @@ class BoxOrganizerController < ApplicationController | ||
| 58 | redirect_to :action => 'index' | 67 | redirect_to :action => 'index' |
| 59 | end | 68 | end |
| 60 | 69 | ||
| 61 | - def add_block | 70 | + def show_block_type_info |
| 62 | type = params[:type] | 71 | type = params[:type] |
| 63 | if ! type.blank? | 72 | if ! type.blank? |
| 64 | if available_blocks.map(&:name).include?(type) | 73 | if available_blocks.map(&:name).include?(type) |
| 65 | - boxes_holder.boxes.find(params[:box_id]).blocks << type.constantize.new | ||
| 66 | - redirect_to :action => 'index' | 74 | + @block = type.constantize |
| 67 | else | 75 | else |
| 68 | - raise ArgumentError.new("Type %s is not allowed. Go away." % type) | 76 | + raise ArgumentError.new("Type %s is not allowed. Go away." % type) |
| 69 | end | 77 | end |
| 78 | + render :action => 'show_block_type_info', :layout => false | ||
| 70 | else | 79 | else |
| 71 | - @center_block_types = (Box.acceptable_center_blocks & available_blocks) + plugins.dispatch(:extra_blocks, :type => boxes_holder.class, :position => 1) | ||
| 72 | - @side_block_types = (Box.acceptable_side_blocks & available_blocks) + plugins.dispatch(:extra_blocks, :type => boxes_holder.class, :position => [2,3]) | ||
| 73 | - @boxes = boxes_holder.boxes.with_position | ||
| 74 | - render :action => 'add_block', :layout => false | 80 | + redirect_to :action => 'index' |
| 75 | end | 81 | end |
| 76 | end | 82 | end |
| 77 | 83 |
app/controllers/my_profile/profile_design_controller.rb
| @@ -3,50 +3,54 @@ class ProfileDesignController < BoxOrganizerController | @@ -3,50 +3,54 @@ class ProfileDesignController < BoxOrganizerController | ||
| 3 | needs_profile | 3 | needs_profile |
| 4 | 4 | ||
| 5 | protect 'edit_profile_design', :profile | 5 | protect 'edit_profile_design', :profile |
| 6 | - | ||
| 7 | - def available_blocks | ||
| 8 | - blocks = [ ArticleBlock, TagsBlock, RecentDocumentsBlock, ProfileInfoBlock, LinkListBlock, MyNetworkBlock, FeedReaderBlock, ProfileImageBlock, LocationBlock, SlideshowBlock, ProfileSearchBlock, HighlightsBlock ] | ||
| 9 | 6 | ||
| 10 | - blocks += plugins.dispatch(:extra_blocks) | 7 | + def available_blocks |
| 8 | + @blocks = [ ArticleBlock, TagsBlock, RecentDocumentsBlock, ProfileInfoBlock, LinkListBlock, MyNetworkBlock, FeedReaderBlock, ProfileImageBlock, LocationBlock, SlideshowBlock, ProfileSearchBlock, HighlightsBlock ] | ||
| 9 | + @blocks += plugins.dispatch(:extra_blocks) | ||
| 11 | 10 | ||
| 12 | # blocks exclusive to people | 11 | # blocks exclusive to people |
| 13 | if profile.person? | 12 | if profile.person? |
| 14 | - blocks << FavoriteEnterprisesBlock | ||
| 15 | - blocks << CommunitiesBlock | ||
| 16 | - blocks << EnterprisesBlock | ||
| 17 | - blocks += plugins.dispatch(:extra_blocks, :type => Person) | 13 | + @blocks << FavoriteEnterprisesBlock |
| 14 | + @blocks << CommunitiesBlock | ||
| 15 | + @blocks << EnterprisesBlock | ||
| 16 | + @blocks += plugins.dispatch(:extra_blocks, :type => Person) | ||
| 18 | end | 17 | end |
| 19 | 18 | ||
| 20 | # blocks exclusive to communities | 19 | # blocks exclusive to communities |
| 21 | if profile.community? | 20 | if profile.community? |
| 22 | - blocks += plugins.dispatch(:extra_blocks, :type => Community) | 21 | + @blocks += plugins.dispatch(:extra_blocks, :type => Community) |
| 23 | end | 22 | end |
| 24 | 23 | ||
| 25 | # blocks exclusive for enterprises | 24 | # blocks exclusive for enterprises |
| 26 | if profile.enterprise? | 25 | if profile.enterprise? |
| 27 | - blocks << DisabledEnterpriseMessageBlock | ||
| 28 | - blocks << HighlightsBlock | ||
| 29 | - blocks << ProductCategoriesBlock | ||
| 30 | - blocks << FeaturedProductsBlock | ||
| 31 | - blocks << FansBlock | ||
| 32 | - blocks += plugins.dispatch(:extra_blocks, :type => Enterprise) | 26 | + @blocks << DisabledEnterpriseMessageBlock |
| 27 | + @blocks << HighlightsBlock | ||
| 28 | + @blocks << ProductCategoriesBlock | ||
| 29 | + @blocks << FeaturedProductsBlock | ||
| 30 | + @blocks << FansBlock | ||
| 31 | + @blocks += plugins.dispatch(:extra_blocks, :type => Enterprise) | ||
| 33 | end | 32 | end |
| 34 | 33 | ||
| 35 | # product block exclusive for enterprises in environments that permits it | 34 | # product block exclusive for enterprises in environments that permits it |
| 36 | if profile.enterprise? && profile.environment.enabled?('products_for_enterprises') | 35 | if profile.enterprise? && profile.environment.enabled?('products_for_enterprises') |
| 37 | - blocks << ProductsBlock | 36 | + @blocks << ProductsBlock |
| 38 | end | 37 | end |
| 39 | 38 | ||
| 40 | # block exclusive to profiles that have blog | 39 | # block exclusive to profiles that have blog |
| 41 | if profile.has_blog? | 40 | if profile.has_blog? |
| 42 | - blocks << BlogArchivesBlock | 41 | + @blocks << BlogArchivesBlock |
| 43 | end | 42 | end |
| 44 | 43 | ||
| 45 | if user.is_admin?(profile.environment) | 44 | if user.is_admin?(profile.environment) |
| 46 | - blocks << RawHTMLBlock | 45 | + @blocks << RawHTMLBlock |
| 47 | end | 46 | end |
| 48 | 47 | ||
| 49 | - blocks | 48 | + @blocks |
| 49 | + | ||
| 50 | + end | ||
| 51 | + | ||
| 52 | + def index | ||
| 53 | + available_blocks | ||
| 50 | end | 54 | end |
| 51 | 55 | ||
| 52 | end | 56 | end |
app/helpers/boxes_helper.rb
| @@ -171,7 +171,8 @@ module BoxesHelper | @@ -171,7 +171,8 @@ module BoxesHelper | ||
| 171 | "before-block-#{block.id}" | 171 | "before-block-#{block.id}" |
| 172 | end | 172 | end |
| 173 | 173 | ||
| 174 | - content_tag('div', ' ', :id => id, :class => 'block-target' ) + drop_receiving_element(id, :url => { :action => 'move_block', :target => id }, :accept => box.acceptable_blocks, :hoverclass => 'block-target-hover') | 174 | + content_tag('div', ' ', :id => id, :class => 'block-target', :style => "border: 1px solid red;" ) + |
| 175 | + drop_receiving_element(id, :url => { :action => 'add_or_move_block', :target => id }, :accept => box.acceptable_blocks, :hoverclass => 'block-target-hover') | ||
| 175 | end | 176 | end |
| 176 | 177 | ||
| 177 | # makes the given block draggable so it can be moved away. | 178 | # makes the given block draggable so it can be moved away. |
app/models/block.rb
| @@ -110,11 +110,35 @@ class Block < ActiveRecord::Base | @@ -110,11 +110,35 @@ class Block < ActiveRecord::Base | ||
| 110 | # blocks to choose one to include in the design. | 110 | # blocks to choose one to include in the design. |
| 111 | # | 111 | # |
| 112 | # Must be redefined in subclasses to match the description of each block | 112 | # Must be redefined in subclasses to match the description of each block |
| 113 | - # type. | 113 | + # type. |
| 114 | def self.description | 114 | def self.description |
| 115 | '(dummy)' | 115 | '(dummy)' |
| 116 | end | 116 | end |
| 117 | 117 | ||
| 118 | + def self.short_description | ||
| 119 | + '(dummy)' | ||
| 120 | + end | ||
| 121 | + | ||
| 122 | + def self.release_notes | ||
| 123 | + '(dummy)' | ||
| 124 | + end | ||
| 125 | + | ||
| 126 | + def self.default_preview | ||
| 127 | + "/images/block_preview.png" | ||
| 128 | + end | ||
| 129 | + | ||
| 130 | + def self.previews | ||
| 131 | + [] | ||
| 132 | + end | ||
| 133 | + | ||
| 134 | + def self.icon | ||
| 135 | + "/images/icon_block.png" | ||
| 136 | + end | ||
| 137 | + | ||
| 138 | + def self.position | ||
| 139 | + [1,2,3] | ||
| 140 | + end | ||
| 141 | + | ||
| 118 | # Returns the content to be used for this block. | 142 | # Returns the content to be used for this block. |
| 119 | # | 143 | # |
| 120 | # This method can return several types of objects: | 144 | # This method can return several types of objects: |
app/views/box_organizer/add_block.html.erb
| @@ -1,49 +0,0 @@ | @@ -1,49 +0,0 @@ | ||
| 1 | -<div id="add-block-dialog"> | ||
| 2 | - <%= form_tag do %> | ||
| 3 | - | ||
| 4 | - <p><%= _('In what area do you want to put your new block?') %></p> | ||
| 5 | - | ||
| 6 | - <div id="box-position"> | ||
| 7 | - <% @boxes.each do |box| %> | ||
| 8 | - <% name = box.central? ? _('Main area') : _('Area %d') % box.position %> | ||
| 9 | - <%= labelled_radio_button(name, :box_id, box.id, box.central?, { 'data-position' => box.position }) %> | ||
| 10 | - <% end %> | ||
| 11 | - </div> | ||
| 12 | - | ||
| 13 | - <script type="text/javascript"> | ||
| 14 | - jQuery('#box-position input').bind('change', | ||
| 15 | - function () { | ||
| 16 | - showCenter = jQuery(this).attr('data-position') == '1'; | ||
| 17 | - jQuery('#center-block-types').toggle(showCenter); | ||
| 18 | - jQuery('#side-block-types').toggle(!showCenter); | ||
| 19 | - } | ||
| 20 | - ); | ||
| 21 | - </script> | ||
| 22 | - | ||
| 23 | - <p><%= _('Select the type of block you want to add to your page.') %></p> | ||
| 24 | - | ||
| 25 | - <div id="center-block-types" class="block-types"> | ||
| 26 | - <% @center_block_types.each do |block| %> | ||
| 27 | - <div class='block-type'> | ||
| 28 | - <%= labelled_radio_button(block.description, :type, block.name) %> | ||
| 29 | - </div> | ||
| 30 | - <% end %> | ||
| 31 | - </div> | ||
| 32 | - | ||
| 33 | - <div id="side-block-types" class="block-types" style="display:none"> | ||
| 34 | - <% @side_block_types.each do |block| %> | ||
| 35 | - <div class='block-type'> | ||
| 36 | - <%= labelled_radio_button(block.description, :type, block.name) %> | ||
| 37 | - </div> | ||
| 38 | - <% end %> | ||
| 39 | - </div> | ||
| 40 | - | ||
| 41 | - <br style='clear: both'/> | ||
| 42 | - | ||
| 43 | - <% button_bar do %> | ||
| 44 | - <%= submit_button(:add, _("Add")) %> | ||
| 45 | - <%= colorbox_close_button(_('Close')) %> | ||
| 46 | - <% end %> | ||
| 47 | - | ||
| 48 | - <% end %> | ||
| 49 | -</div> |
app/views/box_organizer/index.html.erb
| 1 | +<%= stylesheet_link_tag '/designs/themes/default/block_store.css' %> | ||
| 2 | + | ||
| 1 | <h1><%= _('Editing sideboxes')%></h1> | 3 | <h1><%= _('Editing sideboxes')%></h1> |
| 2 | 4 | ||
| 3 | <% button_bar :class=>'design-menu' do %> | 5 | <% button_bar :class=>'design-menu' do %> |
| 4 | - <%= colorbox_button('add', _('Add a block'), { :action => 'add_block' }) %> | ||
| 5 | <%= button(:back, _('Back to control panel'), :controller => (profile.nil? ? 'admin_panel': 'profile_editor')) %> | 6 | <%= button(:back, _('Back to control panel'), :controller => (profile.nil? ? 'admin_panel': 'profile_editor')) %> |
| 6 | <% end %> | 7 | <% end %> |
| 8 | + | ||
| 9 | +<div id="block-types"> | ||
| 10 | + <% @blocks.each do |block| %> | ||
| 11 | + | ||
| 12 | + <div id="block-<%=block.name%>" class="block-type <%= block.name.to_css_class %>"> | ||
| 13 | + <div class="button-bar"> | ||
| 14 | + <%= link_to content_tag('span', _('Help on this block')), | ||
| 15 | + {:controller => 'environment_design', :action => 'show_block_type_info', :type => block.name}, | ||
| 16 | + :class => "button icon-button icon-help colorbox", | ||
| 17 | + :title => _('Help on this block') %> | ||
| 18 | + <br style="clear: left"> | ||
| 19 | + </div> | ||
| 20 | + <div> | ||
| 21 | + <%= image_tag(block.icon, height: '48', width: '48', class: 'block-type-icon', alt: '' ) %> | ||
| 22 | + </div> | ||
| 23 | + <span><%= _(block.description) %></span> | ||
| 24 | + </div> | ||
| 25 | + | ||
| 26 | + <%= draggable_element("block-#{block.name}", :revert => true) %> | ||
| 27 | + <% end %> | ||
| 28 | +</div> |
| @@ -0,0 +1,30 @@ | @@ -0,0 +1,30 @@ | ||
| 1 | +<div id="bs-block-container"> | ||
| 2 | + | ||
| 3 | + <div id="bs-block-header"> | ||
| 4 | + <%= image_tag(@block.icon, height: '48', width: '48', id: 'bs-block-icon', alt: '' ) %> | ||
| 5 | + <h1><%= @block.name %></h1> | ||
| 6 | + <p><%= @block.short_description %></p> | ||
| 7 | + </div> | ||
| 8 | + | ||
| 9 | + <div id="bs-block-images"> | ||
| 10 | + <div style="white-space: nowrap;"> | ||
| 11 | + <% if @block.previews.empty? %> | ||
| 12 | + <% for i in 0..2 %> | ||
| 13 | + <%= image_tag(@block.default_preview, height: '240', width: '384', alt: '') %> | ||
| 14 | + <% end %> | ||
| 15 | + <% else %> | ||
| 16 | + <% @block.previews.each do |preview| %> | ||
| 17 | + <%= image_tag(preview, height: '240', width: '384', alt: '') %> | ||
| 18 | + <% end %> | ||
| 19 | + <% end %> | ||
| 20 | + </div> | ||
| 21 | + </div> | ||
| 22 | + | ||
| 23 | + <div id="bs-block-info"> | ||
| 24 | + <h2><%= _('Description') %></h2> | ||
| 25 | + <p><%= @block.description %></p> | ||
| 26 | + <h2><%= _('What\'s New') %></h2> | ||
| 27 | + <p><%= @block.release_notes %></p> | ||
| 28 | + </div> | ||
| 29 | + | ||
| 30 | +</div> |
| @@ -0,0 +1,86 @@ | @@ -0,0 +1,86 @@ | ||
| 1 | +#block-types { | ||
| 2 | + white-space: nowrap; | ||
| 3 | + margin: 20px 0; | ||
| 4 | +} | ||
| 5 | + | ||
| 6 | +#block-types .block-type { | ||
| 7 | + cursor: move; | ||
| 8 | + display: inline-block; | ||
| 9 | + width: 112px; | ||
| 10 | + text-align: center; | ||
| 11 | + vertical-align: top; | ||
| 12 | + min-height: 0; | ||
| 13 | +} | ||
| 14 | + | ||
| 15 | +#block-types .button-bar { | ||
| 16 | + margin: 0; | ||
| 17 | +} | ||
| 18 | + | ||
| 19 | +#bs-block-container { | ||
| 20 | + /*border: 1px solid red;*/ | ||
| 21 | + width: 770px; | ||
| 22 | + padding: 15px; | ||
| 23 | +} | ||
| 24 | + | ||
| 25 | +#bs-block-container #bs-block-icon { | ||
| 26 | + float: left; | ||
| 27 | + padding-right: 10px; | ||
| 28 | +} | ||
| 29 | + | ||
| 30 | +#bs-block-container #bs-block-menu { | ||
| 31 | + border: 1px solid red; | ||
| 32 | + display: inline-block; | ||
| 33 | + float: right; | ||
| 34 | + background: #efefef; | ||
| 35 | + background: linear-gradient(top, #efefef 0%, #bbbbbb 100%); | ||
| 36 | + background: -moz-linear-gradient(top, #efefef 0%, #bbbbbb 100%); | ||
| 37 | + background: -webkit-linear-gradient(top, #efefef 0%,#bbbbbb 100%); | ||
| 38 | + box-shadow: 0px 0px 9px rgba(0,0,0,0.15); | ||
| 39 | + padding: 0 20px; | ||
| 40 | + /*border-radius: 10px;*/ | ||
| 41 | + list-style: none; | ||
| 42 | + position: relative; | ||
| 43 | + display: inline-table; | ||
| 44 | +} | ||
| 45 | + | ||
| 46 | +#bs-block-container #bs-block-menu:hover { | ||
| 47 | + background: #4b545f; | ||
| 48 | + background: linear-gradient(top, #4f5964 0%, #5f6975 40%); | ||
| 49 | + background: -moz-linear-gradient(top, #4f5964 0%, #5f6975 40%); | ||
| 50 | + background: -webkit-linear-gradient(top, #4f5964 0%,#5f6975 40%); | ||
| 51 | +} | ||
| 52 | + | ||
| 53 | +#bs-block-container #bs-block-header { | ||
| 54 | + /*border: 1px solid red;*/ | ||
| 55 | + display: inline-block; | ||
| 56 | + float: left; | ||
| 57 | +} | ||
| 58 | + | ||
| 59 | +#bs-block-container #bs-block-header h1 { | ||
| 60 | + /*border: 1px solid red;*/ | ||
| 61 | + display: inline-block; | ||
| 62 | + margin: 0; | ||
| 63 | +} | ||
| 64 | + | ||
| 65 | +#bs-block-container h2 { | ||
| 66 | + /*border: 1px solid red;*/ | ||
| 67 | + margin: 0; | ||
| 68 | + margin-top: 10px; | ||
| 69 | +} | ||
| 70 | + | ||
| 71 | +#bs-block-container p { | ||
| 72 | + /*border: 1px solid red;*/ | ||
| 73 | + margin: 0; | ||
| 74 | +} | ||
| 75 | + | ||
| 76 | +#bs-block-images { | ||
| 77 | + /*border: 1px solid red;*/ | ||
| 78 | + clear: both; | ||
| 79 | + overflow-x: auto; | ||
| 80 | + padding-top: 15px; | ||
| 81 | +} | ||
| 82 | + | ||
| 83 | +#bs-block-info { | ||
| 84 | + /*border: 1px solid red;*/ | ||
| 85 | + margin-top: 20px; | ||
| 86 | +} |
3.15 KB
903 Bytes