Browse Source

overviews: add vertical navbar

@navBarControllerVertical in ticket_overviews.coffe:12 somehow doesn't get rendered yet. if you change the order (@navBarControll after ..Vertical) it will get rendered but the sidebar navBar won't get rendered
Felix Niklas 9 years ago
parent
commit
fbe42ca6b5

+ 7 - 3
app/assets/javascripts/app/controllers/_application_controller_table.coffee

@@ -24,13 +24,14 @@ class App.ControllerTable extends App.Controller
         @headerWidth[key] = value
 
     @render()
-    $(window).on 'resize.table', @onResize
+    $(window).on 'resize.table', @readjustHeaderWidths
 
   release: =>
-    $(window).off 'resize.table', @onResize
+    $(window).off 'resize.table', @readjustHeaderWidths
 
   render: =>
     @html @tableGen()
+    @readjustHeaderWidths()
 
   ###
 
@@ -347,6 +348,9 @@ class App.ControllerTable extends App.Controller
     table
 
   adjustHeaderWidths: (headers) ->
+    if !@headers
+      return
+
     availableWidth = @el.width()
 
     if availableWidth is 0
@@ -410,7 +414,7 @@ class App.ControllerTable extends App.Controller
 
     return widths
 
-  onResize: =>
+  readjustHeaderWidths: =>
     @headers = @adjustHeaderWidths @headers
 
     @tableHead.each (i, el) =>

+ 76 - 15
app/assets/javascripts/app/controllers/ticket_overview.coffee

@@ -1,4 +1,6 @@
 class App.TicketOverview extends App.Controller
+  className: 'overviews'
+  
   constructor: ->
     super
 
@@ -7,15 +9,18 @@ class App.TicketOverview extends App.Controller
   render: ->
     @html App.view('ticket_overview')()
 
-    @navBarController = new Navbar(
+    @navBarControllerVertical = new Navbar
+      el:   @el.find('.overview-header')
+      view: @view
+      vertical: true
+
+    @navBarController = new Navbar
       el:   @el.find('.sidebar')
       view: @view
-    )
 
-    @contentController = new Table(
-      el:   @el.find('.main')
+    @contentController = new Table
+      el:   @el.find('.overview-table')
       view: @view
-    )
 
   active: (state) =>
     @activeState = state
@@ -39,10 +44,14 @@ class App.TicketOverview extends App.Controller
 
     # build nav bar
     if @navBarController
-      @navBarController.update(
+      @navBarController.update
+        view:        @view
+        activeState: true
+
+    if @navBarControllerVertical
+      @navBarControllerVertical.update
         view:        @view
         activeState: true
-      )
 
     # do not rerender overview if current overview is requested again
     return if @viewLast is @view
@@ -59,6 +68,8 @@ class App.TicketOverview extends App.Controller
   hide: =>
     if @navBarController
       @navBarController.active(false)
+    if @navBarControllerVertical
+      @navBarControllerVertical.active(false)
 
   changed: ->
     false
@@ -658,6 +669,21 @@ class App.OverviewSettings extends App.ControllerModal
     )
 
 class Navbar extends App.Controller
+  elements:
+    '.js-tabsClone': 'clone'
+    '.js-tabClone': 'tabClone'
+    '.js-tabs': 'tabs'
+    '.js-tab': 'tab'
+    '.js-dropdown': 'dropdown'
+    '.js-toggle': 'dropdownToggle'
+    '.js-dropdownItem': 'dropdownItem'
+
+  events:
+    'click .js-tab': 'activate'
+    'click .js-dropdownItem': 'navigate'
+    'hide.bs.dropdown': 'onDropdownHide'
+    'show.bs.dropdown': 'onDropdownShow'
+
   constructor: ->
     super
 
@@ -676,6 +702,9 @@ class Navbar extends App.Controller
     @bind 'ui:rerender', =>
       @render()
 
+    if @options.vertical
+      $(window).on 'resize.navbar', @autoFoldTabs
+
     # init fetch via ajax
     ajaxInit = =>
 
@@ -685,6 +714,37 @@ class Navbar extends App.Controller
 
     @delay( ajaxInit, 5000 )
 
