diff --git a/app/assets/javascripts/app/controllers/_application_controller_table.coffee b/app/assets/javascripts/app/controllers/_application_controller_table.coffee index affd66f6f..d01eb4e57 100644 --- a/app/assets/javascripts/app/controllers/_application_controller_table.coffee +++ b/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) => diff --git a/app/assets/javascripts/app/controllers/ticket_overview.coffee b/app/assets/javascripts/app/controllers/ticket_overview.coffee index c28498ca1..42e00cfc4 100644 --- a/app/assets/javascripts/app/controllers/ticket_overview.coffee +++ b/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) -> diff --git a/app/assets/javascripts/app/views/agent_ticket_view/content.jst.eco b/app/assets/javascripts/app/views/agent_ticket_view/content.jst.eco index 910f784d8..825fe1b16 100644 --- a/app/assets/javascripts/app/views/agent_ticket_view/content.jst.eco +++ b/app/assets/javascripts/app/views/agent_ticket_view/content.jst.eco @@ -1,27 +1,23 @@ -
-
- - -
+ -
-
\ No newline at end of file +
+ +
\ No newline at end of file diff --git a/app/assets/javascripts/app/views/agent_ticket_view/navbar_vertical.jst.eco b/app/assets/javascripts/app/views/agent_ticket_view/navbar_vertical.jst.eco new file mode 100644 index 000000000..86ddfe3d0 --- /dev/null +++ b/app/assets/javascripts/app/views/agent_ticket_view/navbar_vertical.jst.eco @@ -0,0 +1,35 @@ +
+ <% if @items: %> + <% for item in @items: %> + + <%- @T(item.name) %> + <%= item.count %> + + <% end %> + +
+ <%- @Icon('dropdown-list') %> + <%- @Icon('arrow-down', 'arrow') %> +
+ <% end %> +
+<% if @items: %> +
+ <% for item in @items: %> + + <%- @T(item.name) %> + <%= item.count %> + + <% end %> +
+ <%- @Icon('dropdown-list') %> + <%- @Icon('arrow-down', 'arrow') %> +
+
+<% end %> diff --git a/app/assets/javascripts/app/views/ticket_overview.jst.eco b/app/assets/javascripts/app/views/ticket_overview.jst.eco index 69df40de0..f4e27af10 100644 --- a/app/assets/javascripts/app/views/ticket_overview.jst.eco +++ b/app/assets/javascripts/app/views/ticket_overview.jst.eco @@ -1,2 +1,5 @@ -
\ No newline at end of file +
+
+
+
\ No newline at end of file diff --git a/app/assets/stylesheets/svg-dimensions.css b/app/assets/stylesheets/svg-dimensions.css index 0cdf10645..65954e67a 100644 --- a/app/assets/stylesheets/svg-dimensions.css +++ b/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; } diff --git a/app/assets/stylesheets/zammad.scss b/app/assets/stylesheets/zammad.scss index 1ee74dbdf..06f5b5245 100644 --- a/app/assets/stylesheets/zammad.scss +++ b/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; } diff --git a/contrib/icon-sprite.sketch b/contrib/icon-sprite.sketch index 3fa62ad0f..1812c3ace 100644 Binary files a/contrib/icon-sprite.sketch and b/contrib/icon-sprite.sketch differ diff --git a/public/assets/images/icons.svg b/public/assets/images/icons.svg index 4f5e9d1eb..3fff74520 100644 --- a/public/assets/images/icons.svg +++ b/public/assets/images/icons.svg @@ -1 +1 @@ -arrow-downarrow-leftarrow-rightarrow-upchatcheckbox-checkedcheckboxcheckmarkclipboardclockcloudcogcrowndashboarddiagonal-crossdownloademail-buttonemailfacebook-buttonfacebookgoogle-buttongrouphelpimportantin-processline-left-arrowline-right-arrowlinkedin-buttonlistloadinglock-openlocklogotypelong-arrow-rightmagnifiermarkermessageminus-smallminusmood-badmood-goodmood-okmood-super-badmood-supergoodnoteone-ticketorganizationoutbound-callsoverviewspackagepaperclippenpersonphoneplus-smallplusradio-checkedradioreceived-callsreloadreopeningreply-allreplyreportsignoutsplitstatus-modified-inner-circlestatus-modified-outer-circlestatusstopwatchswitchViewtask-stateteamtemplatestoolstotal-ticketstrashtwitter-buttontwitteruser \ No newline at end of file +arrow-downarrow-leftarrow-rightarrow-upchatcheckbox-checkedcheckboxcheckmarkclipboardclockcloudcogcrowndashboarddiagonal-crossdownloaddropdown-listemail-buttonemailfacebook-buttonfacebookgoogle-buttongrouphelpimportantin-processline-left-arrowline-right-arrowlinkedin-buttonlistloadinglock-openlocklogotypelong-arrow-rightmagnifiermarkermessageminus-smallminusmood-badmood-goodmood-okmood-super-badmood-supergoodnoteone-ticketorganizationoutbound-callsoverviewspackagepaperclippenpersonphoneplus-smallplusradio-checkedradioreceived-callsreloadreopeningreply-allreplyreportsignoutsplitstatus-modified-inner-circlestatus-modified-outer-circlestatusstopwatchswitchViewtask-stateteamtemplatestoolstotal-ticketstrashtwitter-buttontwitteruser \ No newline at end of file diff --git a/public/assets/images/icons/dropdown-list.svg b/public/assets/images/icons/dropdown-list.svg new file mode 100644 index 000000000..011c8cd2a --- /dev/null +++ b/public/assets/images/icons/dropdown-list.svg @@ -0,0 +1,12 @@ + + + + dropdown-list + Created with Sketch. + + + + + + + \ No newline at end of file