aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.quasar/entry.js4
-rw-r--r--quasar.conf.js3
-rw-r--r--src/components/CommentVoter.vue59
-rw-r--r--src/components/UploadVoter.vue11
-rw-r--r--src/pages/UploadDetail.vue83
-rw-r--r--src/pages/UploadList.vue9
6 files changed, 150 insertions, 19 deletions
diff --git a/.quasar/entry.js b/.quasar/entry.js
index e50aef7..4e35988 100644
--- a/.quasar/entry.js
+++ b/.quasar/entry.js
@@ -40,12 +40,12 @@ import 'src/css/app.styl'
import Vue from 'vue'
-import Quasar, {QAlert,QLayout,QLayoutHeader,QLayoutDrawer,QPageContainer,QPage,QToolbar,QToolbarTitle,QBtn,QIcon,QList,QListHeader,QInput,QItem,QItemMain,QItemSide,QTable,QTabs,QRouteTab,QInnerLoading,QField,QStep,QStepper,QStepperNavigation,QTd,QSpinner,QCard,QCardTitle,QCardMain,QCardMedia,QCardSeparator,QCardActions,QParallax,QCheckbox,QChip,Ripple,LocalStorage,Dialog} from 'quasar'
+import Quasar, {QAlert,QLayout,QLayoutHeader,QLayoutDrawer,QPageContainer,QPage,QToolbar,QToolbarTitle,QBtn,QIcon,QList,QListHeader,QInput,QItem,QItemMain,QItemSide,QTable,QTabs,QRouteTab,QInnerLoading,QSpinnerComment,QField,QStep,QStepper,QStepperNavigation,QTd,QSpinner,QCard,QCardTitle,QCardMain,QCardMedia,QCardSeparator,QCardActions,QParallax,QCheckbox,QChip,QChatMessage,Ripple,LocalStorage,Dialog,Notify} from 'quasar'
Vue.config.productionTip = false
import App from 'src/App'
-Vue.use(Quasar, {components: {QAlert,QLayout,QLayoutHeader,QLayoutDrawer,QPageContainer,QPage,QToolbar,QToolbarTitle,QBtn,QIcon,QList,QListHeader,QInput,QItem,QItemMain,QItemSide,QTable,QTabs,QRouteTab,QInnerLoading,QField,QStep,QStepper,QStepperNavigation,QTd,QSpinner,QCard,QCardTitle,QCardMain,QCardMedia,QCardSeparator,QCardActions,QParallax,QCheckbox,QChip},directives: {Ripple},plugins: {LocalStorage,Dialog}})
+Vue.use(Quasar, {components: {QAlert,QLayout,QLayoutHeader,QLayoutDrawer,QPageContainer,QPage,QToolbar,QToolbarTitle,QBtn,QIcon,QList,QListHeader,QInput,QItem,QItemMain,QItemSide,QTable,QTabs,QRouteTab,QInnerLoading,QSpinnerComment,QField,QStep,QStepper,QStepperNavigation,QTd,QSpinner,QCard,QCardTitle,QCardMain,QCardMedia,QCardSeparator,QCardActions,QParallax,QCheckbox,QChip,QChatMessage},directives: {Ripple},plugins: {LocalStorage,Dialog,Notify}})
diff --git a/quasar.conf.js b/quasar.conf.js
index 8705458..610ef26 100644
--- a/quasar.conf.js
+++ b/quasar.conf.js
@@ -76,6 +76,7 @@ module.exports = function (ctx) {
'QTabs',
'QRouteTab',
'QInnerLoading',
+ 'QSpinnerComment',
'QField',
'QStep',
'QStepper',
@@ -91,6 +92,7 @@ module.exports = function (ctx) {
'QParallax',
'QCheckbox',
'QChip',
+ 'QChatMessage',
],
directives: [
'Ripple'
@@ -98,6 +100,7 @@ module.exports = function (ctx) {
plugins: [
'LocalStorage',
'Dialog',
+ 'Notify',
]
},
// animations: 'all' --- includes all animations
diff --git a/src/components/CommentVoter.vue b/src/components/CommentVoter.vue
new file mode 100644
index 0000000..6f2ce0d
--- /dev/null
+++ b/src/components/CommentVoter.vue
@@ -0,0 +1,59 @@
+<template>
+ <div>
+ <div class="flex row items-center group" v-if="$store.getters['user/loggedIn']">
+ <span style="margin: 0 1rem">
+ <i class="fa"
+ :class="{'fa-caret-up text-positive': comment.voting.sum > 0, 'fa-caret-down text-negative': comment.voting.sum < 0, 'fa-sort text-dark': comment.voting.sum === 0}">
+ </i>
+ {{ comment.voting.sum }}
+ </span>
+ <span v-if="comment.author.username !== $store.state.user.decodedToken.username && !myVote">
+ <q-btn color="negative" round small icon="fa-thumbs-down" @click="vote(-1)"></q-btn>
+ <q-btn color="positive" round small icon="fa-thumbs-up" @click="vote(1)"></q-btn>
+ </span>
+ <span v-if="myVote">You voted <i :class="`fas fa-thumbs-${myVote.impact === 1 ? 'up text-positive' : 'down text-negative'}`"></i></span>
+ </div>
+ <div class="group" v-else>
+ <i class="fa"
+ :class="{'fa-caret-up text-positive': comment.voting.sum > 0, 'fa-caret-down text-negative': comment.voting.sum < 0, 'fa-sort text-dark': comment.voting.sum === 0}">
+ </i>
+ {{ comment.voting.sum }} votes
+ <em>Please log in to vote</em>
+ </div>
+ </div>
+</template>
+
+<script>
+ import {
+ QBtn,
+ } from 'quasar'
+
+ export default {
+ props: {
+ comment: Object,
+ },
+ components: {
+ QBtn,
+ },
+ data () {
+ return {}
+ },
+ computed: {
+ myVote () {
+ if (!this.comment || !this.comment.voting || !Array.isArray(this.comment.voting.votes) || this.comment.voting.votes.length === 0) {
+ return undefined
+ }
+ return this.comment.voting.votes[0]
+ },
+ },
+ methods: {
+ vote (impact) {
+ let that = this
+ this.$http.post(`/comments/${this.comment.upload}/comments/${this.comment._id}/vote`, {impact: impact}).then(response => that.$emit('voted'))
+ },
+ },
+ }
+</script>
+
+<style lang="styl" type="text/stylus" scoped>
+</style>
diff --git a/src/components/UploadVoter.vue b/src/components/UploadVoter.vue
index 65a5453..563bc79 100644
--- a/src/components/UploadVoter.vue
+++ b/src/components/UploadVoter.vue
@@ -7,10 +7,11 @@
</i>
{{ upload.voting.sum }}
</h5>
- <span v-if="upload.author.username !== $store.state.user.decodedToken.username">
+ <span v-if="upload.author.username !== $store.state.user.decodedToken.username && !myVote">
<q-btn color="negative" round small icon="fa-thumbs-down" @click="vote(-1)"></q-btn>
<q-btn color="positive" round small icon="fa-thumbs-up" @click="vote(1)"></q-btn>
</span>
+ <span v-if="myVote">You voted <i :class="`fas fa-thumbs-${myVote.impact === 1 ? 'up text-positive' : 'down text-negative'}`"></i></span>
</div>
<div class="group" v-else>
<i class="fa"
@@ -37,6 +38,14 @@
data () {
return {}
},
+ computed: {
+ myVote () {
+ if (!this.upload || !this.upload.voting || !Array.isArray(this.upload.voting.votes) || this.upload.voting.votes.length === 0) {
+ return undefined
+ }
+ return this.upload.voting.votes[0]
+ },
+ },
methods: {
vote (impact) {
let that = this
diff --git a/src/pages/UploadDetail.vue b/src/pages/UploadDetail.vue
index b2042b6..9b6f73a 100644
--- a/src/pages/UploadDetail.vue
+++ b/src/pages/UploadDetail.vue
@@ -21,14 +21,6 @@
<span slot="right" class="text-light" style="margin-left: 3rem">updated {{ upload.updatedAt | moment("from") }}</span>
</q-card-title>
<q-card-separator />
- <q-card-main>
- <p class="text-faded">
- {{ upload.description }}
- </p>
- <div class="group">
- <q-chip v-for="tag of upload.tags" :key="tag">{{ tag }}</q-chip>
- </div>
- </q-card-main>
<q-card-actions>
<q-btn @click="openInOpenclonk" color="positive" outline>
Install mod with OpenClonk
@@ -41,6 +33,46 @@
Delete mod
</q-btn>
</q-card-actions>
+ <q-card-main>
+ <p class="text-faded">
+ {{ upload.description }}
+ </p>
+ <div class="group">
+ <q-chip v-for="tag of upload.tags" :key="tag">{{ tag }}</q-chip>
+ </div>
+ </q-card-main>
+ <q-card-title>Comments</q-card-title>
+ <q-card-main>
+ <div class="flex row no-wrap items-center"
+ v-for="comment of comments.comments"
+ :key="comment._id">
+ <q-chat-message
+ style="max-width: 90%"
+ :name="(comment.author || {}).username"
+ :text="comment.body.split('\n').filter(el => el.trim() !== '')"
+ :stamp="$moment(comment.createdAt).format('LLLL')" />
+ <comment-voter :comment="comment"></comment-voter>
+ </div>
+ <div>
+ <q-input
+ v-model="comment"
+ type="textarea"
+ placeholder="Write a comment"
+ :max-height="100"
+ @keyup.enter="sendComment"
+ :after="[
+ {
+ icon: 'fa-paper-plane',
+ content: true,
+ handler () {
+ sendComment()
+ }
+ }
+ ]"
+ />
+ <q-inner-loading :visible="commentSaving"><q-spinner-comment></q-spinner-comment></q-inner-loading>
+ </div>
+ </q-card-main>
<q-card-media v-if="upload.pic" overlay-position="bottom">
<q-card-title slot="overlay">
Voting
@@ -139,10 +171,12 @@
<script>
import { openURL } from 'quasar'
import UploadVoter from 'components/UploadVoter'
+ import CommentVoter from 'components/CommentVoter'
import FileSaver from 'file-saver'
export default {
components: {
+ CommentVoter,
UploadVoter,
},
computed: {
@@ -164,6 +198,9 @@
return {
upload: null,
downloadProgresses: {},
+ comments: [],
+ comment: '',
+ commentSaving: false,
}
},
methods: {
@@ -171,10 +208,23 @@
let that = this
this.$http.get(`/uploads/${this.routeId}`).then(response => {
that.upload = response.data
+ that.loadComments()
}).catch((error) => {
if (error.response.status === 404) {
that.$router.push({name: 'upload-list'})
}
+ else {
+ console.error(error)
+ }
+ })
+ },
+ loadComments () {
+ let that = this
+ this.$http.get(`/uploads/${this.routeId}/comments`).then(response => {
+ that.comments = response.data
+ }).catch((error) => {
+ that.$q.notify('Failed loading comments')
+ console.error(error)
})
},
deleteUpload (upload) {
@@ -218,6 +268,23 @@
},
openInOpenclonk () {
openURL(`openclonk://installmod/${this.upload._id}`)
+ },
+ sendComment () {
+ let that = this
+ this.commentSaving = true
+ if (this.comment.length > 0) {
+ this.$http.post(`/uploads/${this.upload._id}/comments`, {body: this.comment}).then(() => {
+ that.comment = ''
+ that.$q.notify({color: 'positive', icon: 'fa-check', message: 'Comment sent'})
+ that.loadComments()
+ this.commentSaving = false
+ }).catch((error) => {
+ that.$q.notify('Error sending your comment')
+ that.loadComments()
+ this.commentSaving = false
+ console.error(error)
+ })
+ }
}
}
}
diff --git a/src/pages/UploadList.vue b/src/pages/UploadList.vue
index a37d8a1..b90fce1 100644
--- a/src/pages/UploadList.vue
+++ b/src/pages/UploadList.vue
@@ -20,15 +20,8 @@
small
outline
icon="fa-info-circle"
- label="Details"
+ label="Show"
@click="$router.push({name: 'upload-detail', params: {uploadId: props.row._id}})" />
- <q-btn color="negative"
- outline
- small
- icon="fa-trash"
- label="Delete"
- v-if="$route.params.uploadId !== props.row._id && props.row.author.username === $store.state.user.decodedToken.username"
- @click="deleteUpload(props.row)" />
</q-td>
<q-td slot='body-cell-voting' slot-scope="props" :props='props'>
{{ props.value.sum }} <i class="fa" :class="{'fa-caret-up text-positive': props.value.sum > 0, 'fa-caret-down text-negative': props.value.sum < 0, 'fa-sort text-dark': props.value.sum === 0}"></i>