+  navigate: (event) =>
+    location.hash = $(event.currentTarget).attr('data-target')
+
+  onDropdownShow: =>
+    @dropdownToggle.addClass('active')
+
+  onDropdownHide: =>
+    @dropdownToggle.removeClass('active')
+
+  activate: (event) =>
+    @tab.removeClass('active')
+    $(event.currentTarget).addClass('active')
+
+  release: =>
+    $(window).off 'resize.navbar', @autoFoldTabs
+
+  autoFoldTabs: =>
+    @html App.view("agent_ticket_view/navbar#{ if @options.vertical then '_vertical' }")
+      items: @data
+
+    while @clone.width() > @el.width()
+      @tabClone.not('.hide').last().addClass('hide')
+      @tab.not('.hide').last().addClass('hide')
+      @dropdownItem.filter('.hide').last().removeClass('hide')
+
+    # if all tabs are visible
+    # remove dropdown and dropdown button
+    if @dropdownItem.filter('.hide').size() is 0
+      @dropdown.remove()
+      @dropdownToggle.remove()
+
   fetch: =>
     #console.log('AJAX CALLL')
     # init fetch via ajax, all other updates on time via websockets
@@ -716,19 +776,18 @@ class Navbar extends App.Controller
       @title meta.title, true
 
   render: =>
-    #console.log('RENDER NAV')
     return if !@cache
-    data = _.clone(@cache)
+    @data = _.clone(@cache)
 
     # redirect to first view
-    if @activeState && !@view && !_.isEmpty(data)
-      view = data[0].link
+    if @activeState && !@view && !_.isEmpty(@data)
+      view = @data[0].link
       #console.log('REDIRECT', "ticket/view/#{view}")
       @navigate "ticket/view/#{view}", true
       return
 
     # add new views
-    for item in data
+    for item in @data
       item.target = '#ticket/view/' + item.link
       if item.link is @view
         item.active = true
@@ -736,9 +795,11 @@ class Navbar extends App.Controller
       else
         item.active = false
 
-    @html App.view('agent_ticket_view/navbar')(
-      items: data
-    )
+    @html App.view("agent_ticket_view/navbar#{ if @options.vertical then '_vertical' else '' }")
+      items: @data
+
+    if @options.vertical
+      @autoFoldTabs()
 
 class TicketOverviewRouter extends App.ControllerPermanent
   constructor: (params) ->

+ 21 - 25
app/assets/javascripts/app/views/agent_ticket_view/content.jst.eco

@@ -1,27 +1,23 @@
-<div class="fit vertical">
-  <div class="tableOverview flex scrollable">
-    <div class="page-header">
-      <div class="page-header-title">
-        <h1><%- @T( @overview.name ) %></h1>
-      </div>
-      <div class="page-header-meta">
-        <% if @edit: %>
-          <div class="btn btn--action" data-type="settings"><%- @T('Options') %></div>
-        <% end %>
-        <!--
-        <ul class="pagination">
-        <% for item in @view_modes: %>
-          <li class="<%= item.class %>">
-            <a class="centered" href="#" data-type="viewmode" data-mode="<%= item.type %>"><%= item.name %></a>
-          </li>
-        <% end %>
-        </ul>
-        -->
-      </div>
-    </div>
-
-    <div class="table-overview"></div>
+<div class="page-header">
+  <div class="page-header-title">
+    <h1><%- @T( @overview.name ) %></h1>
+  </div>
+  <div class="page-header-meta">
+    <% if @edit: %>
+      <div class="btn btn--action" data-type="settings"><%- @T('Options') %></div>
+    <% end %>
+    <!--
+    <ul class="pagination">
+    <% for item in @view_modes: %>
+      <li class="<%= item.class %>">
+        <a class="centered" href="#" data-type="viewmode" data-mode="<%= item.type %>"><%= item.name %></a>
+      </li>
+    <% end %>
+    </ul>
+    -->
   </div>
+</div>
+
+<div class="table-overview"></div>
 
-  <div class="bulkAction hide"></div>
-</div>
+<div class="bulkAction hide"></div>

+ 35 - 0
app/assets/javascripts/app/views/agent_ticket_view/navbar_vertical.jst.eco

