diff --git a/src/App.vue b/src/App.vue index b1c57d46..3a538efc 100644 --- a/src/App.vue +++ b/src/App.vue @@ -128,6 +128,7 @@ return { user: auth.user, namespaces: [], + namespaceService: NamespaceService, mobileMenuActive: false, fullpage: false, currentDate: new Date(), @@ -149,6 +150,7 @@ }, created() { if (this.user.authenticated) { + this.namespaceService = new NamespaceService() this.loadNamespaces() } }, @@ -164,8 +166,7 @@ return 'https://www.gravatar.com/avatar/' + this.user.infos.avatar + '?s=50' }, loadNamespaces() { - let namespaceService = new NamespaceService() - namespaceService.getAll() + this.namespaceService.getAll() .then(r => { this.$set(this, 'namespaces', r) }) diff --git a/src/components/lists/EditList.vue b/src/components/lists/EditList.vue index 8eff4d91..8d63b8a5 100644 --- a/src/components/lists/EditList.vue +++ b/src/components/lists/EditList.vue @@ -41,8 +41,8 @@ - - + + { message.error(e, this) diff --git a/src/components/namespaces/EditNamespace.vue b/src/components/namespaces/EditNamespace.vue index 5f0bd1b5..481a92e8 100644 --- a/src/components/namespaces/EditNamespace.vue +++ b/src/components/namespaces/EditNamespace.vue @@ -41,8 +41,8 @@ - - + + { message.error(e, this) diff --git a/src/components/sharing/team.vue b/src/components/sharing/team.vue deleted file mode 100644 index 3d0d9693..00000000 --- a/src/components/sharing/team.vue +++ /dev/null @@ -1,221 +0,0 @@ - - - - - \ No newline at end of file diff --git a/src/components/sharing/user.vue b/src/components/sharing/user.vue deleted file mode 100644 index 27ee3f01..00000000 --- a/src/components/sharing/user.vue +++ /dev/null @@ -1,291 +0,0 @@ - - - - - \ No newline at end of file diff --git a/src/components/sharing/userTeam.vue b/src/components/sharing/userTeam.vue new file mode 100644 index 00000000..bc49b2d4 --- /dev/null +++ b/src/components/sharing/userTeam.vue @@ -0,0 +1,342 @@ + + + + + \ No newline at end of file diff --git a/src/models/rights.json b/src/models/rights.json new file mode 100644 index 00000000..61e6b145 --- /dev/null +++ b/src/models/rights.json @@ -0,0 +1,5 @@ +{ + "READ": 0, + "READ_WRITE": 1, + "ADMIN": 2 +} \ No newline at end of file diff --git a/src/styles/_multiselect.scss b/src/styles/_multiselect.scss new file mode 100644 index 00000000..3b2e5112 --- /dev/null +++ b/src/styles/_multiselect.scss @@ -0,0 +1,433 @@ +fieldset[disabled] .multiselect { + pointer-events: none; +} + +.multiselect__spinner { + position: absolute; + right: 1px; + top: 1px; + width: 48px; + height: 35px; + background: $white; + display: block; + + &:before, &:after { + position: absolute; + content: ""; + top: 50%; + left: 50%; + margin: -8px 0 0 -8px; + width: 16px; + height: 16px; + border-radius: 100%; + border-color: $multiselect_primary transparent transparent; + border-style: solid; + border-width: 2px; + box-shadow: 0 0 0 1px transparent; + } + &:before { + animation: spinning 2.4s cubic-bezier(0.41, 0.26, 0.2, 0.62); + animation-iteration-count: infinite; + } + &:after { + animation: spinning 2.4s cubic-bezier(0.51, 0.09, 0.21, 0.8); + animation-iteration-count: infinite; + } +} + +.multiselect__loading-enter-active, .multiselect__loading-leave-active { + transition: opacity 0.4s ease-in-out; + opacity: 1; +} + +.multiselect__loading-enter, .multiselect__loading-leave-active { + opacity: 0; +} + +.multiselect, .multiselect__input, .multiselect__single { + font-family: inherit; + font-size: 16px; + touch-action: manipulation; +} + +.multiselect { + box-sizing: content-box; + display: block; + position: relative; + width: 100%; + min-height: 40px; + text-align: left; + color: $text; + * { + box-sizing: border-box; + } + &:focus { + outline: none; + } +} + +.multiselect--disabled { + pointer-events: none; + opacity: 0.6; +} + +.multiselect--active { + z-index: 50; + &:not(.multiselect--above) { + .multiselect__current, .multiselect__input, .multiselect__tags { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + } + } + .multiselect__select { + transform: rotateZ(180deg); + } +} + +.multiselect--above.multiselect--active { + .multiselect__current, .multiselect__input, .multiselect__tags { + border-top-left-radius: 0; + border-top-right-radius: 0; + } +} + +.multiselect__input, .multiselect__single { + position: relative; + display: inline-block; + min-height: 20px; + line-height: 20px; + border: none; + border-radius: 5px; + background: $white; + padding: 0 0 0 5px; + width: calc(100%); + transition: border 0.1s ease; + box-sizing: border-box; + margin-bottom: 8px; + vertical-align: top; +} + +.multiselect__input::placeholder { + color: $multiselect-dark; +} + +.multiselect__tag ~ { + .multiselect__input, .multiselect__single { + width: auto; + } +} + +.multiselect__input:hover, .multiselect__single:hover { + border-color: darken($white, 10); +} + +.multiselect__input:focus { + border-color: $primary; + outline: none; +} + +.multiselect__single { + &:focus { + border-color: $primary; + outline: none; + } + padding-left: 5px; + margin-bottom: 8px; +} + +.multiselect__tags-wrap { + display: inline; +} + +.multiselect__tags { + min-height: 40px; + display: block; + padding: 8px 40px 0 8px; + border-radius: 5px; + border: 1px solid $multiselect-border; + background: $white; + font-size: 14px; +} + +.multiselect__tag { + position: relative; + display: inline-block; + padding: 4px 26px 4px 10px; + border-radius: 5px; + margin-right: 10px; + color: $white; + line-height: 1; + background: $multiselect-highlight; + margin-bottom: 5px; + white-space: nowrap; + overflow: hidden; + max-width: 100%; + text-overflow: ellipsis; +} + +.multiselect__tag-icon { + cursor: pointer; + margin-left: 7px; + position: absolute; + right: 0; + top: 0; + bottom: 0; + font-weight: 700; + font-style: initial; + width: 22px; + text-align: center; + line-height: 22px; + transition: all 0.2s ease; + border-radius: 5px; + &:after { + content: "×"; + color: darken($multiselect-highlight, 20); + font-size: 14px; + } + &:focus, &:hover { + background: lighten($multiselect-highlight, 10); + } + &:focus:after, &:hover:after { + color: $white; + } +} + +.multiselect__current { + line-height: 16px; + min-height: 40px; + box-sizing: border-box; + display: block; + overflow: hidden; + padding: 8px 30px 0 12px; + white-space: nowrap; + margin: 0; + text-decoration: none; + border-radius: 5px; + border: 1px solid $multiselect-border; + cursor: pointer; +} + +.multiselect__select { + line-height: 16px; + display: block; + position: absolute; + box-sizing: border-box; + width: 40px; + height: 38px; + right: 1px; + top: 1px; + padding: 4px 8px; + margin: 0; + text-decoration: none; + text-align: center; + cursor: pointer; + transition: transform 0.2s ease; + &:before { + position: relative; + right: 0; + top: 65%; + color: darken($multiselect-border, 30); + margin-top: 4px; + border-style: solid; + border-width: 5px 5px 0 5px; + border-color: darken($multiselect-border, 30) transparent transparent transparent; + content: ""; + } +} + +.multiselect__placeholder { + color: darken($white, 15); + display: inline-block; + margin-bottom: 10px; + padding-top: 2px; +} + +.multiselect--active .multiselect__placeholder { + display: none; +} + +.multiselect__content-wrapper { + position: absolute; + display: block; + background: $white; + width: 100%; + max-height: 240px; + overflow: auto; + border: 1px solid $multiselect-border; + border-top: none; + border-bottom-left-radius: 5px; + border-bottom-right-radius: 5px; + z-index: 50; + -webkit-overflow-scrolling: touch; +} + +.multiselect__content, .content ul.multiselect__content { + list-style: none; + display: inline-block; + padding: 0; + margin: 0; + min-width: 100%; + vertical-align: top; +} + +.multiselect--above .multiselect__content-wrapper { + bottom: 100%; + border-radius: 5px 5px 0 0; + border-bottom: none; + border-top: 1px solid $multiselect-border; +} + +.multiselect__content::webkit-scrollbar { + display: none; +} + +.multiselect__element { + display: block; +} + +.multiselect__option { + display: block; + padding: 12px; + min-height: 40px; + line-height: 16px; + text-decoration: none; + text-transform: none; + vertical-align: middle; + position: relative; + cursor: pointer; + white-space: nowrap; + &:after { + top: 0; + right: 0; + position: absolute; + line-height: 40px; + padding-right: 12px; + padding-left: 20px; + font-size: 13px; + } +} + +.multiselect__option--highlight { + background: $multiselect-highlight; + outline: none; + color: $white; + &:after { + content: attr(data-select); + background: $multiselect-highlight; + color: $white; + } +} + +.multiselect__option--selected { + background: darken($white, 10); + color: $multiselect-dark; + font-weight: bold; + &:after { + content: attr(data-selected); + color: silver; + } + &.multiselect__option--highlight { + background: $multiselect-highlight-negative; + color: $white; + &:after { + background: $multiselect-highlight-negative; + content: attr(data-deselect); + color: $white; + } + } +} + +.multiselect--disabled { + background: $multiselect-disabled; + pointer-events: none; + .multiselect__current, .multiselect__select { + background: $multiselect-disabled; + color: darken($multiselect-disabled, 40); + } +} + +.multiselect__option--disabled { + background: $multiselect-disabled !important; + color: darken($multiselect-disabled, 40) !important; + cursor: text; + pointer-events: none; +} + +.multiselect__option--group { + background: $multiselect-disabled; + color: $multiselect-dark; + &.multiselect__option--highlight { + background: $multiselect-dark; + color: $white; + &:after { + background: $multiselect-dark; + } + } +} + +.multiselect__option--disabled.multiselect__option--highlight { + background: $multiselect-disabled; +} + +.multiselect__option--group-selected.multiselect__option--highlight { + background: $multiselect-highlight-negative; + color: $white; + &:after { + background: $multiselect-highlight-negative; + content: attr(data-deselect); + color: $white; + } +} + +.multiselect-enter-active, .multiselect-leave-active { + transition: all 0.15s ease; +} + +.multiselect-enter, .multiselect-leave-active { + opacity: 0; +} + +.multiselect__strong { + margin-bottom: 8px; + line-height: 20px; + display: inline-block; + vertical-align: top; +} + +*[dir="rtl"] { + .multiselect { + text-align: right; + } + .multiselect__select { + right: auto; + left: 1px; + } + .multiselect__tags { + padding: 8px 8px 0px 40px; + } + .multiselect__content { + text-align: right; + } + .multiselect__option:after { + right: auto; + left: 0; + } + .multiselect__clear { + right: auto; + left: 12px; + } + .multiselect__spinner { + right: auto; + left: 1px; + } +} + +@keyframes spinning { + from { + transform: rotate(0); + } + + to { + transform: rotate(2turn); + } +} \ No newline at end of file diff --git a/src/styles/_variables.scss b/src/styles/_variables.scss index 7283455f..94f090a4 100644 --- a/src/styles/_variables.scss +++ b/src/styles/_variables.scss @@ -23,4 +23,11 @@ $vikunja-blue: #7F23FF;// #7F23FF; // #5974d9 $vikunja-green: #4DB788; $navbar-padding: 1.5em; -$transition: 150ms ease; \ No newline at end of file +$transition: 150ms ease; + +$multiselect-primary: $green; +$multiselect-dark: #35495e; +$multiselect-border: #e8e8e8; +$multiselect-highlight: $green; +$multiselect-highlight-negative: $red; +$multiselect-disabled: darken(#fff, 40); \ No newline at end of file diff --git a/src/styles/theme.scss b/src/styles/theme.scss index 9b3d2c34..4a58d7ed 100644 --- a/src/styles/theme.scss +++ b/src/styles/theme.scss @@ -28,6 +28,10 @@ box-shadow: 0.1em 0.1em 0.7em lighten($dark, 75) !important; } + &.icon-only{ + padding-left: 16px; + } + @each $name, $pair in $colors { $color: nth($pair, 1); diff --git a/src/vikunja.scss b/src/vikunja.scss index ace4940b..a28753bc 100644 --- a/src/vikunja.scss +++ b/src/vikunja.scss @@ -6,4 +6,6 @@ @import 'styles/fullpage'; @import 'styles/fancycheckbox'; -@import 'styles/tooltip'; \ No newline at end of file +@import 'styles/tooltip'; + +@import 'styles/multiselect'; \ No newline at end of file diff --git a/todo.md b/todo.md index a7448ce6..4be6ca71 100644 --- a/todo.md +++ b/todo.md @@ -105,10 +105,13 @@ * [x] Move everything to models * [x] Make sure all loading properties are depending on its service * [x] Fix the first request afer login being made with an old token -* [ ] Team sharing - * [ ] Refactor team sharing to not make a new request every time something was changed - * [ ] Team sharing should be able to search for a team instead of its ID, like it's the case with users - * [ ] Dropdown for rights +* [x] Team sharing + * [x] Refactor team sharing to not make a new request every time something was changed + * [x] Team sharing should be able to search for a team instead of its ID, like it's the case with users + * [x] Dropdown for rights +* [x] Same improvements also for user sharing +* [x] Use rights const everywhere +* [x] Styling of the search dropdown to match the rest of the theme ## Waiting for backend