Compare commits

...

7 Commits

Author SHA1 Message Date
Julius Härtl
f116d4f56b Implement drag scrolling the board
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2020-11-03 14:36:12 +01:00
Julius Härtl
4b8c811429 Use smooth scrolling to the center
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2020-11-03 14:16:27 +01:00
Julius Härtl
8ae580fd57 Implement fading out the cards when scrolling
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2020-11-03 14:16:27 +01:00
Julius Härtl
d0147cb03e Revert "Do not scroll cards into view"
This reverts commit abf67138e7.

Signed-off-by: Julius Härtl <jus@bitgrid.net>
2020-11-03 14:16:27 +01:00
Julius Härtl
c1423cde5a Fix card hover/active states
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2020-11-03 14:16:27 +01:00
Julius Härtl
7efd702b24 Fix new card input positioning
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2020-11-03 14:16:26 +01:00
Julius Härtl
bd9fe49ec4 Implement scrolling per stack
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2020-11-03 14:16:26 +01:00
5 changed files with 67 additions and 197 deletions

161
package-lock.json generated
View File

@@ -628,103 +628,6 @@
} }
} }
}, },
"@babel/helper-module-imports": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz",
"integrity": "sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw==",
"requires": {
"@babel/types": "^7.10.4"
},
"dependencies": {
"@babel/helper-validator-identifier": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz",
"integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw=="
},
"@babel/types": {
"version": "7.11.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.0.tgz",
"integrity": "sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA==",
"requires": {
"@babel/helper-validator-identifier": "^7.10.4",
"lodash": "^4.17.19",
"to-fast-properties": "^2.0.0"
}
}
}
},
"@babel/helper-module-transforms": {
"version": "7.11.0",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz",
"integrity": "sha512-02EVu8COMuTRO1TAzdMtpBPbe6aQ1w/8fePD2YgQmxZU4gpNWaL9gK3Jp7dxlkUlUCJOTaSeA+Hrm1BRQwqIhg==",
"requires": {
"@babel/helper-module-imports": "^7.10.4",
"@babel/helper-replace-supers": "^7.10.4",
"@babel/helper-simple-access": "^7.10.4",
"@babel/helper-split-export-declaration": "^7.11.0",
"@babel/template": "^7.10.4",
"@babel/types": "^7.11.0",
"lodash": "^4.17.19"
},
"dependencies": {
"@babel/code-frame": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
"integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==",
"requires": {
"@babel/highlight": "^7.10.4"
}
},
"@babel/helper-split-export-declaration": {
"version": "7.11.0",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz",
"integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==",
"requires": {
"@babel/types": "^7.11.0"
}
},
"@babel/helper-validator-identifier": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz",
"integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw=="
},
"@babel/highlight": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz",
"integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==",
"requires": {
"@babel/helper-validator-identifier": "^7.10.4",
"chalk": "^2.0.0",
"js-tokens": "^4.0.0"
}
},
"@babel/parser": {
"version": "7.11.0",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.0.tgz",
"integrity": "sha512-qvRvi4oI8xii8NllyEc4MDJjuZiNaRzyb7Y7lup1NqJV8TZHF4O27CcP+72WPn/k1zkgJ6WJfnIbk4jTsVAZHw=="
},
"@babel/template": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz",
"integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==",
"requires": {
"@babel/code-frame": "^7.10.4",
"@babel/parser": "^7.10.4",
"@babel/types": "^7.10.4"
}
},
"@babel/types": {
"version": "7.11.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.0.tgz",
"integrity": "sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA==",
"requires": {
"@babel/helper-validator-identifier": "^7.10.4",
"lodash": "^4.17.19",
"to-fast-properties": "^2.0.0"
}
}
}
},
"@babel/helper-optimise-call-expression": { "@babel/helper-optimise-call-expression": {
"version": "7.10.4", "version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz",
@@ -916,65 +819,6 @@
} }
} }
}, },
"@babel/helper-simple-access": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz",
"integrity": "sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw==",
"requires": {
"@babel/template": "^7.10.4",
"@babel/types": "^7.10.4"
},
"dependencies": {
"@babel/code-frame": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
"integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==",
"requires": {
"@babel/highlight": "^7.10.4"
}
},
"@babel/helper-validator-identifier": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz",
"integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw=="
},
"@babel/highlight": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz",
"integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==",
"requires": {
"@babel/helper-validator-identifier": "^7.10.4",
"chalk": "^2.0.0",
"js-tokens": "^4.0.0"
}
},
"@babel/parser": {
"version": "7.11.0",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.0.tgz",
"integrity": "sha512-qvRvi4oI8xii8NllyEc4MDJjuZiNaRzyb7Y7lup1NqJV8TZHF4O27CcP+72WPn/k1zkgJ6WJfnIbk4jTsVAZHw=="
},
"@babel/template": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz",
"integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==",
"requires": {
"@babel/code-frame": "^7.10.4",
"@babel/parser": "^7.10.4",
"@babel/types": "^7.10.4"
}
},
"@babel/types": {
"version": "7.11.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.0.tgz",
"integrity": "sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA==",
"requires": {
"@babel/helper-validator-identifier": "^7.10.4",
"lodash": "^4.17.19",
"to-fast-properties": "^2.0.0"
}
}
}
},
"@babel/helper-skip-transparent-expression-wrappers": { "@babel/helper-skip-transparent-expression-wrappers": {
"version": "7.12.1", "version": "7.12.1",
"resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz",
@@ -20478,6 +20322,11 @@
"tinycolor2": "^1.1.2" "tinycolor2": "^1.1.2"
} }
}, },
"vue-dragscroll": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/vue-dragscroll/-/vue-dragscroll-2.1.0.tgz",
"integrity": "sha512-ZNcvOdrnq9w4US2RqZOfp2cCJzEz1p4xZ1w4I+xKSAFlEOrXbryLe/iclspHH57dco5QT3Azd8/KD930WzadiQ=="
},
"vue-easymde": { "vue-easymde": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmjs.org/vue-easymde/-/vue-easymde-1.3.0.tgz", "resolved": "https://registry.npmjs.org/vue-easymde/-/vue-easymde-1.3.0.tgz",

View File

@@ -54,6 +54,7 @@
"vue": "^2.6.12", "vue": "^2.6.12",
"vue-at": "^2.5.0-beta.2", "vue-at": "^2.5.0-beta.2",
"vue-click-outside": "^1.1.0", "vue-click-outside": "^1.1.0",
"vue-dragscroll": "^2.1.0",
"vue-easymde": "^1.3.0", "vue-easymde": "^1.3.0",
"vue-infinite-loading": "^2.4.5", "vue-infinite-loading": "^2.4.5",
"vue-router": "^3.4.8", "vue-router": "^3.4.8",

View File

@@ -49,13 +49,13 @@
</form> </form>
</template> </template>
</EmptyContent> </EmptyContent>
<div v-else-if="!isEmpty && !loading" key="board" class="board"> <div v-else-if="!isEmpty && !loading" key="board" class="board" v-dragscroll:nochilddrag>
<Container lock-axix="y" <Container lock-axix="y"
orientation="horizontal" orientation="horizontal"
:drag-handle-selector="dragHandleSelector" :drag-handle-selector="dragHandleSelector"
@drop="onDropStack"> @drop="onDropStack">
<Draggable v-for="stack in stacksByBoard" :key="stack.id"> <Draggable v-for="stack in stacksByBoard" :key="stack.id">
<Stack :stack="stack" /> <Stack :stack="stack" data-dragscroll />
</Draggable> </Draggable>
</Container> </Container>
</div> </div>
@@ -75,7 +75,7 @@ import { mapState, mapGetters } from 'vuex'
import Controls from '../Controls' import Controls from '../Controls'
import Stack from './Stack' import Stack from './Stack'
import { EmptyContent } from '@nextcloud/vue' import { EmptyContent } from '@nextcloud/vue'
import { dragscroll } from 'vue-dragscroll'
export default { export default {
name: 'Board', name: 'Board',
components: { components: {
@@ -88,6 +88,9 @@ export default {
inject: [ inject: [
'boardApi', 'boardApi',
], ],
directives: {
dragscroll,
},
props: { props: {
id: { id: {
type: Number, type: Number,
@@ -112,7 +115,7 @@ export default {
return this.$store.getters.stacksByBoard(this.board.id) return this.$store.getters.stacksByBoard(this.board.id)
}, },
dragHandleSelector() { dragHandleSelector() {
return this.canEdit ? null : '.no-drag' return this.canEdit ? '.stack--header' : '.no-drag'
}, },
isEmpty() { isEmpty() {
return this.stacksByBoard.length === 0 return this.stacksByBoard.length === 0
@@ -194,6 +197,8 @@ export default {
.smooth-dnd-container.horizontal { .smooth-dnd-container.horizontal {
display: flex; display: flex;
align-items: stretch; align-items: stretch;
height: 100%;
.smooth-dnd-draggable-wrapper::v-deep { .smooth-dnd-draggable-wrapper::v-deep {
display: flex; display: flex;
height: auto; height: auto;
@@ -201,21 +206,17 @@ export default {
.stack { .stack {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
position: relative;
.smooth-dnd-container.vertical { .smooth-dnd-container.vertical {
flex-grow: 1; flex-grow: 1;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding: 0; padding: $stack-spacing;
/** overflow-x: hidden;
* Use this to scroll each stack individually overflow-y: auto;
* This currenly has the issue that the popover menu will be cut off padding-top: 15px;
*/ margin-top: -10px;
/*
overflow-x: scroll;
height: calc(100vh - 50px - 44px * 2 - 30px);
max-height: calc(100vh - 50px - 44px * 2 - 30px);
*/
} }
.smooth-dnd-container.vertical > .smooth-dnd-draggable-wrapper { .smooth-dnd-container.vertical > .smooth-dnd-draggable-wrapper {

View File

@@ -23,7 +23,7 @@
<template> <template>
<div class="stack"> <div class="stack">
<div v-click-outside="stopCardCreation" class="stack--header"> <div v-click-outside="stopCardCreation" class="stack--header" :class="{'stack--header--add': showAddCard }">
<transition name="fade" mode="out-in"> <transition name="fade" mode="out-in">
<h3 v-if="!canManage || isArchived"> <h3 v-if="!canManage || isArchived">
{{ stack.title }} {{ stack.title }}
@@ -267,9 +267,9 @@ export default {
@import './../../css/variables'; @import './../../css/variables';
.stack { .stack {
width: $stack-width; width: $stack-width + $stack-spacing*3;
margin-left: $stack-spacing; margin-left: $stack-spacing/2;
margin-right: $stack-spacing; margin-right: $stack-spacing/2;
} }
.stack--header { .stack--header {
@@ -277,14 +277,33 @@ export default {
position: sticky; position: sticky;
top: 0; top: 0;
z-index: 100; z-index: 100;
padding: 3px; padding-left: $card-spacing;
margin: 3px -3px;
margin-right: -10px;
margin-top: 0;
margin-bottom: 3px;
background-color: var(--color-main-background-translucent);
cursor: grab; cursor: grab;
// Smooth fade out of the cards at the top
&:before {
content: ' ';
display: block;
position: absolute;
background-image: linear-gradient(180deg, var(--color-main-background) 3px, transparent 100%);
width: 100%;
height: 25px;
top: 35px;
right: 6px;
z-index: 99;
transition: top var(--animation-slow);
}
&--add:before {
height: 80px;
background-image: linear-gradient(180deg, var(--color-main-background) 68px, transparent 100%);
}
& > * {
position: relative;
z-index: 100;
}
h3, form { h3, form {
flex-grow: 1; flex-grow: 1;
display: flex; display: flex;
@@ -304,22 +323,20 @@ export default {
} }
.stack--card-add { .stack--card-add {
position: sticky;
top: 52px;
height: 52px; height: 52px;
z-index: 100; z-index: 100;
display: flex; display: flex;
margin-left: 12px;
margin-right: 12px;
margin-top: 5px;
margin-bottom: 20px;
background-color: var(--color-main-background); background-color: var(--color-main-background);
margin-left: -10px;
margin-right: -10px;
padding-top: 3px;
form { form {
display: flex; display: flex;
width: 100%; width: 100%;
margin: 10px; margin: 0;
margin-top: 0; margin-right: 6px;
margin-bottom: 10px;
box-shadow: 0 0 3px var(--color-box-shadow); box-shadow: 0 0 3px var(--color-box-shadow);
border-radius: var(--border-radius-large); border-radius: var(--border-radius-large);
overflow: hidden; overflow: hidden;
@@ -339,10 +356,6 @@ export default {
} }
} }
.stack .smooth-dnd-container.vertical {
margin-top: 3px;
}
/** /**
* Rules to handle scrolling behaviour are inherited from Board.vue * Rules to handle scrolling behaviour are inherited from Board.vue
*/ */

View File

@@ -131,6 +131,13 @@ export default {
return [...this.card.labels].sort((a, b) => (a.title < b.title) ? -1 : 1) return [...this.card.labels].sort((a, b) => (a.title < b.title) ? -1 : 1)
}, },
}, },
watch: {
currentCard(newValue) {
if (newValue) {
this.$nextTick(() => this.$el.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'center' }))
}
},
},
methods: { methods: {
openCard() { openCard() {
const boardId = this.card && this.card.boardId ? this.card.boardId : this.$route.params.id const boardId = this.card && this.card.boardId ? this.card.boardId : this.$route.params.id
@@ -160,10 +167,6 @@ export default {
@import './../../css/animations'; @import './../../css/animations';
@import './../../css/variables'; @import './../../css/variables';
.card:hover {
box-shadow: 0 0 5px 1px var(--color-box-shadow);
}
.card { .card {
transition: box-shadow 0.1s ease-in-out; transition: box-shadow 0.1s ease-in-out;
box-shadow: 0 0 2px 0 var(--color-box-shadow); box-shadow: 0 0 2px 0 var(--color-box-shadow);
@@ -180,9 +183,12 @@ export default {
border: 2px solid var(--color-border); border: 2px solid var(--color-border);
} }
&.current-card { &:hover {
box-shadow: 0 0 5px 0 var(--color-box-shadow); box-shadow: 0 0 5px 0 var(--color-box-shadow);
} }
&.current-card {
box-shadow: 0 0 5px 1px var(--color-box-shadow);
}
.card-upper { .card-upper {
display: flex; display: flex;