|
@@ -1,27 +1,55 @@
|
|
|
<template>
|
|
|
- <label class='heart_button' :class='{"heart_button--unlikeable": !likeable}'>
|
|
|
- <input
|
|
|
- type='checkbox'
|
|
|
- :disabled='!likeable'
|
|
|
- :checked='liked'
|
|
|
- v-on:change="change"
|
|
|
- >
|
|
|
- <span class='fa'></span>
|
|
|
- <span class='heart_button__count'>{{likes}}</span>
|
|
|
- </label>
|
|
|
+ <div class='heart_button'>
|
|
|
+ <modal-window v-model='showModal' :close-button='true'>
|
|
|
+ <div class='heart_button__modal'>
|
|
|
+ <div class='heart_button__modal__header'>Likes</div>
|
|
|
+ <div
|
|
|
+ class='heart_button__modal__user'
|
|
|
+ v-for='user in likes'
|
|
|
+ @click='$router.push("/user/" + user.username)'
|
|
|
+ >
|
|
|
+ <avatar-icon
|
|
|
+ :user='user'
|
|
|
+ size='small'
|
|
|
+ ></avatar-icon>
|
|
|
+ <div class='heart_button__modal__username'>{{user.username}}</div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class='heart_button__modal__empty' v-if='!likes.length'>
|
|
|
+ No likes
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </modal-window>
|
|
|
+
|
|
|
+ <span
|
|
|
+ class='heart_button__heart fa'
|
|
|
+ :class='{
|
|
|
+ "heart_button__heart--unlikeable": !likeable,
|
|
|
+ "heart_button__heart--liked": liked
|
|
|
+ }'
|
|
|
+ @click='changeLike'
|
|
|
+ ></span>
|
|
|
+ <span class='heart_button__count' @click='showModal = true'>{{likes.length}}</span>
|
|
|
+ </div>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
+ import ModalWindow from './ModalWindow'
|
|
|
+ import AvatarIcon from './AvatarIcon'
|
|
|
+
|
|
|
import AjaxErrorHandler from '../assets/js/errorHandler'
|
|
|
|
|
|
export default {
|
|
|
name: 'HeartButton',
|
|
|
props: ['post'],
|
|
|
+ components: {
|
|
|
+ ModalWindow,
|
|
|
+ AvatarIcon
|
|
|
+ },
|
|
|
data () {
|
|
|
return {
|
|
|
- changed: false,
|
|
|
- likes_: undefined,
|
|
|
- liked_: false
|
|
|
+ likes: this.post.Likes,
|
|
|
+ showModal: false
|
|
|
}
|
|
|
},
|
|
|
computed: {
|
|
@@ -35,60 +63,50 @@
|
|
|
postUsername !== this.$store.state.username
|
|
|
)
|
|
|
},
|
|
|
- likes: {
|
|
|
- get () {
|
|
|
- let likes = this.post.Likes.length
|
|
|
-
|
|
|
- if(this.changed) {
|
|
|
- return this.likes_
|
|
|
- } else {
|
|
|
- return likes
|
|
|
- }
|
|
|
- }
|
|
|
- },
|
|
|
- liked: {
|
|
|
- get () {
|
|
|
- if(this.changed) {
|
|
|
- return this.liked_
|
|
|
- } else {
|
|
|
- return this.post.Likes.some(u => {
|
|
|
- return u.username === this.$store.state.username
|
|
|
- })
|
|
|
- }
|
|
|
- },
|
|
|
- set (val) {
|
|
|
- if(this.likes_ === undefined) {
|
|
|
- this.likes_ = this.post.Likes.length + (val ? 1 : -1)
|
|
|
- } else {
|
|
|
- this.likes_+= val ? 1 : -1
|
|
|
- }
|
|
|
-
|
|
|
- this.changed = true
|
|
|
- this.liked_ = val
|
|
|
- }
|
|
|
+ liked () {
|
|
|
+ return this.likes.some(u => {
|
|
|
+ return u.username === this.$store.state.username
|
|
|
+ })
|
|
|
}
|
|
|
},
|
|
|
methods: {
|
|
|
- change (e) {
|
|
|
- let liked = e.target.checked
|
|
|
+ getIndexOfUser () {
|
|
|
+ let index
|
|
|
+
|
|
|
+ for(let i = 0; i < this.likes.length; i++) {
|
|
|
+ let user = this.likes[i]
|
|
|
+
|
|
|
+ if(user.username === this.$store.state.username) {
|
|
|
+ index = i
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return index
|
|
|
+ },
|
|
|
+ changeLike (e) {
|
|
|
let id = this.post.id
|
|
|
-
|
|
|
- if(liked) {
|
|
|
+
|
|
|
+ if(!this.likeable) return
|
|
|
+
|
|
|
+ if(!this.liked) {
|
|
|
this.axios
|
|
|
.put('/api/v1/post/' + id + '/like')
|
|
|
- .then(_ => this.liked = true)
|
|
|
- .catch((err) => {
|
|
|
- e.target.checked = !liked
|
|
|
- AjaxErrorHandler(this.$store)(err)
|
|
|
+ .then(() => {
|
|
|
+ return this.axios
|
|
|
+ .get('/api/v1/user/' + this.$store.state.username)
|
|
|
+ })
|
|
|
+ .then(res => {
|
|
|
+ this.likes.push(res.data)
|
|
|
})
|
|
|
+ .catch(AjaxErrorHandler(this.$store))
|
|
|
} else {
|
|
|
this.axios
|
|
|
- .delete('/api/v1/post/' + id + '/like')
|
|
|
- .then(_ => this.liked = false)
|
|
|
- .catch((err) => {
|
|
|
- e.target.checked = !liked
|
|
|
- AjaxErrorHandler(this.$store)(err)
|
|
|
+ .delete('/api/v1/post/' + id + '/like')
|
|
|
+ .then(() => {
|
|
|
+ this.likes.splice(this.getIndexOfUser(), 1)
|
|
|
})
|
|
|
+ .catch(AjaxErrorHandler(this.$store))
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -99,37 +117,86 @@
|
|
|
@import '../assets/scss/variables.scss';
|
|
|
|
|
|
.heart_button {
|
|
|
- cursor: pointer;
|
|
|
- @include user-select(none);
|
|
|
+ @at-root #{&}__modal {
|
|
|
+ padding: 1rem;
|
|
|
|
|
|
- @at-root #{&}--unlikeable {
|
|
|
- cursor: not-allowed;
|
|
|
- }
|
|
|
+ @at-root #{&}__header {
|
|
|
+ font-size: 1.5rem;
|
|
|
+ font-weight: bold;
|
|
|
+ margin-bottom: 0.25rem;
|
|
|
+ }
|
|
|
+ @at-root #{&}__user {
|
|
|
+ display: flex;
|
|
|
+ align-items: centre;
|
|
|
+ line-height: 2.2rem;
|
|
|
+ max-height: 3rem;
|
|
|
+ padding: 0.25rem;
|
|
|
+ margin: 0 -0.25rem;
|
|
|
+ border-bottom: solid thin $color__gray--primary;
|
|
|
+ transition: background-color 0.2s;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background-color: $color__lightgray--primary;
|
|
|
+ }
|
|
|
|
|
|
- input {
|
|
|
- display: none;
|
|
|
+ &:last-child {
|
|
|
+ border-bottom: none;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ @at-root #{&}__username {
|
|
|
+ cursor: default;
|
|
|
+ font-size: 1.25rem;
|
|
|
+ margin-left: 0.5rem;
|
|
|
+ margin-bottom: -0.4rem;
|
|
|
+ }
|
|
|
+ @at-root #{&}__empty {
|
|
|
+ text-align: center;
|
|
|
+ font-size: 1.5rem;
|
|
|
+ user-select: none;
|
|
|
+ cursor: default;
|
|
|
+ color: $color__gray--darkest;
|
|
|
+ font-style: italic;
|
|
|
+ margin-bottom: 0.5rem;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- #{&}__count {
|
|
|
+ @at-root #{&}__count {
|
|
|
+ @include user-select(none);
|
|
|
+
|
|
|
position: relative;
|
|
|
bottom: 0.0625rem;
|
|
|
+ cursor: default;
|
|
|
}
|
|
|
|
|
|
- span.fa {
|
|
|
+ @at-root #{&}__heart {
|
|
|
+ @include user-select(none);
|
|
|
+
|
|
|
+ cursor: pointer;
|
|
|
color: $color__gray--darkest;
|
|
|
- transition: text-shadow 0.2s, color 0.2s, filter 0.2s;
|
|
|
+ transition: transform 0.2s, text-shadow 0.2s, color 0.2s, filter 0.2s;
|
|
|
font-size: 1.125rem;
|
|
|
|
|
|
&:hover {
|
|
|
filter: brightness(0.9);
|
|
|
+ transform: scale(1.1);
|
|
|
}
|
|
|
|
|
|
&::before {
|
|
|
content: "\f004";
|
|
|
}
|
|
|
- }
|
|
|
- input:checked + span.fa {
|
|
|
- color: #E91E63;
|
|
|
+
|
|
|
+
|
|
|
+ @at-root #{&}--liked {
|
|
|
+ color: #E91E63;
|
|
|
+ }
|
|
|
+ @at-root #{&}--unlikeable {
|
|
|
+ cursor: default;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ filter: none;
|
|
|
+ transform: none;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
</style>
|