Commit 24196763 authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch '38239-update-toggle-design' into 'master'

Update feature toggle design to use icons and make it i18n friendly

Closes #38239

See merge request gitlab-org/gitlab-ce!15904
parents 627a9687 d0edbf6d
<script>
import { s__ } from '../../locale';
import icon from './icon.vue';
import loadingIcon from './loading_icon.vue';
const ICON_ON = 'status_success_borderless';
const ICON_OFF = 'status_failed_borderless';
const LABEL_ON = s__('ToggleButton|Toggle Status: ON');
const LABEL_OFF = s__('ToggleButton|Toggle Status: OFF');
export default {
props: {
name: {
......@@ -22,19 +29,10 @@
required: false,
default: false,
},
enabledText: {
type: String,
required: false,
default: 'Enabled',
},
disabledText: {
type: String,
required: false,
default: 'Disabled',
},
},
components: {
icon,
loadingIcon,
},
......@@ -43,6 +41,15 @@
event: 'change',
},
computed: {
toggleIcon() {
return this.value ? ICON_ON : ICON_OFF;
},
ariaLabel() {
return this.value ? LABEL_ON : LABEL_OFF;
},
},
methods: {
toggleFeature() {
if (!this.disabledInput) this.$emit('change', !this.value);
......@@ -60,10 +67,8 @@
/>
<button
type="button"
aria-label="Toggle"
class="project-feature-toggle"
:data-enabled-text="enabledText"
:data-disabled-text="disabledText"
:aria-label="ariaLabel"
:class="{
'is-checked': value,
'is-disabled': disabledInput,
......@@ -72,6 +77,11 @@
@click="toggleFeature"
>
<loadingIcon class="loading-icon" />
<span class="toggle-icon">
<icon
css-classes="toggle-icon-svg"
:name="toggleIcon"/>
</span>
</button>
</label>
</template>
......@@ -27,7 +27,7 @@
border: 0;
outline: 0;
display: block;
width: 100px;
width: 50px;
height: 24px;
cursor: pointer;
user-select: none;
......@@ -42,31 +42,31 @@
background: none;
}
&::before {
color: $feature-toggle-text-color;
font-size: 12px;
line-height: 24px;
position: absolute;
top: 0;
left: 25px;
right: 5px;
text-align: center;
overflow: hidden;
text-overflow: ellipsis;
animation: animate-disabled .2s ease-in;
content: attr(data-disabled-text);
}
&::after {
.toggle-icon {
position: relative;
display: block;
content: "";
width: 22px;
height: 18px;
left: 0;
border-radius: 9px;
background: $feature-toggle-color;
transition: all .2s ease;
&,
.toggle-icon-svg {
width: 18px;
height: 18px;
}
.toggle-icon-svg {
fill: $feature-toggle-color-disabled;
}
.toggle-status-checked {
display: none;
}
.toggle-status-unchecked {
display: inline;
}
}
.loading-icon {
......@@ -77,11 +77,10 @@
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
&.is-loading {
&::before {
.toggle-icon {
display: none;
}
......@@ -100,15 +99,20 @@
&.is-checked {
background: $feature-toggle-color-enabled;
&::before {
left: 5px;
right: 25px;
animation: animate-enabled .2s ease-in;
content: attr(data-enabled-text);
}
.toggle-icon {
left: calc(100% - 18px);
&::after {
left: calc(100% - 22px);
.toggle-icon-svg {
fill: $feature-toggle-color-enabled;
}
.toggle-status-checked {
display: inline;
}
.toggle-status-unchecked {
display: none;
}
}
}
......
......@@ -16,7 +16,8 @@
class: "js-toggle-cluster-list project-feature-toggle #{'is-checked' if cluster.enabled?} #{'is-disabled' if !cluster.can_toggle_cluster?}",
"aria-label": s_("ClusterIntegration|Toggle Cluster"),
disabled: !cluster.can_toggle_cluster?,
data: { "enabled-text": s_("ClusterIntegration|Active"),
"disabled-text": s_("ClusterIntegration|Inactive"),
endpoint: namespace_project_cluster_path(@project.namespace, @project, cluster, format: :json) } }
data: { endpoint: namespace_project_cluster_path(@project.namespace, @project, cluster, format: :json) } }
= icon("spinner spin", class: "loading-icon")
%span.toggle-icon
= sprite_icon('status_success_borderless', size: 16, css_class: 'toggle-icon-svg toggle-status-checked')
= sprite_icon('status_failed_borderless', size: 16, css_class: 'toggle-icon-svg toggle-status-unchecked')
......@@ -7,8 +7,10 @@
%button{ type: 'button',
class: "js-toggle-cluster project-feature-toggle #{'is-checked' unless !@cluster.enabled?} #{'is-disabled' unless can?(current_user, :update_cluster, @cluster)}",
"aria-label": s_("ClusterIntegration|Toggle Cluster"),
disabled: !can?(current_user, :update_cluster, @cluster),
data: { "enabled-text": s_("ClusterIntegration|Active"), "disabled-text": s_("ClusterIntegration|Inactive"), } }
disabled: !can?(current_user, :update_cluster, @cluster) }
%span.toggle-icon
= sprite_icon('status_success_borderless', size: 16, css_class: 'toggle-icon-svg toggle-status-checked')
= sprite_icon('status_failed_borderless', size: 16, css_class: 'toggle-icon-svg toggle-status-unchecked')
- if can?(current_user, :update_cluster, @cluster)
.form-group
......
---
title: Update feature toggle design to use icons and make it i18n friendly
merge_request: 15904
author:
type: changed
......@@ -30,9 +30,9 @@ describe('Toggle Button', () => {
expect(vm.$el.querySelector('input').getAttribute('value')).toEqual('true');
});
it('renders Enabled and Disabled text data attributes', () => {
expect(vm.$el.querySelector('button').getAttribute('data-enabled-text')).toEqual('Enabled');
expect(vm.$el.querySelector('button').getAttribute('data-disabled-text')).toEqual('Disabled');
it('renders input status icon', () => {
expect(vm.$el.querySelectorAll('span.toggle-icon').length).toEqual(1);
expect(vm.$el.querySelectorAll('svg.s16.toggle-icon-svg').length).toEqual(1);
});
});
......@@ -49,6 +49,14 @@ describe('Toggle Button', () => {
expect(vm.$el.querySelector('button').classList.contains('is-checked')).toEqual(true);
});
it('sets aria-label representing toggle state', () => {
vm.value = true;
expect(vm.ariaLabel).toEqual('Toggle Status: ON');
vm.value = false;
expect(vm.ariaLabel).toEqual('Toggle Status: OFF');
});
it('emits change event when clicked', () => {
vm.$el.querySelector('button').click();
......
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