diff options
author | Alfredo Sumaran <alfredo@gitlab.com> | 2016-04-07 15:44:36 -0500 |
---|---|---|
committer | Alfredo Sumaran <alfredo@gitlab.com> | 2016-04-07 15:44:36 -0500 |
commit | 6ae6f29a2ebc4540b5b3b790b19976ab3763ed53 (patch) | |
tree | e191b2f3e11ee8f0bdbfcfcb5b4634795d66da52 /app/assets | |
parent | 8c0aba9458a25266bb52bbc2101a83ed05967722 (diff) | |
parent | 1060467bb8f1ce6886b05436d16f95996da2fa91 (diff) | |
download | gitlab-ce-6ae6f29a2ebc4540b5b3b790b19976ab3763ed53.tar.gz |
Merge branch 'master' into issue_14678
Diffstat (limited to 'app/assets')
49 files changed, 1261 insertions, 530 deletions
diff --git a/app/assets/javascripts/awards_handler.coffee b/app/assets/javascripts/awards_handler.coffee index 47b080406d4..6a670d5e887 100644 --- a/app/assets/javascripts/awards_handler.coffee +++ b/app/assets/javascripts/awards_handler.coffee @@ -1,5 +1,5 @@ class @AwardsHandler - constructor: (@post_emoji_url, @noteable_type, @noteable_id, @aliases) -> + constructor: (@get_emojis_url, @post_emoji_url, @noteable_type, @noteable_id, @aliases) -> $(".js-add-award").on "click", (event) => event.stopPropagation() event.preventDefault() @@ -34,7 +34,7 @@ class @AwardsHandler $("#emoji_search").focus() else $('.js-add-award').addClass "is-loading" - $.get "/emojis", (response) => + $.get @get_emojis_url, (response) => $('.js-add-award').removeClass "is-loading" $(".js-award-holder").append response setTimeout => diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee index f5e1ca9860d..70fd6f50e9c 100644 --- a/app/assets/javascripts/dispatcher.js.coffee +++ b/app/assets/javascripts/dispatcher.js.coffee @@ -146,15 +146,11 @@ class Dispatcher when 'project_members', 'deploy_keys', 'hooks', 'services', 'protected_branches' shortcut_handler = new ShortcutsNavigation() - # If we haven't installed a custom shortcut handler, install the default one if not shortcut_handler new Shortcuts() initSearch: -> - opts = $('.search-autocomplete-opts') - path = opts.data('autocomplete-path') - project_id = opts.data('autocomplete-project-id') - project_ref = opts.data('autocomplete-project-ref') - new SearchAutocomplete(path, project_id, project_ref) + # Only when search form is present + new SearchAutocomplete() if $('.search').length diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee index dbcad9c0514..e8d25591f63 100644 --- a/app/assets/javascripts/gl_dropdown.js.coffee +++ b/app/assets/javascripts/gl_dropdown.js.coffee @@ -1,8 +1,13 @@ class GitLabDropdownFilter BLUR_KEYCODES = [27, 40] + ARROW_KEY_CODES = [38, 40] HAS_VALUE_CLASS = "has-value" constructor: (@input, @options) -> + { + @filterInputBlur = true + } = @options + $inputContainer = @input.parent() $clearButton = $inputContainer.find('.js-dropdown-input-clear') @@ -18,22 +23,26 @@ class GitLabDropdownFilter # Key events timeout = "" @input.on "keyup", (e) => + keyCode = e.which + + return if ARROW_KEY_CODES.indexOf(keyCode) >= 0 + if @input.val() isnt "" and !$inputContainer.hasClass HAS_VALUE_CLASS $inputContainer.addClass HAS_VALUE_CLASS else if @input.val() is "" and $inputContainer.hasClass HAS_VALUE_CLASS $inputContainer.removeClass HAS_VALUE_CLASS - if e.keyCode is 13 and @input.val() isnt "" + if keyCode is 13 and @input.val() isnt "" if @options.enterCallback @options.enterCallback() return clearTimeout timeout timeout = setTimeout => - blur_field = @shouldBlur e.keyCode + blur_field = @shouldBlur keyCode search_text = @input.val() - if blur_field + if blur_field and @filterInputBlur @input.blur() if @options.remote @@ -92,38 +101,61 @@ class GitLabDropdown LOADING_CLASS = "is-loading" PAGE_TWO_CLASS = "is-page-two" ACTIVE_CLASS = "is-active" + currentIndex = -1 + + FILTER_INPUT = '.dropdown-input .dropdown-input-field' constructor: (@el, @options) -> - self = @ @dropdown = $(@el).parent() + + # Set Defaults + { + # If no input is passed create a default one + @filterInput = @getElement(FILTER_INPUT) + @highlight = false + @filterInputBlur = true + @enterCallback = true + } = @options + + self = @ + + # If selector was passed + if _.isString(@filterInput) + @filterInput = @getElement(@filterInput) + search_fields = if @options.search then @options.search.fields else []; if @options.data - # Remote data - @remote = new GitLabDropdownRemote @options.data, { - dataType: @options.dataType, - beforeSend: @toggleLoading.bind(@) - success: (data) => - @fullData = data + # If data is an array + if _.isArray @options.data + @fullData = @options.data + @parseData @options.data + else + # Remote data + @remote = new GitLabDropdownRemote @options.data, { + dataType: @options.dataType, + beforeSend: @toggleLoading.bind(@) + success: (data) => + @fullData = data - @parseData @fullData - } + @parseData @fullData + } - # Init filiterable + # Init filterable if @options.filterable - @input = @dropdown.find('.dropdown-input .dropdown-input-field') - - @filter = new GitLabDropdownFilter @input, + @filter = new GitLabDropdownFilter @filterInput, + filterInputBlur: @filterInputBlur remote: @options.filterRemote query: @options.data keys: @options.search.fields data: => return @fullData callback: (data) => + currentIndex = -1 @parseData data - @highlightRow 1 enterCallback: => - @selectFirstRow() + if @enterCallback + @selectRowAtIndex 0 # Event listeners @@ -145,10 +177,15 @@ class GitLabDropdown selector = ".dropdown-page-one .dropdown-content a" @dropdown.on "click", selector, (e) -> - selected = self.rowClicked $(@) + $el = $(@) + selected = self.rowClicked $el if self.options.clicked - self.options.clicked(selected) + self.options.clicked(selected, $el, e) + + # Finds an element inside wrapper element + getElement: (selector) -> + @dropdown.find selector toggleLoading: -> $('.dropdown-menu', @dropdown).toggleClass LOADING_CLASS @@ -188,16 +225,19 @@ class GitLabDropdown return true opened: => + @addArrowKeyEvent() + contentHtml = $('.dropdown-content', @dropdown).html() if @remote && contentHtml is "" @remote.execute() if @options.filterable - @dropdown.find(".dropdown-input-field").focus() + @filterInput.focus() @dropdown.trigger('shown.gl.dropdown') hidden: (e) => + @removeArrayKeyEvent() if @options.filterable @dropdown .find(".dropdown-input-field") @@ -237,13 +277,19 @@ class GitLabDropdown renderItem: (data) -> html = "" + # Divider return "<li class='divider'></li>" if data is "divider" + # Separator is a full-width divider + return "<li class='separator'></li>" if data is "separator" + + # Header + return "<li class='dropdown-header'>#{data.header}</li>" if data.header? + if @options.renderRow # Call the render function html = @options.renderRow(data) else - selected = if @options.isSelected then @options.isSelected(data) else false if not selected value = if @options.id then @options.id(data) else data.id fieldName = @options.fieldName @@ -251,35 +297,54 @@ class GitLabDropdown if field.length selected = true - url = if @options.url then @options.url(data) else "#" - text = if @options.text then @options.text(data) else "" + # Set URL + if @options.url? + url = @options.url(data) + else + url = if data.url? then data.url else '#' + + # Set Text + if @options.text? + text = @options.text(data) + else + text = if data.text? then data.text else '' + cssClass = ""; if selected cssClass = "is-active" - html = "<li>" - html += "<a href='#{url}' class='#{cssClass}'>" - html += text - html += "</a>" - html += "</li>" + if @highlight + text = @highlightTextMatches(text, @filterInput.val()) + + html = "<li> + <a href='#{url}' class='#{cssClass}'> + #{text} + </a> + </li>" return html + highlightTextMatches: (text, term) -> + occurrences = fuzzaldrinPlus.match(text, term) + text.split('').map((character, i) -> + if i in occurrences then "<b>#{character}</b>" else character + ).join('') + noResults: -> - html = "<li>" - html += "<a href='#' class='dropdown-menu-empty-link is-focused'>" - html += "No matching results." - html += "</a>" - html += "</li>" + html = "<li class='dropdown-menu-empty-link'> + <a href='#' class='is-focused'> + No matching results. + </a> + </li>" highlightRow: (index) -> - if @input.val() isnt "" + if @filterInput.val() isnt "" selector = '.dropdown-content li:first-child a' if @dropdown.find(".dropdown-toggle-page").length selector = ".dropdown-page-one .dropdown-content li:first-child a" - $(selector).addClass 'is-focused' + @getElement(selector).addClass 'is-focused' rowClicked: (el) -> fieldName = @options.fieldName @@ -288,7 +353,7 @@ class GitLabDropdown selectedObject = @renderedData[selectedIndex] value = if @options.id then @options.id(selectedObject, el) else selectedObject.id field = @dropdown.parent().find("input[name='#{fieldName}'][value='#{value}']") - + if el.hasClass(ACTIVE_CLASS) el.removeClass(ACTIVE_CLASS) field.remove() @@ -296,6 +361,8 @@ class GitLabDropdown # Toggle the dropdown label if @options.toggleLabel $(@el).find(".dropdown-toggle-text").text @options.toggleLabel + else + selectedObject else if !value? field.remove() @@ -311,24 +378,93 @@ class GitLabDropdown if @options.toggleLabel $(@el).find(".dropdown-toggle-text").text @options.toggleLabel(selectedObject) if value? - if !field.length + if !field.length and fieldName # Create hidden input for form input = "<input type='hidden' name='#{fieldName}' value='#{value}' />" if @options.inputId? input = $(input) .attr('id', @options.inputId) @dropdown.before input + else + field.val value return selectedObject - selectFirstRow: -> - selector = '.dropdown-content li:first-child a' + selectRowAtIndex: (index) -> + selector = ".dropdown-content li:not(.divider):eq(#{index}) a" + if @dropdown.find(".dropdown-toggle-page").length - selector = ".dropdown-page-one .dropdown-content li:first-child a" + selector = ".dropdown-page-one #{selector}" # simulate a click on the first link - $(selector).trigger "click" + $(selector, @dropdown).trigger "click" + + addArrowKeyEvent: -> + ARROW_KEY_CODES = [38, 40] + $input = @dropdown.find(".dropdown-input-field") + + selector = '.dropdown-content li:not(.divider)' + if @dropdown.find(".dropdown-toggle-page").length + selector = ".dropdown-page-one #{selector}" + + $('body').on 'keydown', (e) => + currentKeyCode = e.which + + if ARROW_KEY_CODES.indexOf(currentKeyCode) >= 0 + e.preventDefault() + e.stopImmediatePropagation() + + PREV_INDEX = currentIndex + $listItems = $(selector, @dropdown) + + # if @options.filterable + # $input.blur() + + if currentKeyCode is 40 + # Move down + currentIndex += 1 if currentIndex < ($listItems.length - 1) + else if currentKeyCode is 38 + # Move up + currentIndex -= 1 if currentIndex > 0 + + @highlightRowAtIndex($listItems, currentIndex) if currentIndex isnt PREV_INDEX + + return false + + if currentKeyCode is 13 + @selectRowAtIndex currentIndex + + removeArrayKeyEvent: -> + $('body').off 'keydown' + + highlightRowAtIndex: ($listItems, index) -> + # Remove the class for the previously focused row + $('.is-focused', @dropdown).removeClass 'is-focused' + + # Update the class for the row at the specific index + $listItem = $listItems.eq(index) + $listItem.find('a:first-child').addClass "is-focused" + + # Dropdown content scroll area + $dropdownContent = $listItem.closest('.dropdown-content') + dropdownScrollTop = $dropdownContent.scrollTop() + dropdownContentHeight = $dropdownContent.outerHeight() + dropdownContentTop = $dropdownContent.prop('offsetTop') + dropdownContentBottom = dropdownContentTop + dropdownContentHeight + + # Get the offset bottom of the list item + listItemHeight = $listItem.outerHeight() + listItemTop = $listItem.prop('offsetTop') + listItemBottom = listItemTop + listItemHeight + + if listItemBottom > dropdownContentBottom + dropdownScrollTop + # Scroll the dropdown content down + $dropdownContent.scrollTop(listItemBottom - dropdownContentBottom) + else if listItemTop < dropdownContentTop + dropdownScrollTop + # Scroll the dropdown content up + $dropdownContent.scrollTop(listItemTop - dropdownContentTop) $.fn.glDropdown = (opts) -> return @.each -> - new GitLabDropdown @, opts + if (!$.data @, 'glDropdown') + $.data(@, 'glDropdown', new GitLabDropdown @, opts) diff --git a/app/assets/javascripts/issue.js.coffee b/app/assets/javascripts/issue.js.coffee index d663e34871c..946d83b7bdd 100644 --- a/app/assets/javascripts/issue.js.coffee +++ b/app/assets/javascripts/issue.js.coffee @@ -6,25 +6,10 @@ class @Issue constructor: -> # Prevent duplicate event bindings @disableTaskList() - @fixAffixScroll() if $('a.btn-close').length @initTaskList() @initIssueBtnEventListeners() - fixAffixScroll: -> - fixAffix = -> - $discussion = $('.issuable-discussion') - $sidebar = $('.issuable-sidebar') - if $sidebar.hasClass('no-affix') - $sidebar.removeClass(['affix-top','affix']) - discussionHeight = $discussion.height() - sidebarHeight = $sidebar.height() - if sidebarHeight > discussionHeight - $discussion.height(sidebarHeight + 50) - $sidebar.addClass('no-affix') - $(window).on('resize', fixAffix) - fixAffix() - initTaskList: -> $('.detail-page-description .js-task-list-container').taskList('enable') $(document).on 'tasklist:changed', '.detail-page-description .js-task-list-container', @updateTaskList @@ -49,7 +34,7 @@ class @Issue issueStatus = if isClose then 'close' else 'open' new Flash(issueFailMessage, 'alert') success: (data, textStatus, jqXHR) -> - if data.saved + if 'id' of data $(document).trigger('issuable:change'); if isClose $('a.btn-close').addClass('hidden') diff --git a/app/assets/javascripts/issues.js.coffee b/app/assets/javascripts/issues.js.coffee index b1479bfb449..0d9f2094c2a 100644 --- a/app/assets/javascripts/issues.js.coffee +++ b/app/assets/javascripts/issues.js.coffee @@ -26,6 +26,20 @@ $(".selected_issue").bind "change", Issues.checkChanged + # Update state filters if present in page + updateStateFilters: -> + stateFilters = $('.issues-state-filters') + newParams = {} + paramKeys = ['author_id', 'label_name', 'milestone_title', 'assignee_id', 'issue_search'] + + for paramKey in paramKeys + newParams[paramKey] = gl.utils.getUrlParameter(paramKey) or '' + + if stateFilters.length + stateFilters.find('a').each -> + initialUrl = $(this).attr 'href' + $(this).attr 'href', gl.utils.mergeUrlParams(newParams, initialUrl) + # Make sure we trigger ajax request only after user stop typing initSearch: -> @timer = null @@ -54,6 +68,7 @@ # Change url so if user reload a page - search results are saved history.replaceState {page: issuesUrl}, document.title, issuesUrl Issues.reload() + Issues.updateStateFilters() dataType: "json" checkChanged: -> diff --git a/app/assets/javascripts/lib/notify.js.coffee b/app/assets/javascripts/lib/notify.js.coffee new file mode 100644 index 00000000000..3f9ca39912c --- /dev/null +++ b/app/assets/javascripts/lib/notify.js.coffee @@ -0,0 +1,30 @@ +((w) -> + notificationGranted = (message, opts, onclick) -> + notification = new Notification(message, opts) + + if onclick + notification.onclick = onclick + + notifyPermissions = -> + if 'Notification' of window + Notification.requestPermission() + + notifyMe = (message, body, icon, onclick) -> + opts = + body: body + icon: icon + # Let's check if the browser supports notifications + if !('Notification' of window) + # do nothing + else if Notification.permission == 'granted' + # If it's okay let's create a notification + notificationGranted message, opts, onclick + else if Notification.permission != 'denied' + Notification.requestPermission (permission) -> + # If the user accepts, let's create a notification + if permission == 'granted' + notificationGranted message, opts, onclick + + w.notify = notifyMe + w.notifyPermissions = notifyPermissions +) window diff --git a/app/assets/javascripts/lib/url_utility.js.coffee b/app/assets/javascripts/lib/url_utility.js.coffee new file mode 100644 index 00000000000..abd556e0b4e --- /dev/null +++ b/app/assets/javascripts/lib/url_utility.js.coffee @@ -0,0 +1,31 @@ +((w) -> + + w.gl ?= {} + w.gl.utils ?= {} + + w.gl.utils.getUrlParameter = (sParam) -> + sPageURL = decodeURIComponent(window.location.search.substring(1)) + sURLVariables = sPageURL.split('&') + sParameterName = undefined + i = 0 + while i < sURLVariables.length + sParameterName = sURLVariables[i].split('=') + if sParameterName[0] is sParam + return if sParameterName[1] is undefined then true else sParameterName[1] + i++ + + # # + # @param {Object} params - url keys and value to merge + # @param {String} url + # # + w.gl.utils.mergeUrlParams = (params, url) -> + newUrl = decodeURIComponent(url) + for paramName, paramValue of params + pattern = new RegExp "\\b(#{paramName}=).*?(&|$)" + if url.search(pattern) >= 0 + newUrl = newUrl.replace pattern, "$1#{paramValue}$2" + else + newUrl = "#{newUrl}#{(if newUrl.indexOf('?') > 0 then '&' else '?')}#{paramName}=#{paramValue}" + newUrl + +) window diff --git a/app/assets/javascripts/merge_request.js.coffee b/app/assets/javascripts/merge_request.js.coffee index 6af5a48a0bb..1f46e331427 100644 --- a/app/assets/javascripts/merge_request.js.coffee +++ b/app/assets/javascripts/merge_request.js.coffee @@ -15,8 +15,6 @@ class @MergeRequest this.$('.show-all-commits').on 'click', => this.showAllCommits() - @fixAffixScroll(); - @initTabs() # Prevent duplicate event bindings @@ -30,20 +28,6 @@ class @MergeRequest $: (selector) -> this.$el.find(selector) - fixAffixScroll: -> - fixAffix = -> - $discussion = $('.issuable-discussion') - $sidebar = $('.issuable-sidebar') - if $sidebar.hasClass('no-affix') - $sidebar.removeClass(['affix-top','affix']) - discussionHeight = $discussion.height() - sidebarHeight = $sidebar.height() - if sidebarHeight > discussionHeight - $discussion.height(sidebarHeight + 50) - $sidebar.addClass('no-affix') - $(window).on('resize', fixAffix) - fixAffix() - initTabs: -> if @opts.action != 'new' # `MergeRequests#new` has no tab-persisting or lazy-loading behavior diff --git a/app/assets/javascripts/merge_request_widget.js.coffee b/app/assets/javascripts/merge_request_widget.js.coffee index 738ffc8343b..84a8887fbce 100644 --- a/app/assets/javascripts/merge_request_widget.js.coffee +++ b/app/assets/javascripts/merge_request_widget.js.coffee @@ -2,13 +2,20 @@ class @MergeRequestWidget # Initialize MergeRequestWidget behavior # # check_enable - Boolean, whether to check automerge status - # url_to_automerge_check - String, URL to use to check automerge status - # current_status - String, current automerge status - # ci_enable - Boolean, whether a CI service is enabled - # url_to_ci_check - String, URL to use to check CI status + # merge_check_url - String, URL to use to check automerge status + # ci_status_url - String, URL to use to check CI status # + constructor: (@opts) -> - modal = $('#modal_merge_info').modal(show: false) + $('#modal_merge_info').modal(show: false) + @firstCICheck = true + @readyForCICheck = true + clearInterval @fetchBuildStatusInterval + + @pollCIStatus() + notifyPermissions() + + setOpts: (@opts) -> mergeInProgress: (deleteSourceBranch = false)-> $.ajax @@ -27,18 +34,61 @@ class @MergeRequestWidget dataType: 'json' getMergeStatus: -> - $.get @opts.url_to_automerge_check, (data) -> + $.get @opts.merge_check_url, (data) -> $('.mr-state-widget').replaceWith(data) - getCiStatus: -> - if @opts.ci_enable - $.get @opts.url_to_ci_check, (data) => - this.showCiState data.status + ciLabelForStatus: (status) -> + if status == 'success' + 'passed' + else + status + + pollCIStatus: -> + @fetchBuildStatusInterval = setInterval ( => + return if not @readyForCICheck + + @getCIStatus(true) + + @readyForCICheck = false + ), 10000 + + getCIStatus: (showNotification) -> + _this = @ + $('.ci-widget-fetching').show() + + $.getJSON @opts.ci_status_url, (data) => + @readyForCICheck = true + + if @firstCICheck + @firstCICheck = false + @opts.ci_status = data.status + + if @opts.ci_status is '' + @opts.ci_status = data.status + return + + if data.status isnt @opts.ci_status + @showCIStatus data.status if data.coverage - this.showCiCoverage data.coverage - , 'json' + @showCICoverage data.coverage + + if showNotification + message = @opts.ci_message.replace('{{status}}', @ciLabelForStatus(data.status)) + message = message.replace('{{sha}}', data.sha) + message = message.replace('{{title}}', data.title) + + notify( + "Build #{@ciLabelForStatus(data.status)}", + message, + @opts.gitlab_icon, + -> + @close() + Turbolinks.visit _this.opts.builds_path + ) + + @opts.ci_status = data.status - showCiState: (state) -> + showCIStatus: (state) -> $('.ci_widget').hide() allowed_states = ["failed", "canceled", "running", "pending", "success", "skipped", "not_found"] if state in allowed_states @@ -52,7 +102,7 @@ class @MergeRequestWidget $('.ci_widget.ci-error').show() @setMergeButtonClass('btn-danger') - showCiCoverage: (coverage) -> + showCICoverage: (coverage) -> text = 'Coverage ' + coverage + '%' $('.ci_widget:visible .ci-coverage').text(text) diff --git a/app/assets/javascripts/milestone_select.js.coffee b/app/assets/javascripts/milestone_select.js.coffee index e2a7d5fbba2..f73127f49f0 100644 --- a/app/assets/javascripts/milestone_select.js.coffee +++ b/app/assets/javascripts/milestone_select.js.coffee @@ -84,12 +84,16 @@ class @MilestoneSelect # display:block overrides the hide-collapse rule $value.removeAttr('style') - clicked: (e) -> + clicked: (selected) -> if $dropdown.hasClass 'js-filter-bulk-update' return - if $dropdown.hasClass 'js-filter-submit' - $dropdown.parents('form').submit() + if $dropdown.hasClass('js-filter-submit') + if selected.name? + selectedMilestone = selected.name + else + selectedMilestone = '' + Issues.filterResults $dropdown.closest('form') else selected = $selectbox .find('input[type="hidden"]') @@ -117,4 +121,4 @@ class @MilestoneSelect else $value.html(milestoneLinkNoneTemplate) $sidebarCollapsedValue.find('span').text('No') - )
\ No newline at end of file + ) diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee index ff06c57f2b5..86e3b860fcb 100644 --- a/app/assets/javascripts/notes.js.coffee +++ b/app/assets/javascripts/notes.js.coffee @@ -251,13 +251,11 @@ class @Notes Sets some hidden fields in the form. ### setupMainTargetNoteForm: -> - # find the form form = $(".js-new-note-form") - # insert the form after the button - form.clone().replaceAll $(".js-main-target-form") - form = form.prev("form") + # Set a global clone of the form for later cloning + @formClone = form.clone() # show the form @setupNoteForm(form) @@ -266,9 +264,7 @@ class @Notes form.removeClass "js-new-note-form" form.addClass "js-main-target-form" - # remove unnecessary fields and buttons form.find("#note_line_code").remove() - form.find(".js-close-discussion-note-form").remove() ### General note form setup. @@ -297,7 +293,14 @@ class @Notes else previewButton.removeClass("turn-on").addClass "turn-off" + textarea.on 'focus', -> + $(this).closest('.md-area').addClass 'is-focused' + + textarea.on 'blur', -> + $(this).closest('.md-area').removeClass 'is-focused' + autosize(textarea) + new Autosave textarea, [ "Note" form.find("#note_commit_id").val() @@ -307,7 +310,6 @@ class @Notes ] # remove notify commit author checkbox for non-commit notes - form.find(".js-notify-commit-author").remove() if form.find("#note_noteable_type").val() isnt "Commit" GitLab.GfmAutoComplete.setup() new DropzoneInput(form) form.show() @@ -455,15 +457,15 @@ class @Notes Shows the note form below the notes. ### replyToDiscussionNote: (e) => - form = $(".js-new-note-form") + form = @formClone.clone() replyLink = $(e.target).closest(".js-discussion-reply-button") replyLink.hide() # insert the form after the button - form.clone().insertAfter replyLink + replyLink.after form # show the form - @setupDiscussionNoteForm(replyLink, replyLink.next("form")) + @setupDiscussionNoteForm(replyLink, form) ### Shows the diff or discussion form and does some setup on it. @@ -488,7 +490,9 @@ class @Notes .text(form.find('.js-close-discussion-note-form').data('cancel-text')) @setupNoteForm form form.find(".js-note-text").focus() - form.addClass "js-discussion-note-form" + form + .removeClass('js-main-target-form') + .addClass("discussion-form js-discussion-note-form") ### Called when clicking on the "add a comment" button on the side of a diff line. @@ -498,9 +502,8 @@ class @Notes ### addDiffNote: (e) => e.preventDefault() - link = e.currentTarget - form = $(".js-new-note-form") - row = $(link).closest("tr") + $link = $(e.currentTarget) + row = $link.closest("tr") nextRow = row.next() hasNotes = nextRow.is(".notes_holder") addForm = false @@ -509,7 +512,7 @@ class @Notes # In parallel view, look inside the correct left/right pane if @isParallelView() - lineType = $(link).data("lineType") + lineType = $link.data("lineType") targetContent += "." + lineType rowCssToAdd = "<tr class=\"notes_holder js-temp-notes-holder\"><td class=\"notes_line\"></td><td class=\"notes_content parallel old\"></td><td class=\"notes_line\"></td><td class=\"notes_content parallel new\"></td></tr>" @@ -531,11 +534,11 @@ class @Notes addForm = true if addForm - newForm = form.clone() + newForm = @formClone.clone() newForm.appendTo row.next().find(targetContent) # show the form - @setupDiscussionNoteForm $(link), newForm + @setupDiscussionNoteForm $link, newForm ### Called in response to "cancel" on a diff note form. @@ -560,7 +563,6 @@ class @Notes cancelDiscussionForm: (e) => e.preventDefault() - form = $(".js-new-note-form") form = $(e.target).closest(".js-discussion-note-form") @removeDiscussionNoteForm(form) diff --git a/app/assets/javascripts/search_autocomplete.js.coffee b/app/assets/javascripts/search_autocomplete.js.coffee index c1801365266..6a7b4ad1db7 100644 --- a/app/assets/javascripts/search_autocomplete.js.coffee +++ b/app/assets/javascripts/search_autocomplete.js.coffee @@ -1,11 +1,296 @@ class @SearchAutocomplete - constructor: (search_autocomplete_path, project_id, project_ref) -> - project_id = '' unless project_id - project_ref = '' unless project_ref - query = "?project_id=" + project_id + "&project_ref=" + project_ref - - $("#search").autocomplete - source: search_autocomplete_path + query - minLength: 1 - select: (event, ui) -> - location.href = ui.item.url + + KEYCODE = + ESCAPE: 27 + BACKSPACE: 8 + ENTER: 13 + + constructor: (opts = {}) -> + { + @wrap = $('.search') + + @optsEl = @wrap.find('.search-autocomplete-opts') + @autocompletePath = @optsEl.data('autocomplete-path') + @projectId = @optsEl.data('autocomplete-project-id') || '' + @projectRef = @optsEl.data('autocomplete-project-ref') ||Â '' + + } = opts + + # Dropdown Element + @dropdown = @wrap.find('.dropdown') + @dropdownContent = @dropdown.find('.dropdown-content') + + @locationBadgeEl = @getElement('.search-location-badge') + @locationText = @getElement('.location-text') + @scopeInputEl = @getElement('#scope') + @searchInput = @getElement('.search-input') + @projectInputEl = @getElement('#search_project_id') + @groupInputEl = @getElement('#group_id') + @searchCodeInputEl = @getElement('#search_code') + @repositoryInputEl = @getElement('#repository_ref') + @clearInput = @getElement('.js-clear-input') + + @saveOriginalState() + + # Only when user is logged in + @createAutocomplete() if gon.current_user_id + + @searchInput.addClass('disabled') + + @saveTextLength() + + @bindEvents() + + # Finds an element inside wrapper element + getElement: (selector) -> + @wrap.find(selector) + + saveOriginalState: -> + @originalState = @serializeState() + + saveTextLength: -> + @lastTextLength = @searchInput.val().length + + createAutocomplete: -> + @searchInput.glDropdown + filterInputBlur: false + filterable: true + filterRemote: true + highlight: true + enterCallback: false + filterInput: 'input#search' + search: + fields: ['text'] + data: @getData.bind(@) + selectable: true + clicked: @onClick.bind(@) + + getData: (term, callback) -> + _this = @ + + # Do not trigger request if input is empty + return if @searchInput.val() is '' + + # Prevent multiple ajax calls + return if @loadingSuggestions + + @loadingSuggestions = true + + jqXHR = $.get(@autocompletePath, { + project_id: @projectId + project_ref: @projectRef + term: term + }, (response) -> + # Hide dropdown menu if no suggestions returns + if !response.length + _this.disableAutocomplete() + return + + data = [] + + # List results + firstCategory = true + for suggestion in response + + # Add group header before list each group + if lastCategory isnt suggestion.category + data.push 'separator' if !firstCategory + + firstCategory = false if firstCategory + + data.push + header: suggestion.category + + lastCategory = suggestion.category + + data.push + id: "#{suggestion.category.toLowerCase()}-#{suggestion.id}" + category: suggestion.category + text: suggestion.label + url: suggestion.url + + # Add option to proceed with the search + if data.length + data.push('separator') + data.push + text: "Result name contains \"#{term}\"" + url: "/search?\ + search=#{term}\ + &project_id=#{_this.projectInputEl.val()}\ + &group_id=#{_this.groupInputEl.val()}" + + callback(data) + ).always -> + _this.loadingSuggestions = false + + serializeState: -> + { + # Search Criteria + search_project_id: @projectInputEl.val() + group_id: @groupInputEl.val() + search_code: @searchCodeInputEl.val() + repository_ref: @repositoryInputEl.val() + scope: @scopeInputEl.val() + + # Location badge + _location: @locationText.text() + } + + bindEvents: -> + $(document).on 'click', @onDocumentClick + @searchInput.on 'keydown', @onSearchInputKeyDown + @searchInput.on 'keyup', @onSearchInputKeyUp + @searchInput.on 'click', @onSearchInputClick + @searchInput.on 'focus', @onSearchInputFocus + @clearInput.on 'click', @onClearInputClick + + onDocumentClick: (e) => + # If clicking outside the search box + # And search input is not focused + # And we are not clicking inside a suggestion + if not $.contains(@dropdown[0], e.target) and @isFocused and not $(e.target).parents('ul').length + @onSearchInputBlur() + + enableAutocomplete: -> + # No need to enable anything if user is not logged in + return if !gon.current_user_id + + _this = @ + @loadingSuggestions = false + + @dropdown.addClass('open') + @searchInput.removeClass('disabled') + + onSearchInputKeyDown: => + # Saves last length of the entered text + @saveTextLength() + + onSearchInputKeyUp: (e) => + switch e.keyCode + when KEYCODE.BACKSPACE + # when trying to remove the location badge + if @lastTextLength is 0 and @badgePresent() + @removeLocationBadge() + + # When removing the last character and no badge is present + if @lastTextLength is 1 + @disableAutocomplete() + + # When removing any character from existin value + if @lastTextLength > 1 + @enableAutocomplete() + + when KEYCODE.ESCAPE + @restoreOriginalState() + + else + # Handle the case when deleting the input value other than backspace + # e.g. Pressing ctrl + backspace or ctrl + x + if @searchInput.val() is '' + @disableAutocomplete() + else + # We should display the menu only when input is not empty + @enableAutocomplete() + + @wrap.toggleClass 'has-value', !!e.target.value + + # Avoid falsy value to be returned + return + + onSearchInputClick: (e) => + # Prevents closing the dropdown menu + e.stopImmediatePropagation() + + onSearchInputFocus: => + @isFocused = true + @wrap.addClass('search-active') + + onClearInputClick: (e) => + e.preventDefault() + @searchInput.val('').focus() + + onSearchInputBlur: (e) => + @isFocused = false + @wrap.removeClass('search-active') + + # If input is blank then restore state + if @searchInput.val() is '' + @restoreOriginalState() + + addLocationBadge: (item) -> + category = if item.category? then "#{item.category}: " else '' + value = if item.value? then item.value else '' + + html = "<span class='location-badge'> + <i class='location-text'>#{category}#{value}</i> + </span>" + @locationBadgeEl.html(html) + @wrap.addClass('has-location-badge') + + restoreOriginalState: -> + inputs = Object.keys @originalState + + for input in inputs + @getElement("##{input}").val(@originalState[input]) + + + if @originalState._location is '' + @locationBadgeEl.empty() + else + @addLocationBadge( + value: @originalState._location + ) + + @dropdown.removeClass 'open' + + badgePresent: -> + @locationBadgeEl.children().length + + resetSearchState: -> + inputs = Object.keys @originalState + + for input in inputs + + # _location isnt a input + break if input is '_location' + + @getElement("##{input}").val('') + + removeLocationBadge: -> + @locationBadgeEl.empty() + + # Reset state + @resetSearchState() + + @wrap.removeClass('has-location-badge') + + disableAutocomplete: -> + @searchInput.addClass('disabled') + @dropdown.removeClass('open') + @restoreMenu() + + restoreMenu: -> + html = "<ul> + <li><a class='dropdown-menu-empty-link is-focused'>Loading...</a></li> + </ul>" + @dropdownContent.html(html) + + onClick: (item, $el, e) -> + if location.pathname.indexOf(item.url) isnt -1 + e.preventDefault() + if not @badgePresent + if item.category is 'Projects' + @projectInputEl.val(item.id) + @addLocationBadge( + value: 'This project' + ) + + if item.category is 'Groups' + @groupInputEl.val(item.id) + @addLocationBadge( + value: 'This group' + ) + + $el.removeClass('is-active') + @disableAutocomplete() + @searchInput.val('').focus() diff --git a/app/assets/javascripts/sidebar.js.coffee b/app/assets/javascripts/sidebar.js.coffee index 860d4f438d0..e1778511240 100644 --- a/app/assets/javascripts/sidebar.js.coffee +++ b/app/assets/javascripts/sidebar.js.coffee @@ -4,7 +4,6 @@ expanded = 'page-sidebar-expanded' toggleSidebar = -> $('.page-with-sidebar').toggleClass("#{collapsed} #{expanded}") $('header').toggleClass("header-collapsed header-expanded") - $('.toggle-nav-collapse i').toggleClass("fa-angle-right fa-angle-left") $.cookie("collapsed_nav", $('.page-with-sidebar').hasClass(collapsed), { path: '/' }) setTimeout ( -> diff --git a/app/assets/javascripts/zen_mode.js.coffee b/app/assets/javascripts/zen_mode.js.coffee index e1c5446eaac..99f35ecfb0f 100644 --- a/app/assets/javascripts/zen_mode.js.coffee +++ b/app/assets/javascripts/zen_mode.js.coffee @@ -42,7 +42,7 @@ class @ZenMode $(e.currentTarget).trigger('zen_mode:leave') $(document).on 'zen_mode:enter', (e) => - @enter(e.target.parentNode) + @enter($(e.target).closest('.md-area').find('.zen-backdrop')) $(document).on 'zen_mode:leave', (e) => @exit() diff --git a/app/assets/stylesheets/behaviors.scss b/app/assets/stylesheets/behaviors.scss index 469f4f296ae..542a53f0377 100644 --- a/app/assets/stylesheets/behaviors.scss +++ b/app/assets/stylesheets/behaviors.scss @@ -13,10 +13,10 @@ // Toggle between two states. .js-toggler-container { - .turn-on { display: block; } + .turn-on { display: block; } .turn-off { display: none; } &.on { - .turn-on { display: none; } + .turn-on { display: none; } .turn-off { display: block; } } } diff --git a/app/assets/stylesheets/framework/calendar.scss b/app/assets/stylesheets/framework/calendar.scss index e3192823a1a..0b3af592d4a 100644 --- a/app/assets/stylesheets/framework/calendar.scss +++ b/app/assets/stylesheets/framework/calendar.scss @@ -1,3 +1,9 @@ +.calender-block { + @media (min-width: $screen-sm-min) and (max-width: $screen-lg-min) { + overflow-x: scroll; + } +} + .user-calendar-activities { .calendar_onclick_hr { padding: 0; diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss index 9b676d759e0..2ade341c9dd 100644 --- a/app/assets/stylesheets/framework/common.scss +++ b/app/assets/stylesheets/framework/common.scss @@ -121,17 +121,10 @@ p.time { text-shadow: none; } -.thin_area{ +.thin_area { height: 150px; } -// Fixes alignment on notes. -.new_note { - label { - text-align: left; - } -} - // Fix issue with notes & lists creating a bunch of bottom borders. li.note { img { max-width: 100% } @@ -148,7 +141,7 @@ li.note { } } -.wiki_content code, .readme code{ +.wiki_content code, .readme code { background-color: inherit; } diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss index 6c870ed927e..82dc1acbd01 100644 --- a/app/assets/stylesheets/framework/dropdowns.scss +++ b/app/assets/stylesheets/framework/dropdowns.scss @@ -42,7 +42,7 @@ font-size: 15px; text-align: left; border: 1px solid $dropdown-toggle-border-color; - border-radius: 2px; + border-radius: $dropdown-border-radius; outline: 0; text-overflow: ellipsis; white-space: nowrap; @@ -75,12 +75,12 @@ width: 240px; margin-top: 2px; margin-bottom: 0; - padding: 10px; - font-size: 14px; + font-size: 15px; font-weight: normal; + padding: 10px 0; background-color: $dropdown-bg; border: 1px solid $dropdown-border-color; - border-radius: $border-radius-base; + border-radius: $dropdown-border-radius; box-shadow: 0 2px 4px $dropdown-shadow-color; &.is-loading { @@ -101,9 +101,17 @@ li { text-align: left; list-style: none; + padding: 0 10px; } .divider { + height: 1px; + margin: 8px 10px; + padding: 0; + background-color: $dropdown-divider-color; + } + + .separator { width: 100%; height: 1px; margin-top: 8px; @@ -141,6 +149,17 @@ line-height: 16px; } } + + .dropdown-header { + color: $dropdown-header-color; + font-size: 13px; + line-height: 22px; + padding: 0 10px 10px; + } + + .separator + .dropdown-header { + padding-top: 2px; + } } .dropdown-menu-paging { @@ -158,6 +177,10 @@ .dropdown-menu-back { display: block; } + + .dropdown-content { + padding: 0 10px; + } } } @@ -193,7 +216,7 @@ } .dropdown-select { - width: 300px; + width: $dropdown-width; } .dropdown-menu-align-right { @@ -222,20 +245,11 @@ } } -.dropdown-header { - padding-left: 5px; - padding-right: 5px; - color: $dropdown-header-color; - font-size: 13px; - line-height: 22px; -} .dropdown-title { position: relative; - margin-bottom: 10px; - padding-left: 30px; - padding-right: 30px; - padding-bottom: 10px; + padding: 0 0 15px; + margin: 0 10px 10px; font-weight: 600; line-height: 1; text-align: center; @@ -261,21 +275,26 @@ } .dropdown-menu-close { - right: 0; + right: 7px; + width: 20px; + height: 20px; + top: -1px; } .dropdown-menu-back { - left: 0; + left: 7px; + top: 2px; } .dropdown-input { position: relative; margin-bottom: 10px; + padding: 0 10px; .fa { position: absolute; top: 10px; - right: 10px; + right: 20px; color: #c7c7c7; font-size: 12px; pointer-events: none; @@ -285,6 +304,9 @@ display: none; cursor: pointer; pointer-events: all; + right: 22px; + top: 9px; + font-size: 14px; } &.has-value { diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss index a26ace5cc19..b15f4e7bd5e 100644 --- a/app/assets/stylesheets/framework/files.scss +++ b/app/assets/stylesheets/framework/files.scss @@ -20,6 +20,7 @@ margin: 0; text-align: left; padding: 10px $gl-padding; + word-wrap: break-word; .file-actions { float: right; diff --git a/app/assets/stylesheets/framework/filters.scss b/app/assets/stylesheets/framework/filters.scss index b05c5df1bd8..9209347f9bc 100644 --- a/app/assets/stylesheets/framework/filters.scss +++ b/app/assets/stylesheets/framework/filters.scss @@ -3,7 +3,7 @@ vertical-align: top; } -@media (min-width: $screen-sm-min) { +@media (min-width: $screen-sm-min) { .issues-filters, .issues_bulk_update { .dropdown-menu-toggle { diff --git a/app/assets/stylesheets/framework/forms.scss b/app/assets/stylesheets/framework/forms.scss index 4cb4129b71b..54cb5461113 100644 --- a/app/assets/stylesheets/framework/forms.scss +++ b/app/assets/stylesheets/framework/forms.scss @@ -6,40 +6,6 @@ input { border-radius: $border-radius-base; } -input[type='search'] { - background-color: white; - padding-left: 10px; -} - -input[type='search'].search-input { - background-repeat: no-repeat; - background-position: 10px; - background-size: 16px; - background-position-x: 30%; - padding-left: 10px; - background-color: $gray-light; - - &.search-input[value=""] { - background-image: url('data:image/png;base64,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'); - } - - &.search-input::-webkit-input-placeholder { - text-align: center; - } - - &.search-input:-moz-placeholder { /* Firefox 18- */ - text-align: center; - } - - &.search-input::-moz-placeholder { /* Firefox 19+ */ - text-align: center; - } - - &.search-input:-ms-input-placeholder { - text-align: center; - } -} - input[type='text'].danger { background: #f2dede!important; border-color: #d66; @@ -125,7 +91,7 @@ label { } .form-control::-webkit-input-placeholder { - color: #7f8fa4; + color: $gl-placeholder-color; } .input-group { diff --git a/app/assets/stylesheets/framework/gitlab-theme.scss b/app/assets/stylesheets/framework/gitlab-theme.scss index c83cf881596..fa9038ebaca 100644 --- a/app/assets/stylesheets/framework/gitlab-theme.scss +++ b/app/assets/stylesheets/framework/gitlab-theme.scss @@ -33,10 +33,15 @@ background: $color; } + .complex-sidebar .nav-primary { + border-right: 1px solid lighten($color, 3%); + } + .sidebar-wrapper { background: $color-darker; .sidebar-user { + border-top: 1px solid lighten($color, 3%); background: $color-darker; color: $color-light; @@ -62,7 +67,6 @@ .count { color: $color-light; - background: $color-dark; } } diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss index 6a68bb5c115..724980b2208 100644 --- a/app/assets/stylesheets/framework/header.scss +++ b/app/assets/stylesheets/framework/header.scss @@ -36,7 +36,7 @@ header { padding: 0; .nav > li > a { - color: #7f8fa4; + color: $gl-icon-color; font-size: 18px; padding: 0; margin: ($header-height - 28) / 2 0; @@ -62,7 +62,7 @@ header { background-color: #eee; } &.active { - color: #7f8fa4; + color: $gl-icon-color; } } } @@ -81,14 +81,14 @@ header { font-size: 19px; line-height: $header-height; font-weight: normal; - color: #4c4e54; + color: $gl-text-color; overflow: hidden; text-overflow: ellipsis; vertical-align: top; white-space: nowrap; a { - color: #4c4e54; + color: $gl-text-color; &:hover { text-decoration: underline; } @@ -117,37 +117,17 @@ header { } } - .search { - margin-right: 10px; - margin-left: 10px; - margin-top: ($header-height - 36) / 2; - - form { - margin: 0; - padding: 0; - } - - .search-input { - width: 220px; - - &:focus { - @include box-shadow(none); - outline: none; - } - } - } - .impersonation i { color: $red-normal; } } @mixin collapsed-header { - margin-left: $sidebar_collapsed_width; + margin-left: 40px; } .header-collapsed { - margin-left: $sidebar_collapsed_width; + margin-left: 40px; @media (min-width: $screen-md-min) { @include collapsed-header; diff --git a/app/assets/stylesheets/framework/markdown_area.scss b/app/assets/stylesheets/framework/markdown_area.scss index 8328aac4e7a..c8f86d60e3b 100644 --- a/app/assets/stylesheets/framework/markdown_area.scss +++ b/app/assets/stylesheets/framework/markdown_area.scss @@ -1,9 +1,7 @@ .div-dropzone-wrapper { .div-dropzone { position: relative; - padding: 0; - border: 0; - margin-bottom: 5px; + margin-bottom: -5px; .div-dropzone-focus { border-color: #66afe9 !important; @@ -25,12 +23,10 @@ .div-dropzone-spinner { position: absolute; - top: 100%; - left: 100%; - margin-top: -1.1em; - margin-left: -1.1em; + bottom: 10px; + right: 5px; opacity: 0; - font-size: 30px; + font-size: 20px; transition: opacity 200ms ease-in-out; } @@ -65,17 +61,30 @@ position: relative; } +.md-header { + .nav-links { + .active { + a { + border-bottom-color: #000; + } + } + + a { + padding-top: 0; + line-height: 1; + } + } +} + .referenced-users { color: #4c4e54; padding-top: 10px; } .md-preview-holder { - background: #fff; - border: 1px solid #ddd; - min-height: 169px; - padding: 5px; - box-shadow: none; + min-height: 167px; + padding: 10px 0; + overflow-x: auto; } .markdown-area { diff --git a/app/assets/stylesheets/framework/mobile.scss b/app/assets/stylesheets/framework/mobile.scss index 5ea4f9a49db..66180f38a4f 100644 --- a/app/assets/stylesheets/framework/mobile.scss +++ b/app/assets/stylesheets/framework/mobile.scss @@ -107,7 +107,7 @@ } .page-title { - .note_created_ago, .new-issue-link { + .note-created-ago, .new-issue-link { display: none; } } @@ -116,7 +116,7 @@ display: none; } - aside:not(.right-sidebar){ + aside:not(.right-sidebar) { display: none; } diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss index 95bdd6d1ea3..94f5a12ff6a 100644 --- a/app/assets/stylesheets/framework/nav.scss +++ b/app/assets/stylesheets/framework/nav.scss @@ -56,6 +56,17 @@ } } + .nav-search { + display: inline-block; + width: 50%; + padding: 11px 0; + + /* Small devices (phones, tablets, 768px and lower) */ + @media (max-width: $screen-sm-min) { + width: 100%; + } + } + .nav-links { display: inline-block; width: 50%; @@ -100,6 +111,7 @@ > form { display: inline-block; + margin-top: -1px; } .icon-label { @@ -110,7 +122,7 @@ height: 34px; display: inline-block; position: relative; - top: 1px; + top: 2px; margin-right: $gl-padding-top; /* Medium devices (desktops, 992px and up) */ diff --git a/app/assets/stylesheets/framework/selects.scss b/app/assets/stylesheets/framework/selects.scss index e82d052f45a..b2fab387e17 100644 --- a/app/assets/stylesheets/framework/selects.scss +++ b/app/assets/stylesheets/framework/selects.scss @@ -51,7 +51,7 @@ padding: 10px 15px; } -.select2-drop{ +.select2-drop { color: #7f8fa4; } diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss index 18189e985c4..1d49249dd80 100644 --- a/app/assets/stylesheets/framework/sidebar.scss +++ b/app/assets/stylesheets/framework/sidebar.scss @@ -144,7 +144,7 @@ } a { - padding: 7px 15px; + padding: 7px 12px; font-size: $gl-font-size; line-height: 24px; color: $gray; @@ -169,10 +169,12 @@ } .count { - float: right; - background: #eee; - padding: 0 8px; - @include border-radius(6px); + &:before { + content: '('; + } + &:after { + content: ')'; + } } &.back-link i { @@ -191,6 +193,27 @@ } } +.expand-nav a { + color: $gl-icon-color; + width: 60px; + position: fixed; + top: 0; + left: 0; + font-size: 20px; + background: #fff; + height: 59px; + text-align: center; + line-height: 59px; + border-bottom: 1px solid #eee; + transition-duration: .3s; + outline: none; + z-index: 100; + + &:hover { + text-decoration: none; + } +} + .collapse-nav a { width: $sidebar_width; position: fixed; @@ -210,55 +233,12 @@ } .page-sidebar-collapsed { - padding-left: $sidebar_collapsed_width; - .sidebar-wrapper { - width: $sidebar_collapsed_width; - - .header-logo { - width: $sidebar_collapsed_width; - - a { - padding-left: ($sidebar_collapsed_width - 36) / 2; - - .gitlab-text-container { - display: none; - } - } - } - - .nav-sidebar { - width: $sidebar_collapsed_width; - - li { - width: auto; - - a { - span { - display: none; - } - } - } - } - - .collapse-nav a { - width: $sidebar_collapsed_width; - } - - .sidebar-user { - padding-left: ($sidebar_collapsed_width - 36) / 2; - width: $sidebar_collapsed_width; - - .username { - display: none; - } - } + display: none; } } .page-sidebar-expanded { - padding-left: $sidebar_collapsed_width; - @media (min-width: $screen-md-min) { padding-left: $sidebar_width; } @@ -309,3 +289,48 @@ padding-right: $sidebar_collapsed_width; } } + +.complex-sidebar { + display: inline-block; + + .nav-primary { + width: 61px; + float: left; + height: 100vh; + + .nav-sidebar { + width: 60px; + + li a { + width: 60px; + + span { + display: none; + } + } + } + } + + .nav-secondary { + $nav-secondary-width: 168px; + + float: left; + width: $nav-secondary-width; + + .nav-sidebar { + width: $nav-secondary-width; + + li { + width: $nav-secondary-width; + + a { + width: $nav-secondary-width; + + i { + display: none; + } + } + } + } + } +} diff --git a/app/assets/stylesheets/framework/tw_bootstrap_variables.scss b/app/assets/stylesheets/framework/tw_bootstrap_variables.scss index f63ac033234..c72af5dad0a 100644 --- a/app/assets/stylesheets/framework/tw_bootstrap_variables.scss +++ b/app/assets/stylesheets/framework/tw_bootstrap_variables.scss @@ -56,8 +56,8 @@ $component-active-bg: $brand-info; //## $input-color: $text-color; -$input-border: #e7e9ed; -$input-border-focus: #7f8fa4; +$input-border: $border-color; +$input-border-focus: $focus-border-color; $legend-color: $text-color; diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss index b1886fbe67b..7b2aada5a0d 100644 --- a/app/assets/stylesheets/framework/typography.scss +++ b/app/assets/stylesheets/framework/typography.scss @@ -138,6 +138,12 @@ } } + a.no-attachment-icon { + &:before { + display: none; + } + } + /* Link to current header. */ h1, h2, h3, h4, h5, h6 { position: relative; @@ -244,7 +250,7 @@ a > code { * Textareas intended for GFM * */ -textarea.js-gfm-input { +.js-gfm-input { font-family: $monospace_font; color: $gl-text-color; } diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 61e0dd4d672..8d3ad934a50 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -11,6 +11,7 @@ $gutter_inner_width: 258px; * UI elements */ $border-color: #efeff1; +$focus-border-color: #3aabf0; $table-border-color: #eef0f2; $background-color: #faf9f9; @@ -26,6 +27,7 @@ $gl-text-orange: #d90; $gl-link-color: #3084bb; $gl-dark-link-color: #333; $gl-placeholder-color: #8f8f8f; +$gl-icon-color: $gl-placeholder-color; $gl-gray: $gl-text-color; $gl-header-color: $gl-title-color; @@ -66,7 +68,7 @@ $header-height: 58px; $fixed-layout-width: 1280px; $gl-avatar-size: 40px; $error-exclamation-point: #e62958; -$border-radius-default: 3px; +$border-radius-default: 2px; $btn-transparent-color: #8f8f8f; $ssh-key-icon-color: #8f8f8f; $ssh-key-icon-size: 18px; @@ -102,9 +104,9 @@ $orange-light: rgba(252, 109, 38, 0.80); $orange-normal: #e75e40; $orange-dark: #ce5237; -$red-light: #f06559; -$red-normal: #e52c5a; -$red-dark: #d22852; +$red-light: #e52c5a; +$red-normal: #d22852; +$red-dark: darken($red-normal, 5%); $border-white-light: #f1f2f4; $border-white-normal: #d6dae2; @@ -126,9 +128,9 @@ $border-orange-light: #fc6d26; $border-orange-normal: #ce5237; $border-orange-dark: #c14e35; -$border-red-light: #f24f41; -$border-red-normal: #d22852; -$border-red-dark: #ca264f; +$border-red-light: #d22852; +$border-red-normal: #ca264f; +$border-red-dark: darken($border-red-normal, 5%); $help-well-bg: #fafafa; $help-well-border: #e5e5e5; @@ -166,6 +168,8 @@ $regular_font: 'Source Sans Pro', "Helvetica Neue", Helvetica, Arial, sans-serif /* * Dropdowns */ +$dropdown-border-radius: 2px; +$dropdown-width: 300px; $dropdown-bg: #fff; $dropdown-link-color: #555; $dropdown-link-hover-bg: $row-hover; @@ -176,8 +180,8 @@ $dropdown-divider-color: rgba(#000, .1); $dropdown-header-color: #959494; $dropdown-title-btn-color: #bfbfbf; $dropdown-input-color: #555; -$dropdown-input-focus-border: rgb(58, 171, 240); -$dropdown-input-focus-shadow: rgba(#000, .2); +$dropdown-input-focus-border: $focus-border-color; +$dropdown-input-focus-shadow: rgba($dropdown-input-focus-border, .4); $dropdown-loading-bg: rgba(#fff, .6); $dropdown-toggle-bg: #fff; @@ -193,3 +197,29 @@ $dropdown-toggle-hover-icon-color: $dropdown-toggle-hover-border-color; $award-emoji-menu-bg: #fff; $award-emoji-menu-border: #f1f2f4; $award-emoji-new-btn-icon-color: #dcdcdc; + +/* + * Search Box + */ +$search-input-border-color: rgba(#4688f1, .8); +$search-input-focus-shadow-color: $dropdown-input-focus-shadow; +$search-input-width: 244px; +$location-badge-color: #aaa; +$location-badge-bg: $gray-normal; +$location-badge-active-bg: #4f91f8; +$location-icon-color: #e7e9ed; +$location-icon-active-color: #807e7e; + +/* + * Notes + */ +$notes-light-color: #8e8e8e; +$notes-action-color: #c3c3c3; +$notes-role-color: #8e8e8e; +$notes-role-border-color: #e4e4e4; + +$note-disabled-comment-color: #b2b2b2; +$note-form-border-color: #e5e5e5; +$note-toolbar-color: #959494; + +$zen-control-hover-color: #111; diff --git a/app/assets/stylesheets/framework/zen.scss b/app/assets/stylesheets/framework/zen.scss index 02e24ec7c4d..f870ea0d87f 100644 --- a/app/assets/stylesheets/framework/zen.scss +++ b/app/assets/stylesheets/framework/zen.scss @@ -1,61 +1,62 @@ -.zennable { - a.js-zen-enter { - color: $gl-gray; - position: absolute; +.zen-backdrop { + &.fullscreen { + background-color: white; + position: fixed; top: 0; - right: 4px; - line-height: 56px; - } + bottom: 0; + left: 0; + right: 0; + z-index: 1031; - a.js-zen-leave { - display: none; - color: $gl-text-color; - position: absolute; - top: 10px; - right: 10px; - padding: 5px; - font-size: 36px; + textarea { + border: none; + box-shadow: none; + border-radius: 0; + color: #000; + font-size: 20px; + line-height: 26px; + padding: 30px; + display: block; + outline: none; + resize: none; + height: 100vh; + max-width: 900px; + margin: 0 auto; + } - &:hover { - color: #111; + .zen-control-leave { + display: block; + position: absolute; + top: 0; } } +} - .zen-backdrop { - &.fullscreen { - background-color: white; - position: fixed; - top: 0; - bottom: 0; - left: 0; - right: 0; - z-index: 1031; +.zen-cotrol { + padding: 0; + color: #555; + background: none; + border: 0; +} - textarea { - border: none; - box-shadow: none; - border-radius: 0; - color: #000; - font-size: 20px; - line-height: 26px; - padding: 30px; - display: block; - outline: none; - resize: none; - height: 100vh; - max-width: 900px; - margin: 0 auto; - } +.zen-control-full { + color: $note-toolbar-color; - a.js-zen-enter { - display: none; - } + &:hover { + color: $gl-link-color; + text-decoration: none; + } +} - a.js-zen-leave { - display: block; - position: absolute; - top: 0; - } - } +.zen-control-leave { + display: none; + color: $gl-text-color; + position: absolute; + right: 10px; + padding: 5px; + font-size: 36px; + + &:hover { + color: $zen-control-hover-color; } } diff --git a/app/assets/stylesheets/pages/awards.scss b/app/assets/stylesheets/pages/awards.scss index 28994e60baa..37bf38fa65d 100644 --- a/app/assets/stylesheets/pages/awards.scss +++ b/app/assets/stylesheets/pages/awards.scss @@ -37,7 +37,7 @@ height: 300px; overflow-y: scroll; - input.emoji-search{ + input.emoji-search { background-image: url("data:image/png;base64,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"); background-repeat: no-repeat; background-position: right 5px center; diff --git a/app/assets/stylesheets/pages/ci_projects.scss b/app/assets/stylesheets/pages/ci_projects.scss index 2a7b5cfc7fd..67a9d7d2cf7 100644 --- a/app/assets/stylesheets/pages/ci_projects.scss +++ b/app/assets/stylesheets/pages/ci_projects.scss @@ -42,7 +42,7 @@ } } - .loading{ + .loading { font-size: 20px; } diff --git a/app/assets/stylesheets/pages/commit.scss b/app/assets/stylesheets/pages/commit.scss index 971656feb42..082911bd118 100644 --- a/app/assets/stylesheets/pages/commit.scss +++ b/app/assets/stylesheets/pages/commit.scss @@ -1,15 +1,15 @@ -.commit-title{ +.commit-title { display: block; } -.commit-author, .commit-committer{ +.commit-author, .commit-committer { display: block; color: #999; font-weight: normal; font-style: italic; } -.commit-author strong, .commit-committer strong{ +.commit-author strong, .commit-committer strong { font-weight: bold; font-style: normal; } @@ -74,7 +74,7 @@ color: $gl-text-red; } } - .edit-file{ + .edit-file { a { color: $gl-text-color; } diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss index b6011fe7679..8272615768d 100644 --- a/app/assets/stylesheets/pages/commits.scss +++ b/app/assets/stylesheets/pages/commits.scss @@ -1,4 +1,4 @@ -.commits-compare-switch{ +.commits-compare-switch { @include btn-default; @include btn-white; background: image-url("switch_icon.png") no-repeat center center; diff --git a/app/assets/stylesheets/pages/detail_page.scss b/app/assets/stylesheets/pages/detail_page.scss index d3eda1a57e6..5917f089720 100644 --- a/app/assets/stylesheets/pages/detail_page.scss +++ b/app/assets/stylesheets/pages/detail_page.scss @@ -33,8 +33,12 @@ .description { margin-top: 6px; - p:last-child { - margin-bottom: 0; + p { + overflow-x: auto; + + &:last-child { + margin-bottom: 0; + } } } } diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss index f1368d74b3b..939555bb260 100644 --- a/app/assets/stylesheets/pages/diff.scss +++ b/app/assets/stylesheets/pages/diff.scss @@ -59,9 +59,14 @@ border-collapse: separate; margin: 0; padding: 0; + .line_holder td { line-height: $code_line_height; font-size: $code_font_size; + + span { + white-space: pre; + } } } diff --git a/app/assets/stylesheets/pages/editor.scss b/app/assets/stylesheets/pages/editor.scss index 43be5e38ba8..0f0592a0ab8 100644 --- a/app/assets/stylesheets/pages/editor.scss +++ b/app/assets/stylesheets/pages/editor.scss @@ -1,5 +1,5 @@ .file-editor { - #editor{ + #editor { border: none; @include border-radius(0); height: 500px; diff --git a/app/assets/stylesheets/pages/events.scss b/app/assets/stylesheets/pages/events.scss index 84eefd01cfe..c66efe978cd 100644 --- a/app/assets/stylesheets/pages/events.scss +++ b/app/assets/stylesheets/pages/events.scss @@ -43,10 +43,6 @@ .md { color: #7f8fa4; font-size: $gl-font-size; - - iframe.twitter-share-button { - vertical-align: bottom; - } } pre { diff --git a/app/assets/stylesheets/pages/lint.scss b/app/assets/stylesheets/pages/lint.scss index 6d2bd33b28b..6926448519e 100644 --- a/app/assets/stylesheets/pages/lint.scss +++ b/app/assets/stylesheets/pages/lint.scss @@ -1,9 +1,9 @@ .ci-body { - .incorrect-syntax{ + .incorrect-syntax { font-size: 19px; color: red; } - .correct-syntax{ + .correct-syntax { font-size: 19px; color: #47a447; } diff --git a/app/assets/stylesheets/pages/login.scss b/app/assets/stylesheets/pages/login.scss index 777bcbca5c3..403171d4532 100644 --- a/app/assets/stylesheets/pages/login.scss +++ b/app/assets/stylesheets/pages/login.scss @@ -36,7 +36,7 @@ } } - .login-box{ + .login-box { background: #fafafa; border-radius: 10px; box-shadow: 0 0 2px #ccc; diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss index 7ff63ca20b6..1c6a4208974 100644 --- a/app/assets/stylesheets/pages/merge_requests.scss +++ b/app/assets/stylesheets/pages/merge_requests.scss @@ -195,42 +195,6 @@ line-height: 31px; } -.disabled-comment-area { - padding: 16px 0; - - .disabled-profile { - width: 40px; - height: 40px; - background: $border-gray-dark; - border-radius: 20px; - display: inline-block; - margin-right: 10px; - } - - .disabled-comment { - background: $gray-light; - display: inline-block; - vertical-align: top; - height: 200px; - border-radius: 4px; - border: 1px solid $border-gray-normal; - padding-top: 90px; - text-align: center; - right: 20px; - position: absolute; - left: 70px; - margin-bottom: 20px; - - span { - color: #b2b2b2; - - a { - color: $md-link-color; - } - } - } -} - .builds { .table-holder { overflow-x: scroll; diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss index 655f88b0c2c..a909776b437 100644 --- a/app/assets/stylesheets/pages/note_form.scss +++ b/app/assets/stylesheets/pages/note_form.scss @@ -1,10 +1,6 @@ /** * Note Form */ - -.comment-btn { - @extend .btn-create; -} .reply-btn { @extend .btn-primary; margin: 10px $gl-padding; @@ -17,16 +13,17 @@ } .diff-file, .discussion { - .new_note { + .new-note { margin: 0; border: none; } } -.new_note { + +.new-note { display: none; } -.new_note, .note-edit-form { +.new-note, .note-edit-form { .note-form-actions { margin-top: $gl-padding; } @@ -40,21 +37,18 @@ img { max-width: 100%; } +} - .note_text { - width: 100%; - } +.note-textarea { + padding: 10px 0; + font-family: $regular_font; + border: 0; - .comment-hints { - margin-top: -12px; + &:focus { + outline: 0; } } -/* loading indicator */ -.notes-busy { - margin: 18px; -} - .note-image-attach { @extend .col-md-4; margin-left: 45px; @@ -62,38 +56,29 @@ } .common-note-form { - margin: 0; - background: #fff; - padding: $gl-padding; - margin-left: -$gl-padding; - margin-right: -$gl-padding; - margin-bottom: -$gl-padding; -} - -.note-form-actions { - .note-form-option { - margin-top: 8px; - margin-left: 30px; - @extend .pull-left; - } - - .js-notify-commit-author { - float: left; - } - - .write-preview-btn { - // makes the "absolute" position for links relative to this - position: relative; - - // preview/edit buttons - > a { - position: absolute; - right: 5px; - top: 8px; + .md-area { + padding: $gl-padding-top $gl-padding; + border: 1px solid $note-form-border-color; + border-radius: $border-radius-base; + + &.is-focused { + border-color: $focus-border-color; + box-shadow: 0 0 2px rgba(#000, .2), + 0 0 4px rgba($focus-border-color, .4); + + .comment-toolbar, + .nav-links { + border-color: $focus-border-color; + } } } } +.discussion-form { + padding: $gl-padding-top $gl-padding; + background-color: #fff; +} + .note-edit-form { display: none; font-size: 15px; @@ -152,11 +137,49 @@ } } -.comment-hints { - color: #999; - background: #fff; - padding: 7px; - margin-top: -7px; - border: 1px solid $border-color; - font-size: 13px; +.comment-toolbar { + padding-top: $gl-padding-top; + color: $note-toolbar-color; + border-top: 1px solid $border-color; +} + +.toolbar-button { + padding: 0; + background: none; + border: 0; + font-size: 14px; + line-height: 16px; + + &:hover, + &:focus { + color: $gl-link-color; + outline: 0; + } + + @media (min-width: $screen-md-min) { + float: left; + margin-right: $gl-padding; + + &:last-child { + float: right; + margin-right: 0; + } + } +} + +.toolbar-button-icon { + position: relative; + top: 1px; + margin-right: 3px; + color: inherit; + font-size: 16px; +} + +.toolbar-text { + font-size: 14px; + line-height: 16px; + + @media (min-width: $screen-md-min) { + float: left; + } } diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index 4bd2016bdcf..aca86457c70 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -20,9 +20,15 @@ ul.notes { .timeline-content { margin-left: 55px; + + &.timeline-content-form { + @media (max-width: $screen-sm-max) { + margin-left: 0; + } + } } - .note_created_ago, .note-updated-at { + .note-created-ago, .note-updated-at { white-space: nowrap; } @@ -39,53 +45,6 @@ ul.notes { } } - .discussion-header, - .note-header { - @extend .cgray; - - a:hover { - text-decoration: none; - } - - .avatar { - float: left; - margin-right: 10px; - } - - .discussion-last-update, - .note-last-update { - &:before { - content: "\00b7"; - } - - a { - color: $gl-gray; - - &:hover { - text-decoration: underline; - } - } - } - .author { - color: #4c4e54; - margin-right: 3px; - - &:hover { - color: $gl-link-color; - } - } - .author-username { - } - - .note-role { - float: right; - margin-top: 1px; - border: 1px solid #bbb; - background-color: transparent; - color: $gl-gray; - } - } - .discussion-body { padding-top: 15px; } @@ -123,7 +82,7 @@ ul.notes { // On diffs code should wrap nicely and not overflow pre { code { - white-space: pre-wrap; + white-space: pre; } } @@ -196,42 +155,90 @@ ul.notes { &.notes_content { background-color: #fff; border-width: 1px 0; - padding-top: 0; + padding: 0; vertical-align: top; - &.parallel{ + &.parallel { border-width: 1px; } } } } +.discussion-header, +.note-header { + a { + color: inherit; + + &:hover { + color: $gl-link-color; + text-decoration: none; + } + } + + .author_link { + font-weight: 600; + } +} + +.note-headline-light, +.discussion-headline-light { + color: $notes-light-color; +} + /** * Actions for Discussions/Notes */ -.discussion, -.note { - .discussion-actions, - .note-actions { - float: right; - margin-left: 10px; +.discussion-actions, +.note-actions { + float: right; + margin-left: 10px; + color: $notes-action-color; +} - a { - margin-left: 5px; - color: $gl-gray; +.note-action-button, +.discussion-action-button { + display: inline-block; + margin-left: 10px; + line-height: 24px; - i.fa { - font-size: 16px; - line-height: 16px; - } + .fa { + position: relative; + top: 1px; + font-size: 17px; + } - &:hover { - @extend .cgray; - &.danger { @extend .cred; } - } - } + .fa-trash-o { + top: 0; + font-size: 16px; } } + +.discussion-toggle-button { + line-height: 20px; + font-size: 13px; + + .fa { + margin-right: 3px; + font-size: 10px; + line-height: 18px; + vertical-align: top; + } +} + +.note-role { + position: relative; + top: -2px; + display: inline-block; + padding-left: 4px; + padding-right: 4px; + color: $notes-role-color; + font-size: 12px; + line-height: 20px; + border: 1px solid $notes-role-border-color; + border-radius: $border-radius-base; +} + .diff-file .note .note-actions { right: 0; top: 0; @@ -280,3 +287,21 @@ ul.notes { } } } + +.disabled-comment { + margin-left: -$gl-padding-top; + margin-right: -$gl-padding-top; + background-color: $gray-light; + border-radius: $border-radius-base; + border: 1px solid $border-gray-normal; + color: $note-disabled-comment-color; + line-height: 200px; + + .disabled-comment-text { + line-height: normal; + } + + a { + color: $gl-link-color; + } +} diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index 4e6aa8cd1a6..fcca9d4faf5 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -315,7 +315,7 @@ pre.light-well { } .git-empty { - margin: 0 7px; + margin: 0 7px 7px; h5 { color: #5c5d5e; @@ -401,7 +401,7 @@ pre.light-well { } .commit_short_id { - margin-right: 5px; + margin: 0 5px; color: $gl-link-color; font-weight: 600; } diff --git a/app/assets/stylesheets/pages/search.scss b/app/assets/stylesheets/pages/search.scss index b6e45024644..f0f3744c6fa 100644 --- a/app/assets/stylesheets/pages/search.scss +++ b/app/assets/stylesheets/pages/search.scss @@ -21,3 +21,145 @@ } } +.search { + margin-right: 10px; + margin-left: 10px; + margin-top: ($header-height - 35) / 2; + + form { + @extend .form-control; + margin: 0; + padding: 4px; + width: $search-input-width; + line-height: 24px; + } + + .location-text { + font-style: normal; + } + + .search-input { + border: none; + font-size: 14px; + outline: none; + padding: 0; + margin-left: 5px; + line-height: 25px; + width: 98%; + } + + .location-badge { + line-height: 25px; + padding: 0 5px; + border-radius: $border-radius-default; + font-size: 14px; + font-style: normal; + color: $location-badge-color; + display: inline-block; + background-color: $location-badge-bg; + vertical-align: top; + } + + .search-input-container { + display: -webkit-flex; + display: flex; + position: relative; + } + + .search-location-badge, .search-input-wrap { + // Fallback if flexbox is not supported + display: inline-block; + } + + .search-input-wrap { + width: 100%; + + .search-icon, .clear-icon { + position: absolute; + right: 5px; + top: 0; + color: $location-icon-color; + + &:before { + font-family: FontAwesome; + font-weight: normal; + font-style: normal; + } + } + + .search-icon { + @extend .fa-search; + @include transition(color .15s); + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + } + + .clear-icon { + @extend .fa-times; + display: none; + } + + // Rewrite position. Dropdown menu should be relative to .search-input-container + .dropdown { + position: static; + } + + .dropdown-header { + text-transform: uppercase; + font-size: 11px; + } + + // Custom dropdown positioning + .dropdown-menu { + top: 30px; + left: -5px; + padding: 0; + + ul { + padding: 10px 0; + } + } + + .dropdown-content { + max-height: 350px; + } + } + + &.search-active { + form { + @extend .form-control:focus; + border-color: $dropdown-input-focus-border; + box-shadow: 0 0 4px $search-input-focus-shadow-color; + } + + .location-badge { + @include transition(all .15s); + background-color: $location-badge-active-bg; + color: $white-light; + } + + .search-input-wrap { + i { + color: $location-icon-active-color; + } + } + } + + &.has-value { + .search-icon { + display: none; + } + + .clear-icon { + cursor: pointer; + display: block; + } + } + + &.has-location-badge { + .search-input-wrap { + width: 78%; + } + } +} diff --git a/app/assets/stylesheets/pages/status.scss b/app/assets/stylesheets/pages/status.scss index 5e5e38a0ba6..dbb6daf0d70 100644 --- a/app/assets/stylesheets/pages/status.scss +++ b/app/assets/stylesheets/pages/status.scss @@ -1,4 +1,4 @@ -.container-fluid .content { +.container-fluid { .ci-status { padding: 2px 7px; margin-right: 5px; diff --git a/app/assets/stylesheets/pages/todos.scss b/app/assets/stylesheets/pages/todos.scss index e909e15f74c..e83fa9e3d52 100644 --- a/app/assets/stylesheets/pages/todos.scss +++ b/app/assets/stylesheets/pages/todos.scss @@ -6,7 +6,7 @@ .navbar-nav { li { .badge.todos-pending-count { - background-color: #7f8fa4; + background-color: $gl-icon-color; margin-top: -5px; font-weight: normal; } |