Add collapsing kanban buckets
This commit is contained in:
parent
304ba797a0
commit
ac6082a670
4 changed files with 81 additions and 8 deletions
30
src/helpers/saveCollapsedBucketState.js
Normal file
30
src/helpers/saveCollapsedBucketState.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
const key = 'collapsedBuckets'
|
||||
|
||||
const getAllState = () => {
|
||||
const saved = localStorage.getItem(key)
|
||||
if (saved === null) {
|
||||
return {}
|
||||
}
|
||||
|
||||
return JSON.parse(saved)
|
||||
}
|
||||
|
||||
export const saveCollapsedBucketState = (listId, collapsedBuckets) => {
|
||||
const state = getAllState()
|
||||
state[listId] = collapsedBuckets
|
||||
for (const bucketId in state[listId]) {
|
||||
if (!state[listId][bucketId]) {
|
||||
delete state[listId][bucketId]
|
||||
}
|
||||
}
|
||||
localStorage.setItem(key, JSON.stringify(state))
|
||||
}
|
||||
|
||||
export const getCollapsedBucketState = listId => {
|
||||
const state = getAllState()
|
||||
if (typeof state[listId] !== 'undefined') {
|
||||
return state[listId]
|
||||
}
|
||||
|
||||
return {}
|
||||
}
|
|
@ -243,7 +243,8 @@
|
|||
"deleteBucketText2": "This will not delete any tasks but move them into the default bucket.",
|
||||
"deleteBucketSuccess": "The bucket has been deleted successfully.",
|
||||
"bucketTitleSavedSuccess": "The bucket title has been saved successfully.",
|
||||
"bucketLimitSavedSuccess": "The bucket limit been saved successfully."
|
||||
"bucketLimitSavedSuccess": "The bucket limit been saved successfully.",
|
||||
"collapse": "Collapse this bucket"
|
||||
}
|
||||
},
|
||||
"namespace": {
|
||||
|
|
|
@ -2,6 +2,8 @@ $bucket-background: $grey-100;
|
|||
$task-background: $white;
|
||||
$ease-out: all .3s cubic-bezier(0.23, 1, 0.32, 1);
|
||||
$bucket-width: 300px;
|
||||
$bucket-header-height: 60px;
|
||||
$bucket-right-margin: 1rem;
|
||||
|
||||
$crazy-height-calculation: '100vh - 4.5rem - 1.5rem - 1rem - 1.5rem - 11px';
|
||||
$crazy-height-calculation-tasks: '#{$crazy-height-calculation} - 1rem - 2.5rem - 2rem - #{$button-height} - 1rem';
|
||||
|
@ -31,7 +33,7 @@ $filter-container-height: '1rem - #{$switch-view-height}';
|
|||
position: relative;
|
||||
|
||||
flex: 0 0 $bucket-width;
|
||||
margin: 0 1rem 0 0;
|
||||
margin: 0 $bucket-right-margin 0 0;
|
||||
max-height: 100%;
|
||||
min-height: 20px;
|
||||
max-width: $bucket-width;
|
||||
|
@ -233,6 +235,18 @@ $filter-container-height: '1rem - #{$switch-view-height}';
|
|||
a.dropdown-item {
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
&.is-collapsed {
|
||||
transform: rotate(90deg) translateX($bucket-width / 2 - $bucket-header-height / 2);
|
||||
// Using negative margins instead of translateY here to make all other buckets fill the empty space
|
||||
margin-left: ($bucket-width / 2 - $bucket-header-height / 2) * -1;
|
||||
margin-right: calc(#{($bucket-width / 2 - $bucket-header-height / 2) * -1} + #{$bucket-right-margin});
|
||||
cursor: pointer;
|
||||
|
||||
.tasks, .bucket-footer {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bucket-header {
|
||||
|
@ -240,6 +254,7 @@ $filter-container-height: '1rem - #{$switch-view-height}';
|
|||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: .5rem;
|
||||
height: $bucket-header-height;
|
||||
|
||||
.limit {
|
||||
padding-left: .5rem;
|
||||
|
|
|
@ -17,8 +17,13 @@
|
|||
/>
|
||||
</div>
|
||||
<div :class="{ 'is-loading': loading && !oneTaskUpdating}" class="kanban loader-container">
|
||||
<div :key="`bucket${bucket.id}`" class="bucket" v-for="bucket in buckets">
|
||||
<div class="bucket-header">
|
||||
<div
|
||||
:key="`bucket${bucket.id}`"
|
||||
class="bucket"
|
||||
:class="{'is-collapsed': collapsedBuckets[bucket.id]}"
|
||||
v-for="bucket in buckets"
|
||||
>
|
||||
<div class="bucket-header" @click="() => unCollapseBucket(bucket)">
|
||||
<span
|
||||
v-if="bucket.isDoneBucket"
|
||||
class="icon is-small has-text-success mr-2"
|
||||
|
@ -31,7 +36,7 @@
|
|||
@focusout="() => saveBucketTitle(bucket.id)"
|
||||
@keydown.enter.prevent.stop="() => saveBucketTitle(bucket.id)"
|
||||
class="title input"
|
||||
:contenteditable="canWrite"
|
||||
:contenteditable="canWrite && !collapsedBuckets[bucket.id]"
|
||||
spellcheck="false">{{ bucket.title }}</h2>
|
||||
<span
|
||||
:class="{'is-max': bucket.tasks.length >= bucket.limit}"
|
||||
|
@ -41,7 +46,7 @@
|
|||
</span>
|
||||
<dropdown
|
||||
class="is-right options"
|
||||
v-if="canWrite"
|
||||
v-if="canWrite && !collapsedBuckets[bucket.id]"
|
||||
trigger-icon="ellipsis-v"
|
||||
@close="() => showSetLimitInput = false"
|
||||
>
|
||||
|
@ -77,7 +82,7 @@
|
|||
</template>
|
||||
</a>
|
||||
<a
|
||||
@click="toggleDoneBucket(bucket)"
|
||||
@click.stop="toggleDoneBucket(bucket)"
|
||||
class="dropdown-item"
|
||||
v-tooltip="$t('list.kanban.doneBucketHintExtended')"
|
||||
>
|
||||
|
@ -85,9 +90,15 @@
|
|||
icon="check-double"/></span>
|
||||
{{ $t('list.kanban.doneBucket') }}
|
||||
</a>
|
||||
<a
|
||||
class="dropdown-item"
|
||||
@click.stop="() => collapseBucket(bucket)"
|
||||
>
|
||||
{{ $t('list.kanban.collapse') }}
|
||||
</a>
|
||||
<a
|
||||
:class="{'is-disabled': buckets.length <= 1}"
|
||||
@click="() => deleteBucketModal(bucket.id)"
|
||||
@click.stop="() => deleteBucketModal(bucket.id)"
|
||||
class="dropdown-item has-text-danger"
|
||||
v-tooltip="buckets.length <= 1 ? $t('list.kanban.deleteLast') : ''"
|
||||
>
|
||||
|
@ -283,6 +294,7 @@ import FilterPopup from '@/components/list/partials/filter-popup'
|
|||
import Dropdown from '@/components/misc/dropdown'
|
||||
import {playPop} from '@/helpers/playPop'
|
||||
import createTask from '@/components/tasks/mixins/createTask'
|
||||
import {getCollapsedBucketState, saveCollapsedBucketState} from '@/helpers/saveCollapsedBucketState'
|
||||
|
||||
export default {
|
||||
name: 'Kanban',
|
||||
|
@ -315,6 +327,7 @@ export default {
|
|||
showNewBucketInput: false,
|
||||
newTaskError: {},
|
||||
showSetLimitInput: false,
|
||||
collapsedBuckets: {},
|
||||
|
||||
// We're using this to show the loading animation only at the task when updating it
|
||||
taskUpdating: {},
|
||||
|
@ -369,6 +382,8 @@ export default {
|
|||
return
|
||||
}
|
||||
|
||||
this.collapsedBuckets = getCollapsedBucketState(this.$route.params.listId)
|
||||
|
||||
console.debug(`Loading buckets, loadedListId = ${this.loadedListId}, $route.params =`, this.$route.params)
|
||||
this.filtersChanged = false
|
||||
|
||||
|
@ -612,6 +627,18 @@ export default {
|
|||
bucket.isDoneBucket = !bucket.isDoneBucket
|
||||
})
|
||||
},
|
||||
collapseBucket(bucket) {
|
||||
this.$set(this.collapsedBuckets, bucket.id, true)
|
||||
saveCollapsedBucketState(this.$route.params.listId, this.collapsedBuckets)
|
||||
},
|
||||
unCollapseBucket(bucket) {
|
||||
if (!this.collapsedBuckets[bucket.id]) {
|
||||
return
|
||||
}
|
||||
|
||||
this.$set(this.collapsedBuckets, bucket.id, false)
|
||||
saveCollapsedBucketState(this.$route.params.listId, this.collapsedBuckets)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
|
Loading…
Reference in a new issue