Commit bf82662f authored by Robert Speicher's avatar Robert Speicher

Merge branch '224534-replace-fa-times-with-gitlab-svg-close-icon-dropdowns' into 'master'

Replace fa-times with GitLab SVG close icon - Dropdowns

See merge request gitlab-org/gitlab!40585
parents 78ee3a12 d555479e
......@@ -101,12 +101,12 @@ export default {
@keydown.esc.native="$emit('hide-dropdown')"
@hide="$emit('hide-dropdown')"
>
<div v-if="isSidebar" class="dropdown-title text-center">
<span class="alert-title">{{ s__('AlertManagement|Assign status') }}</span>
<div v-if="isSidebar" class="dropdown-title gl-display-flex">
<span class="alert-title gl-ml-auto">{{ s__('AlertManagement|Assign status') }}</span>
<gl-button
:aria-label="__('Close')"
variant="link"
class="dropdown-title-button dropdown-menu-close"
class="dropdown-title-button dropdown-menu-close gl-ml-auto gl-text-black-normal!"
icon="close"
@click="$emit('hide-dropdown')"
/>
......
......@@ -225,12 +225,12 @@ export default {
@keydown.esc.native="hideDropdown"
@hide="hideDropdown"
>
<div class="dropdown-title">
<span class="alert-title">{{ __('Assign To') }}</span>
<div class="dropdown-title gl-display-flex">
<span class="alert-title gl-ml-auto">{{ __('Assign To') }}</span>
<gl-button
:aria-label="__('Close')"
variant="link"
class="dropdown-title-button dropdown-menu-close"
class="dropdown-title-button dropdown-menu-close gl-ml-auto gl-text-black-normal!"
icon="close"
@click="hideDropdown"
/>
......
<script>
import { mapActions, mapGetters, mapState } from 'vuex';
import { GlLoadingIcon, GlButton, GlIcon } from '@gitlab/ui';
import { GlButton, GlLoadingIcon, GlIcon } from '@gitlab/ui';
import { sprintf, n__ } from '~/locale';
import DraftsCount from './drafts_count.vue';
import PublishButton from './publish_button.vue';
......@@ -8,8 +8,8 @@ import PreviewItem from './preview_item.vue';
export default {
components: {
GlLoadingIcon,
GlButton,
GlLoadingIcon,
GlIcon,
DraftsCount,
PublishButton,
......@@ -81,16 +81,17 @@ export default {
show: showPreviewDropdown,
}"
>
<div class="dropdown-title">
{{ dropdownTitle }}
<button
<div class="dropdown-title gl-display-flex gl-align-items-center">
<span class="gl-ml-auto">{{ dropdownTitle }}</span>
<gl-button
:aria-label="__('Close')"
type="button"
class="dropdown-title-button dropdown-menu-close"
category="tertiary"
size="small"
class="dropdown-title-button gl-ml-auto gl-p-0!"
icon="close"
@click="toggleReviewDropdown"
>
<gl-icon name="close" />
</button>
/>
</div>
<div class="dropdown-content">
<ul v-if="isNotesFetched">
......
<script>
/* eslint-disable @gitlab/vue-require-i18n-strings */
import $ from 'jquery';
import { GlIcon } from '@gitlab/ui';
import IssuableTemplateSelectors from '../../../templates/issuable_template_selectors';
export default {
components: {
GlIcon,
},
props: {
formState: {
type: Object,
......@@ -61,14 +65,14 @@ export default {
<i aria-hidden="true" class="fa fa-chevron-down"> </i>
</button>
<div class="dropdown-menu dropdown-select">
<div class="dropdown-title">
Choose a template
<div class="dropdown-title gl-display-flex gl-justify-content-center">
<span class="gl-ml-auto">Choose a template</span>
<button
class="dropdown-title-button dropdown-menu-close"
class="dropdown-title-button dropdown-menu-close gl-ml-auto"
:aria-label="__('Close')"
type="button"
>
<i aria-hidden="true" class="fa fa-times dropdown-menu-close-icon"> </i>
<gl-icon name="close" class="dropdown-menu-close-icon" :aria-hidden="true" />
</button>
</div>
<div class="dropdown-input">
......@@ -79,12 +83,11 @@ export default {
autocomplete="off"
/>
<i aria-hidden="true" class="fa fa-search dropdown-input-search"> </i>
<i
role="button"
<gl-icon
name="close"
class="dropdown-input-clear js-dropdown-input-clear"
:aria-label="__('Clear templates search input')"
class="fa fa-times dropdown-input-clear js-dropdown-input-clear"
>
</i>
/>
</div>
<div class="dropdown-content"></div>
<div class="dropdown-footer">
......
......@@ -41,12 +41,5 @@ export default {
autocomplete="off"
/>
<i class="fa fa-search dropdown-input-search" aria-hidden="true" data-hidden="true"> </i>
<i
class="fa fa-times dropdown-input-clear js-dropdown-input-clear"
aria-hidden="true"
data-hidden="true"
role="button"
>
</i>
</div>
</template>
<script>
export default {};
import { GlIcon } from '@gitlab/ui';
export default {
components: {
GlIcon,
},
};
</script>
<template>
<div class="dropdown-title">
<span>{{ __('Assign labels') }}</span>
<div class="dropdown-title gl-display-flex gl-justify-content-center">
<span class="gl-ml-auto">{{ __('Assign labels') }}</span>
<button
:aria-label="__('Close')"
type="button"
class="dropdown-title-button dropdown-menu-close"
class="dropdown-title-button dropdown-menu-close gl-ml-auto"
>
<i aria-hidden="true" class="fa fa-times dropdown-menu-close-icon" data-hidden="true"> </i>
<gl-icon name="close" aria-hidden="true" class="dropdown-menu-close-icon" />
</button>
</div>
</template>
......@@ -596,8 +596,6 @@
}
.dropdown-title-button {
position: absolute;
top: 0;
padding: 0;
color: $dropdown-title-btn-color;
border: 0;
......@@ -609,17 +607,6 @@
}
}
.dropdown-menu-close {
top: $gl-padding-6;
right: $gl-padding-8;
width: 20px;
height: 20px;
}
.dropdown-menu-close-icon {
vertical-align: middle;
}
.dropdown-menu-back {
left: 10px;
top: $gl-padding-8;
......@@ -632,6 +619,7 @@
.fa,
.input-icon,
.dropdown-input-clear,
.dropdown-input-search {
position: absolute;
top: $gl-padding-8;
......@@ -682,13 +670,15 @@
border-color: $blue-300;
box-shadow: 0 0 4px $dropdown-input-focus-shadow;
~ .fa {
~ .fa,
~ .dropdown-input-clear {
color: $gray-700;
}
}
&:hover {
~ .fa {
~ .fa,
~ .dropdown-input-clear {
color: $gray-700;
}
}
......
......@@ -62,20 +62,37 @@ module DropdownsHelper
end
def dropdown_title(title, options: {})
content_tag :div, class: "dropdown-title" do
has_back = options.fetch(:back, false)
has_close = options.fetch(:close, true)
container_class = %w[dropdown-title gl-display-flex]
margin_class = []
if has_back && has_close
container_class << 'gl-justify-content-space-between'
elsif has_back
margin_class << 'gl-mr-auto'
elsif has_close
margin_class << 'gl-ml-auto'
end
container_class = container_class.join(' ')
margin_class = margin_class.join(' ')
content_tag :div, class: container_class do
title_output = []
if options.fetch(:back, false)
title_output << content_tag(:button, class: "dropdown-title-button dropdown-menu-back", aria: { label: "Go back" }, type: "button") do
if has_back
title_output << content_tag(:button, class: "dropdown-title-button dropdown-menu-back " + margin_class, aria: { label: "Go back" }, type: "button") do
sprite_icon('arrow-left')
end
end
title_output << content_tag(:span, title)
title_output << content_tag(:span, title, class: margin_class)
if options.fetch(:close, true)
title_output << content_tag(:button, class: "dropdown-title-button dropdown-menu-close", aria: { label: "Close" }, type: "button") do
sprite_icon('close', css_class: 'dropdown-menu-close-icon')
if has_close
title_output << content_tag(:button, class: "dropdown-title-button dropdown-menu-close " + margin_class, aria: { label: "Close" }, type: "button") do
sprite_icon('close', size: 16, css_class: 'dropdown-menu-close-icon')
end
end
......@@ -83,20 +100,11 @@ module DropdownsHelper
end
end
def dropdown_input(placeholder, input_id: nil)
content_tag :div, class: "dropdown-input" do
filter_output = text_field_tag input_id, nil, class: "dropdown-input-field dropdown-no-filter", placeholder: placeholder, autocomplete: 'off'
filter_output << icon('times', class: "dropdown-input-clear js-dropdown-input-clear", role: "button")
filter_output.html_safe
end
end
def dropdown_filter(placeholder, search_id: nil)
content_tag :div, class: "dropdown-input" do
filter_output = search_field_tag search_id, nil, class: "dropdown-input-field qa-dropdown-input-field", placeholder: placeholder, autocomplete: 'off'
filter_output << icon('search', class: "dropdown-input-search")
filter_output << icon('times', class: "dropdown-input-clear js-dropdown-input-clear", role: "button")
filter_output << sprite_icon('close', size: 16, css_class: 'dropdown-input-clear js-dropdown-input-clear')
filter_output.html_safe
end
......
......@@ -10,10 +10,11 @@
= issuable.issue_type.capitalize || _("Select type")
= icon('chevron-down')
.dropdown-menu.dropdown-menu-selectable.dropdown-select
.dropdown-title
= _("Select type")
%button.dropdown-title-button.dropdown-menu-close.gl-mt-3
= icon('times', class: 'dropdown-menu-close-icon', 'aria-hidden' => 'true')
.dropdown-title.gl-display-flex
%span.gl-ml-auto
= _("Select type")
%button.dropdown-title-button.dropdown-menu-close.gl-ml-auto{ "aria-label" => _('Close') }
= sprite_icon('close', size: 16, css_class: 'dropdown-menu-close-icon')
.dropdown-content
%ul
%li.js-filter-issuable-type
......
---
title: Replace fa-times with GitLab SVG close icon in dropdowns
merge_request: 40585
author:
type: performance
......@@ -93,12 +93,12 @@ export default {
@keydown.esc.native="hideDropdown"
@hide="hideDropdown"
>
<div class="dropdown-title">
<span class="health-title">{{ s__('Sidebar|Assign health status') }}</span>
<div class="dropdown-title gl-display-flex">
<span class="health-title gl-ml-auto">{{ s__('Sidebar|Assign health status') }}</span>
<gl-button
:aria-label="__('Close')"
variant="link"
class="dropdown-title-button dropdown-menu-close"
class="dropdown-title-button dropdown-menu-close gl-ml-auto gl-text-gray-200!"
icon="close"
@click="hideDropdown"
/>
......
......@@ -173,12 +173,12 @@ export default {
@keydown.esc.native="hideDropdown"
@hide="hideDropdown"
>
<div class="dropdown-title">
<span class="health-title">{{ s__('Sidebar|Assign health status') }}</span>
<div class="dropdown-title gl-display-flex">
<span class="health-title gl-ml-auto">{{ s__('Sidebar|Assign health status') }}</span>
<gl-button
:aria-label="__('Close')"
variant="link"
class="dropdown-title-button dropdown-menu-close"
class="dropdown-title-button dropdown-menu-close gl-ml-auto gl-text-gray-200!"
icon="close"
@click="hideDropdown"
/>
......
......@@ -9,12 +9,13 @@ export default {
</script>
<template>
<div class="dropdown-title">
<span>{{ __('Assign epic') }}</span>
<div class="dropdown-title gl-display-flex gl-align-items-center">
<span class="gl-ml-auto">{{ __('Assign epic') }}</span>
<gl-button
:aria-label="__('Close')"
category="tertiary"
class="dropdown-title-button dropdown-menu-close"
class="dropdown-title-button dropdown-menu-close gl-ml-auto"
size="small"
icon="close"
/>
</div>
......
<script>
import { debounce } from 'lodash';
import { GlDeprecatedButton, GlIcon } from '@gitlab/ui';
import { GlButton, GlIcon } from '@gitlab/ui';
import autofocusonshow from '~/vue_shared/directives/autofocusonshow';
export default {
components: {
GlDeprecatedButton,
GlButton,
GlIcon,
},
directives: {
......@@ -40,9 +40,10 @@ export default {
@keyup="handleKeyUp"
/>
<gl-icon v-show="!query" name="search" />
<gl-deprecated-button
<gl-button
variant="link"
class="fa fa-times dropdown-input-clear js-dropdown-input-clear"
icon="close"
class="dropdown-input-clear js-dropdown-input-clear"
data-hidden="true"
@click.stop="handleInputClear"
/>
......
......@@ -153,7 +153,6 @@
}
.dropdown-title {
margin: 0 -25px;
padding: 0;
overflow: initial;
border-bottom: 0;
......
......@@ -11,11 +11,11 @@
= _('Epic')
.dropdown
.dropdown-menu.promotion-issue-sidebar-message
.dropdown-title
%span
.dropdown-title.gl-display-flex
%span.gl-ml-auto
= _('Epic')
%button.dropdown-title-button.dropdown-menu-close{ "aria-label" => _('Close'), :type => "button" }
%i.fa.fa-times.dropdown-menu-close-icon{ "aria-hidden" => "true", "data-hidden" => "true" }
%button.dropdown-title-button.dropdown-menu-close.gl-ml-auto{ "aria-label" => _('Close'), :type => "button" }
= sprite_icon('close', size: 16, css_class: 'dropdown-menu-close-icon')
%div
%p
= s_('Promotions|Epics let you manage your portfolio of projects more efficiently and with less effort by tracking groups of issues that share a theme, across projects and milestones.')
......
......@@ -4,9 +4,9 @@
= _('to help your contributors communicate effectively!')
.dropdown.promotion-issue-template
.dropdown-menu.promotion-issue-template-message
.dropdown-title
.dropdown-title.gl-display-flex.gl-justify-content-end
%button.dropdown-title-button.dropdown-menu-close{ "aria-label" => "Close", :type => "button" }
%i.fa.fa-times.dropdown-menu-close-icon{ "aria-hidden" => "true", "data-hidden" => "true" }
= sprite_icon('close', size: 16, css_class: 'dropdown-menu-close-icon')
%div
%p
= _('Description templates allow you to define context-specific templates for issue and merge request description fields for your project.')
......
import { shallowMount } from '@vue/test-utils';
import { GlDeprecatedButton, GlIcon } from '@gitlab/ui';
import { GlButton, GlIcon } from '@gitlab/ui';
import DropdownSearchInput from 'ee/vue_shared/components/sidebar/epics_select/dropdown_search_input.vue';
const createComponent = () =>
......@@ -96,16 +96,11 @@ describe('EpicsSelect', () => {
});
it('should render input clear button', () => {
const clearButtonEl = wrapper.find(GlDeprecatedButton);
const clearButtonEl = wrapper.find(GlButton);
expect(clearButtonEl.exists()).toBe(true);
expect(clearButtonEl.classes()).toEqual(
expect.arrayContaining([
'fa',
'fa-times',
'dropdown-input-clear',
'js-dropdown-input-clear',
]),
expect.arrayContaining(['dropdown-input-clear', 'js-dropdown-input-clear']),
);
});
});
......
<div>
<div class="dropdown inline">
<button class="dropdown-menu-toggle" data-toggle="dropdown" id="js-project-dropdown" type="button">
<div class="dropdown-toggle-text">
Projects
</div>
<i class="fa fa-chevron-down dropdown-toggle-caret js-projects-dropdown-toggle"></i>
</button>
<div class="dropdown-menu dropdown-select dropdown-menu-selectable">
<div class="dropdown-title">
<span>Go to project</span>
<button aria="{:label=&gt;&quot;Close&quot;}" class="dropdown-title-button dropdown-menu-close">
<i class="fa fa-times dropdown-menu-close-icon"></i>
</button>
</div>
<div class="dropdown-input">
<input class="dropdown-input-field" placeholder="Filter results" type="search">
<i class="fa fa-search dropdown-input-search"></i>
</div>
<div class="dropdown-content"></div>
<div class="dropdown-loading">
<i class="fa fa-spinner fa-spin"></i>
</div>
</div>
</div>
<div class="dropdown inline">
<button
class="dropdown-menu-toggle"
data-toggle="dropdown"
id="js-project-dropdown"
type="button"
>
<div class="dropdown-toggle-text">
Projects
</div>
<i class="fa fa-chevron-down dropdown-toggle-caret js-projects-dropdown-toggle"></i>
</button>
<div class="dropdown-menu dropdown-select dropdown-menu-selectable">
<div class="dropdown-title gl-display-flex gl-align-items-center">
<span class="gl-ml-auto">Go to project</span>
<button
aria-label="Close"
type="button"
class="btn dropdown-title-button dropdown-menu-close gl-ml-auto btn-default btn-sm gl-button btn-default-tertiary btn-icon"
>
<svg data-testid="close-icon" class="gl-icon s16 dropdown-menu-close-icon">
<use
href="/assets/icons-795a2ef2fd636a0538bbef3b8d2787dd90927b42d7617fdda8620930016b333d.svg#close"
></use>
</svg>
</button>
</div>
<div class="dropdown-input">
<input class="dropdown-input-field" placeholder="Filter results" type="search" />
<i class="fa fa-search dropdown-input-search"></i>
</div>
<div class="dropdown-content"></div>
<div class="dropdown-loading">
<i class="fa fa-spinner fa-spin"></i>
</div>
</div>
</div>
</div>
......@@ -32,12 +32,6 @@ describe('DropdownSearchInputComponent', () => {
expect(wrapper.find('.fa-search.dropdown-input-search').exists()).toBe(true);
});
it('renders clear search icon element', () => {
expect(wrapper.find('.fa-times.dropdown-input-clear.js-dropdown-input-clear').exists()).toBe(
true,
);
});
it('displays custom placeholder text', () => {
expect(findInputEl().attributes('placeholder')).toBe(defaultProps.placeholderText);
});
......
......@@ -33,7 +33,7 @@ describe('DropdownHeaderComponent', () => {
);
expect(closeBtnEl).not.toBeNull();
expect(closeBtnEl.querySelector('.fa-times.dropdown-menu-close-icon')).not.toBeNull();
expect(closeBtnEl.querySelector('.dropdown-menu-close-icon')).not.toBeNull();
});
});
});
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe DropdownsHelper do
before do
allow(helper).to receive(:sprite_icon).and_return('<span class="icon"></span>'.html_safe)
allow(helper).to receive(:icon).and_return('<span class="icon"></span>'.html_safe)
end
shared_examples 'has two icons' do
it 'returns two icons' do
expect(content.scan('icon').count).to eq(2)
end
end
describe '#dropdown_tag' do
let(:content) { helper.dropdown_tag('toggle', options: { wrapper_class: 'fuz' }) { 'fizzbuzz' } }
it 'returns the container in the content' do
expect(content).to include('dropdown fuz')
end
it 'returns the block in the content' do
expect(content).to include('fizzbuzz')
end
end
describe '#dropdown_toggle' do
let(:content) { helper.dropdown_toggle('foo', { default_label: 'foo' }, { toggle_class: 'fuz' }) }
it 'returns the button' do
expect(content).to include('dropdown-menu-toggle fuz')
end
it 'returns the buttons default label data attribute' do
expect(content).to include('data-default-label="foo"')
end
it 'returns the dropdown toggle text', :aggregate_failures do
expect(content).to include('dropdown-toggle-text is-default')
expect(content).to include('foo')
end
it 'returns the button icon in the content' do
expect(content.scan('icon').count).to eq(1)
end
end
describe '#dropdown_toggle_link' do
let(:content) { dropdown_toggle_link('foo', { data: 'bar' }, { toggle_class: 'fuz' }) }
it 'returns the link' do
expect(content).to include('dropdown-toggle-text fuz')
end
it 'returns the links data attribute' do
expect(content).to include('data-data="bar"')
end
it 'returns the link text' do
expect(content).to include('foo')
end
end
describe '#dropdown_title' do
shared_examples 'has a back button' do
it 'contains the back button' do
expect(content).to include('dropdown-title-button dropdown-menu-back')
end
end
shared_examples 'does not have a back button' do
it 'does not contain the back button' do
expect(content).not_to include('dropdown-title-button dropdown-menu-back')
end
end
shared_examples 'does not apply the margin class to the back button' do
it 'does not contain the back button margin class' do
expect(content).not_to include('dropdown-title-button dropdown-menu-back gl-mr-auto')
end
end
shared_examples 'has a close button' do
it 'contains the close button' do
expect(content).to include('dropdown-title-button dropdown-menu-close')
end
end
shared_examples 'does not have a close button' do
it 'does not contain the close button' do
expect(content).not_to include('dropdown-title-button dropdown-menu-close')
end
end
shared_examples 'does not apply the margin class to the close button' do
it 'does not contain the close button margin class' do
expect(content).not_to include('dropdown-title-button dropdown-menu-close gl-ml-auto')
end
end
shared_examples 'has the title text' do
it 'contains the title text' do
expect(content).to include('Foo')
end
end
shared_examples 'has the title margin class' do |margin_class: ''|
it 'contains the title margin class' do
expect(content).to match(/class="#{margin_class}.*"[^>]*>Foo/)
end
end
shared_examples 'does not have the title margin class' do
it 'does not have the title margin class' do
expect(content).not_to match(/class="gl-m[r|l]-auto.*"[^>]*>Foo/)
end
end
context 'with a back and close button' do
let(:content) { helper.dropdown_title('Foo', options: { back: true, close: true }) }
it 'applies the justification class to the container', :aggregate_failures do
expect(content).to match(/"dropdown-title.*gl-justify-content-space-between"/)
end
it_behaves_like 'has a back button'
it_behaves_like 'has the title text'
it_behaves_like 'has a close button'
it_behaves_like 'has two icons'
it_behaves_like 'does not have the title margin class'
end
context 'with a back button' do
let(:content) { helper.dropdown_title('Foo', options: { back: true, close: false }) }
it_behaves_like 'has a back button'
it_behaves_like 'has the title text'
it_behaves_like 'has the title margin class', margin_class: 'gl-mr-auto'
it_behaves_like 'does not have a close button'
it 'returns the back button icon' do
expect(content.scan('icon').count).to eq(1)
end
end
context 'with a close button' do
let(:content) { helper.dropdown_title('Foo', options: { back: false, close: true }) }
it_behaves_like 'does not have a back button'
it_behaves_like 'has the title text'
it_behaves_like 'has the title margin class', margin_class: 'gl-ml-auto'
it_behaves_like 'has a close button'
it 'returns the close button icon' do
expect(content.scan('icon').count).to eq(1)
end
end
context 'without any buttons' do
let(:content) { helper.dropdown_title('Foo', options: { back: false, close: false }) }
it_behaves_like 'does not have a back button'
it_behaves_like 'has the title text'
it_behaves_like 'does not have the title margin class'
it_behaves_like 'does not have a close button'
it 'returns no button icons' do
expect(content.scan('icon').count).to eq(0)
end
end
end
describe '#dropdown_filter' do
let(:content) { helper.dropdown_filter('foo') }
it_behaves_like 'has two icons'
it 'returns the container' do
expect(content).to include('dropdown-input')
end
it 'returns the search input', :aggregate_failures do
expect(content).to include('dropdown-input-field')
expect(content).to include('placeholder="foo"')
end
end
describe '#dropdown_content' do
shared_examples 'contains the container' do
it 'returns the container in the content' do
expect(content).to include('dropdown-content')
end
end
context 'without block' do
let(:content) { helper.dropdown_content }
it_behaves_like 'contains the container'
end
context 'with block' do
let(:content) { helper.dropdown_content { 'foo' } }
it_behaves_like 'contains the container'
it 'returns the block in the content' do
expect(content).to include('foo')
end
end
end
describe '#dropdown_footer' do
shared_examples 'contains the content' do
it 'returns the container in the content' do
expect(content).to include('dropdown-footer')
end
it 'returns the block in the content' do
expect(content).to include('foo')
end
end
context 'without a content class' do
let(:content) { helper.dropdown_footer { 'foo' } }
it_behaves_like 'contains the content'
end
context 'without a content class' do
let(:content) { helper.dropdown_footer(add_content_class: true) { 'foo' } }
it_behaves_like 'contains the content'
it 'returns the footer in the content' do
expect(content).to include('dropdown-footer-content')
end
end
end
describe '#dropdown_loading' do
let(:content) { helper.dropdown_loading }
it 'returns the container in the content' do
expect(content).to include('dropdown-loading')
end
it 'returns an icon in the content' do
expect(content.scan('icon').count).to eq(1)
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment