Tags redesign in edit-task modal (#9122)

* Truncate tags list to maximum number of tasks

This commit truncates the list of tags in the edit task modal and
displays the remaining selected tasks as a number.

* Align tags-select dropdown with "Tags" label

* Add tags popup component

* Use solid purple for tags-select dropdown

* Remove shadow when tags-select is active
* Add border-radius to tags-select
* Re-add previously disabled transitions
* Remove unused template element

* Add Clear Tags button to footer of tags popup

* Decrease column size for tags to better match design
* Truncate tag name to avoid overflows
* Add tag name as title to show full name on hover

* Grow inline tags select from left to right

* Style none button
* Add spacing to streak reset button to line up with tags select

* Add top offset to tags dropdown toggle to line up with label
This commit is contained in:
Michael Hibbs
2017-10-04 18:33:35 +01:00
committed by Sabe Jones
parent d977656e96
commit c4e5633e48
3 changed files with 215 additions and 20 deletions

View File

@@ -0,0 +1,107 @@
<template lang="pug">
.tags-popup
.tags-category.d-flex
.tags-header
strong(v-once) {{ $t('tags') }}
.tags-list.container
.row
.col-4(v-for="tag in tags")
label.custom-control.custom-checkbox
input.custom-control-input(type="checkbox", :value="tag.id", v-model="selectedTags")
span.custom-control-indicator
span.custom-control-description(:title='tag.name') {{tag.name}}
.tags-footer
span.clear-tags(@click="clearTags()") {{$t("clearTags")}}
</template>
<style lang="scss" scoped>
@import '~client/assets/scss/colors.scss';
.tags-popup {
padding-left: 24px;
padding-right: 24px;
max-width: 593px;
z-index: 9999;
background: $white;
border-radius: 2px;
box-shadow: 0 2px 2px 0 rgba($black, 0.16), 0 1px 4px 0 rgba($black, 0.12);
font-size: 14px;
line-height: 1.43;
text-overflow: ellipsis;
.tags-category {
border-bottom: 1px solid $gray-600;
padding-bottom: 24px;
padding-top: 24px;
}
.tags-header {
flex-basis: 96px;
flex-shrink: 0;
a {
font-size: 12px;
line-height: 1.33;
color: $blue-10;
margin-top: 4px;
&:focus, &:hover, &:active {
text-decoration: underline;
}
}
}
.tags-list {
.custom-control-description {
color: $gray-50 !important;
font-weight: normal;
overflow: hidden;
text-overflow: ellipsis;
white-space: pre;
width: 8em;
}
}
.tags-footer {
border-top: 1px solid $gray-600;
display: flex;
justify-content: center;
.clear-tags {
cursor: pointer;
margin: 1.1em 0;
color: $red-50;
font-size: 14px;
&:hover {
text-decoration: underline;
}
}
}
}
</style>
<script>
export default {
props: ['tags', 'value'],
data () {
return {
selectedTags: [],
};
},
watch: {
selectedTags () {
this.$emit('input', this.selectedTags);
},
},
mounted () {
this.selectedTags = this.value;
},
methods: {
clearTags () {
this.selectedTags = [];
},
},
};
</script>

View File

@@ -110,29 +110,22 @@
span.custom-control-indicator span.custom-control-indicator
span.custom-control-description {{ $t('dayOfWeek') }} span.custom-control-description {{ $t('dayOfWeek') }}
.option(v-if="isUserTask") .tags-select.option(v-if="isUserTask")
label(v-once) {{ $t('tags') }} .tags-inline
.category-wrap(@click="showTagsSelect = !showTagsSelect") label(v-once) {{ $t('tags') }}
span.category-select(v-if='task.tags && task.tags.length === 0') {{$t('none')}} .category-wrap(@click="showTagsSelect = !showTagsSelect", v-bind:class="{ active: showTagsSelect }")
span.category-select(v-else) span.category-select(v-if='task.tags && task.tags.length === 0')
.category-label(v-for='tagName in getTagsFor(task)') {{tagName}} .tags-none {{$t('none')}}
.category-box(v-if="showTagsSelect") .dropdown-toggle
.container span.category-select(v-else)
.row .category-label(v-for='tagName in truncatedSelectedTags', :title="tagName") {{ tagName }}
.form-check.col-6( .tags-more(v-if='remainingSelectedTags.length > 0') +{{ $t('more', { count: remainingSelectedTags.length }) }}
v-for="tag in user.tags", .dropdown-toggle
:key="tag.id", tags-popup(v-if="showTagsSelect", :tags="user.tags", v-model="task.tags")
)
label.custom-control.custom-checkbox
input.custom-control-input(type="checkbox", :value="tag.id", v-model="task.tags")
span.custom-control-indicator
span.custom-control-description(v-once) {{ tag.name }}
.row
button.btn.btn-primary(@click="showTagsSelect = !showTagsSelect") {{$t('close')}}
.option(v-if="task.type === 'habit'") .option(v-if="task.type === 'habit'")
label(v-once) {{ $t('resetStreak') }} label(v-once) {{ $t('resetStreak') }}
b-dropdown(:text="$t(task.frequency)") b-dropdown.streak-dropdown(:text="$t(task.frequency)")
b-dropdown-item(v-for="frequency in ['daily', 'weekly', 'monthly']", :key="frequency", @click="task.frequency = frequency", :class="{active: task.frequency === frequency}") b-dropdown-item(v-for="frequency in ['daily', 'weekly', 'monthly']", :key="frequency", @click="task.frequency = frequency", :class="{active: task.frequency === frequency}")
| {{ $t(frequency) }} | {{ $t(frequency) }}
@@ -328,6 +321,88 @@
} }
} }
.tags-select {
position: relative;
.tags-inline {
align-items: center;
display: flex;
justify-content: flex-start;
label {
margin: 0;
}
.category-wrap {
cursor: inherit;
position: relative;
border: 1px solid transparent;
border-radius: 2px;
margin-left: 4em;
&.active {
border-color: $purple-500;
.category-select {
box-shadow: none;
}
}
.category-select {
align-items: center;
display: flex;
padding: .6em;
padding-right: 2.8em;
width: 100%;
.tags-none {
margin: .26em 0 .26em .6em;
& + .dropdown-toggle {
right: 1.3em;
}
}
.tags-more {
color: #a5a1ac;
flex: 0 1 auto;
font-size: 12px;
text-align: left;
position: relative;
left: .5em;
width: 100%;
}
.dropdown-toggle {
position: absolute;
right: 1em;
top: .8em;
}
.category-label {
min-width: 68px;
overflow: hidden;
padding: .5em 1em;
text-overflow: ellipsis;
white-space: nowrap;
width: 68px;
word-wrap: break-word;
}
}
}
}
.tags-popup {
position: absolute;
top: 3.5em;
left: 6.2em;
}
}
.streak-dropdown {
margin-left: .5em;
}
.checklist-group { .checklist-group {
border-top: 1px solid $gray-500; border-top: 1px solid $gray-500;
} }
@@ -418,6 +493,7 @@
</style> </style>
<script> <script>
import TagsPopup from './tagsPopup';
import bModal from 'bootstrap-vue/lib/components/modal'; import bModal from 'bootstrap-vue/lib/components/modal';
import { mapGetters, mapActions, mapState } from 'client/libs/store'; import { mapGetters, mapActions, mapState } from 'client/libs/store';
import bDropdown from 'bootstrap-vue/lib/components/dropdown'; import bDropdown from 'bootstrap-vue/lib/components/dropdown';
@@ -441,6 +517,7 @@ import goldIcon from 'assets/svg/gold.svg';
export default { export default {
components: { components: {
TagsPopup,
bModal, bModal,
bDropdown, bDropdown,
bDropdownItem, bDropdownItem,
@@ -453,6 +530,7 @@ export default {
props: ['task', 'purpose', 'challengeId', 'groupId'], // purpose is either create or edit, task is the task created or edited props: ['task', 'purpose', 'challengeId', 'groupId'], // purpose is either create or edit, task is the task created or edited
data () { data () {
return { return {
maxTags: 3,
showTagsSelect: false, showTagsSelect: false,
showAssignedSelect: false, showAssignedSelect: false,
newChecklistItem: null, newChecklistItem: null,
@@ -574,6 +652,15 @@ export default {
} }
}, },
}, },
selectedTags () {
return this.getTagsFor(this.task);
},
truncatedSelectedTags () {
return this.selectedTags.slice(0, this.maxTags);
},
remainingSelectedTags () {
return this.selectedTags.slice(this.maxTags);
},
}, },
methods: { methods: {
...mapActions({saveTask: 'tasks:save', destroyTask: 'tasks:destroy', createTask: 'tasks:create'}), ...mapActions({saveTask: 'tasks:save', destroyTask: 'tasks:destroy', createTask: 'tasks:create'}),

View File

@@ -68,6 +68,7 @@
"subscriberItemText": "Each month, subscribers will receive a mystery item. This is usually released about one week before the end of the month. See the wiki's 'Mystery Item' page for more information.", "subscriberItemText": "Each month, subscribers will receive a mystery item. This is usually released about one week before the end of the month. See the wiki's 'Mystery Item' page for more information.",
"all": "All", "all": "All",
"none": "None", "none": "None",
"more": "<%= count %> more",
"and": "and", "and": "and",
"loginSuccess": "Login successful!", "loginSuccess": "Login successful!",
"youSure": "Are you sure?", "youSure": "Are you sure?",