@@ -0,0 +1,35 @@
+<div class="tabs wide-tabs js-tabs">
+  <% if @items: %>
+    <% for item in @items: %>
+      <a class="tab js-tab<%= ' active' if item.active %>" href="<%= item.target %>">
+        <span class="tab-name"><%- @T(item.name) %></span>
+        <span class="tab-badge"><%= item.count %></span>
+      </a>
+    <% end %>
+    <ul class="dropdown dropdown--actions dropdown--wide dropdown-menu dropdown-menu-right js-dropdown" role="menu" aria-labelledby="userAction">
+      <% for item in @items: %>
+        <li class="js-dropdownItem hide<%= ' active' if item.active %>" role="presentation" data-target="<%= item.target %>" role="menuitem" tabindex="-1">
+          <span class="flex u-textTruncate"><%- @T( item.name ) %></span>
+          <span class="badge badge--text"><%= item.count %></span>
+      <% end %>
+    </ul>
+    <div class="tab tab-dropdown js-toggle" data-toggle="dropdown">
+      <%- @Icon('dropdown-list') %>
+      <%- @Icon('arrow-down', 'arrow') %>
+    </div>
+  <% end %>
+</div>
+<% if @items: %>
+<div class="tabs wide-tabs u-invisible js-tabsClone">
+  <% for item in @items: %>
+    <a class="tab js-tabClone<%= ' active' if item.active %>" href="<%= item.target %>">
+      <span class="tab-name"><%- @T(item.name) %></span>
+      <span class="tab-badge"><%= item.count %></span>
+    </a>
+  <% end %>
+  <div class="tab tab-dropdown js-toggle">
+    <%- @Icon('dropdown-list') %>
+    <%- @Icon('arrow-down', 'arrow') %>
+  </div>
+</div>
+<% end %>

+ 4 - 1
app/assets/javascripts/app/views/ticket_overview.jst.eco

@@ -1,2 +1,5 @@
 <div class="sidebar"></div>
-<div class="main flex"></div>
+<div class="main flex">
+  <div class="overview-header"></div>
+  <div class="overview-table"></div>
+</div>

+ 1 - 0
app/assets/stylesheets/svg-dimensions.css

@@ -14,6 +14,7 @@
 .icon-dashboard { width: 24px; height: 24px; }
 .icon-diagonal-cross { width: 13px; height: 13px; }
 .icon-download { width: 14px; height: 13px; }
+.icon-dropdown-list { width: 19px; height: 14px; }
 .icon-email-button { width: 29px; height: 22px; }
 .icon-email { width: 17px; height: 17px; }
 .icon-facebook-button { width: 29px; height: 22px; }

+ 125 - 29
app/assets/stylesheets/zammad.scss

@@ -15,6 +15,8 @@ $navigationWidth: 260px;
 
 $highlight-color: hsl(205,90%,60%);
 
+$largeScreenBreakpoint: 1280px;
+
 html {
   height: 100%;
 }
@@ -66,6 +68,12 @@ strong {
   flex-shrink: 0;
 }
 
+.u-invisible {
+  opacity: 0;
+  pointer-events: none;
+  position: absolute;
+}
+
 a {
   outline: none !important;
   @extend .u-highlight;
@@ -669,13 +677,15 @@ blockquote {
   &.badge--text {
     min-width: 0;
     padding: 0;
-    margin-right: 5px;
+    margin-right: 0;
     font-size: inherit;
-    font-weight: normal;
-    text-align: left;
+    font-weight: inherit;
+    text-align: inherit;
+    line-height: inherit;
     color: #d0d2d3;
     background: none;
     border-radius: 0;
+    vertical-align: baseline;
   }
 }
 
@@ -1994,18 +2004,49 @@ ol.tabs li {
   }
 
   .tab {
+    color: inherit;
     height: 35px;
     padding: 8px 20px;
     text-align: center;
     border-right: 1px solid rgba(0,8,14,.08);
     flex: 1 1 auto;
     @extend .u-clickable;
+    white-space: nowrap;
+    
+    &.active {
+      color: white;
+      background: #444a4f;
+      box-shadow: none;
+      
+      .tab-badge {
+        color: hsl(204,3%,65%);
+      }
+    }
   }
 
-  .tab.active {
-    color: white;
-    background: #444a4f;
-    box-shadow: none;
+  .tab-dropdown {
+    position: relative;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+      
+    .arrow {
+      margin-left: 10px;
+      opacity: 0.75;
+    }
+    
+    .icon {
+      fill: hsl(0,0%,70%);
+    }
+    
+    &.active {
+      background: white;
+      
+      .icon {
+        fill: #444a4f;
+        opacity: 1;
+      }
+    }
   }
 
   .tab:first-child {
@@ -2017,15 +2058,26 @@ ol.tabs li {
     border-right: none;
   }
 
+  .tab-badge {
+    margin-left: 3px;
+    font-size: 0.95em;
+  }
+
   .wide-tabs {
-    margin: 25px auto 20px;
-    font-size: 15px;
-    font-weight: 300;
+    margin: 25px 0 20px;
+    font-size: 14px;
     border-radius: 8px;
+    display: inline-flex;
     
     .tab {
-      height: 40px;
-      padding: 10px 20px;
+      height: auto;
+      padding: 10px 24px;
+      flex-grow: 0;
+    }
+
+    .tab-dropdown {
+      padding-left: 18px;
+      padding-right: 15px;
     }
   }
 
@@ -2286,8 +2338,33 @@ footer {
   border-color: #eee;
 }
 
-.tableOverview {
-  padding: 10px 20px;
+.overviews {
+  .sidebar {
+    @media only screen and (max-width: $largeScreenBreakpoint) {
+      display: none;
+    }
+  }
+}
+
+.overview-header {
+  position: relative;
+  height: 92px;
+  display: none;
+  
+  .tabs {
+    margin-top: 20px;
+    margin-bottom: 32px;
+    position: relative;
+  }
+
+  .dropdown {
+    min-width: 0;
+    width: 336px;
+  }
+
+  @media only screen and (max-width: $largeScreenBreakpoint) {
+    display: block;
+  }
 }
 
 .tableOverview-edit {
@@ -2295,12 +2372,20 @@ footer {
 }
 
 .bulkAction {
+  position: fixed;
+  bottom: 0;
+  left: $sidebarWidth + $navigationWidth;
+  right: 0;
   background: white;
   z-index: 1;
   box-shadow: 
     0 -1px rgba(0,0,0,.05),
     0 -2px rgba(0,0,0,.03),
     0 -3px rgba(0,0,0,.01);
+    
+  @media only screen and (max-width: $largeScreenBreakpoint) {
+    left: $navigationWidth;
+  }
 }
 
   .bulkAction-firstStep {
@@ -3044,8 +3129,7 @@ footer {
 }
 
 .sidebar {
-  width: 32%;
-  max-width: 280px;
+  width: 280px;
   padding: 20px;
   color: hsl(60,1%,34%);
   background: white;
@@ -3066,21 +3150,21 @@ footer {
   }
 }
 
-  .sidebar-block {
-    margin: 20px 0;
+.sidebar-block {
+  margin: 20px 0;
 
-    &:first-child {
-      margin-top: 0;
-    }
-  }
-  .sidebar-block [contenteditable=true] {
-    white-space: normal; // do no u-textTruncate, we want to edit it inline
+  &:first-child {
+    margin-top: 0;
   }
+}
+.sidebar-block [contenteditable=true] {
+  white-space: normal; // do no u-textTruncate, we want to edit it inline
+}
 
-  .main + .sidebar {
-    border-right: none;
-    border-left: 1px solid #e6e6e6;
-  }
+.main + .sidebar {
+  border-right: none;
+  border-left: 1px solid #e6e6e6;
+}
 
 .NavBarAdmin.sidebar,
 .NavBarProfile.sidebar, {
@@ -3147,6 +3231,7 @@ footer {
   .nav-pills > li > a > .badge {
     margin-left: auto;
     padding-left: 10px;
+    margin-right: 5px;
   }
 
   a.list-group-item.active > .badge,
@@ -5185,6 +5270,10 @@ footer {
     padding: 0 15px;
     cursor: pointer;
     white-space: nowrap;
+    
+    &:focus {
+      outline: none;
+    }
   }
 
   .dropdown li:not(:first-child) {
@@ -5260,6 +5349,13 @@ footer {
     }
   }
 
+  .dropdown.dropdown--wide {
+    li {
+      padding-top: 12px;
+      padding-bottom: 12px;
+    }
+  }
+
   li.dropdown-header {
     line-height: 36px;
     height: 32px;
@@ -7157,7 +7253,7 @@ output {
 
 */
 
-@media only screen and (max-width: 1280px) {
+@media only screen and (max-width: $largeScreenBreakpoint) {
   .sidebar.optional {
     display: none;
   }

BIN
contrib/icon-sprite.sketch


File diff suppressed because it is too large
+ 0 - 0
public/assets/images/icons.svg


+ 12 - 0
public/assets/images/icons/dropdown-list.svg

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg width="19px" height="14px" viewBox="0 0 19 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
+    <!-- Generator: Sketch 3.4 (15575) - http://www.bohemiancoding.com/sketch -->
+    <title>dropdown-list</title>
+    <desc>Created with Sketch.</desc>
+    <defs></defs>
+    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
+        <g id="dropdown-list" sketch:type="MSArtboardGroup" fill="#50E3C2">
+            <path d="M0,0 L19,0 L19,2 L0,2 L0,0 Z M0,4 L19,4 L19,6 L0,6 L0,4 Z M0,8 L19,8 L19,10 L0,10 L0,8 Z M0,12 L19,12 L19,14 L0,14 L0,12 Z" id="list" sketch:type="MSShapeGroup"></path>
+        </g>
+    </g>
+</svg>

Some files were not shown because too many files changed in this diff