refs #874 Show voted polls with percentage in timeline
This commit is contained in:
parent
3d862068c0
commit
369ff3097b
|
@ -1,11 +1,22 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="poll">
|
<div class="poll">
|
||||||
<ul class="poll-list" v-if="poll">
|
<ul class="poll-list" v-if="poll">
|
||||||
<li v-for="(option, id) in poll.options" v-bind:key="id">
|
<template v-if="poll.voted">
|
||||||
<el-radio v-model="pollRadio" :label="option.title">{{ option.title }}</el-radio>
|
<li class="voted" v-for="(option, id) in poll.options" v-bind:key="id">
|
||||||
|
<span class="progress-bar" :style="progress(option.votes_count * 100 / poll.votes_count)"></span>
|
||||||
|
<label class="text">
|
||||||
|
<span class="percentage">{{ option.votes_count * 100 / poll.votes_count }}%</span>
|
||||||
|
<span>{{ option.title }}</span>
|
||||||
|
</label>
|
||||||
</li>
|
</li>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<li class="not-voted" v-for="(option, id) in poll.options" v-bind:key="id">
|
||||||
|
<el-radio v-model="pollRadio" :label="id">{{ option.title }}</el-radio>
|
||||||
|
</li>
|
||||||
|
</template>
|
||||||
</ul>
|
</ul>
|
||||||
<el-button type="success" @click="vote" :disabled="pollRadio === null">Vote</el-button>
|
<el-button type="success" @click="vote" v-if="!poll.voted" :disabled="pollRadio === null">Vote</el-button>
|
||||||
{{ poll.votes_count }} votes,
|
{{ poll.votes_count }} votes,
|
||||||
until {{ parseDatetime(poll.expires_at, now) }}
|
until {{ parseDatetime(poll.expires_at, now) }}
|
||||||
</div>
|
</div>
|
||||||
|
@ -49,6 +60,9 @@ export default {
|
||||||
if (this.pollRadio !== null) {
|
if (this.pollRadio !== null) {
|
||||||
this.$emit('vote', [this.pollRadio])
|
this.$emit('vote', [this.pollRadio])
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
progress(percent) {
|
||||||
|
return `width: ${percent}%`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,7 +75,31 @@ export default {
|
||||||
padding-left: 16px;
|
padding-left: 16px;
|
||||||
|
|
||||||
li {
|
li {
|
||||||
|
position: relative;
|
||||||
margin: 4px 0;
|
margin: 4px 0;
|
||||||
|
line-height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.voted {
|
||||||
|
max-width: 200px;
|
||||||
|
|
||||||
|
.progress-bar {
|
||||||
|
position: absolute;
|
||||||
|
display: inline-block;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #409eff;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
padding-left: 8px;
|
||||||
|
|
||||||
|
.percentage {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -199,7 +199,8 @@ export default {
|
||||||
showContent: this.$store.state.App.ignoreCW,
|
showContent: this.$store.state.App.ignoreCW,
|
||||||
showAttachments: this.$store.state.App.ignoreNFSW,
|
showAttachments: this.$store.state.App.ignoreNFSW,
|
||||||
hideAllAttachments: this.$store.state.App.hideAllAttachments,
|
hideAllAttachments: this.$store.state.App.hideAllAttachments,
|
||||||
now: Date.now()
|
now: Date.now(),
|
||||||
|
pollResponse: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
|
@ -279,7 +280,11 @@ export default {
|
||||||
return !this.spoilered || this.showContent
|
return !this.spoilered || this.showContent
|
||||||
},
|
},
|
||||||
poll: function() {
|
poll: function() {
|
||||||
|
if (this.pollResponse) {
|
||||||
|
return this.pollResponse
|
||||||
|
} else {
|
||||||
return this.originalMessage.poll
|
return this.originalMessage.poll
|
||||||
|
}
|
||||||
},
|
},
|
||||||
sensitive: function() {
|
sensitive: function() {
|
||||||
return (this.hideAllAttachments || this.originalMessage.sensitive) && this.mediaAttachments.length > 0
|
return (this.hideAllAttachments || this.originalMessage.sensitive) && this.mediaAttachments.length > 0
|
||||||
|
@ -555,8 +560,12 @@ export default {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
vote(choices) {
|
async vote(choices) {
|
||||||
console.log(choices)
|
const res = await this.$store.dispatch('organisms/Toot/vote', {
|
||||||
|
id: this.poll.id,
|
||||||
|
choices: choices
|
||||||
|
})
|
||||||
|
this.pollResponse = res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
import Mastodon, { Response, Status, Account } from 'megalodon'
|
import Mastodon, { Response, Status, Account, Poll } from 'megalodon'
|
||||||
import { ipcRenderer } from 'electron'
|
import { ipcRenderer } from 'electron'
|
||||||
import { Module, ActionTree } from 'vuex'
|
import { Module, ActionTree } from 'vuex'
|
||||||
import { RootState } from '@/store'
|
import { RootState } from '@/store'
|
||||||
|
|
||||||
|
type VoteParam = {
|
||||||
|
id: string
|
||||||
|
choices: Array<string>
|
||||||
|
}
|
||||||
|
|
||||||
export type TootState = {}
|
export type TootState = {}
|
||||||
|
|
||||||
const state = (): TootState => ({})
|
const state = (): TootState => ({})
|
||||||
|
@ -45,6 +50,13 @@ const actions: ActionTree<TootState, RootState> = {
|
||||||
block: async ({ rootState }, account: Account) => {
|
block: async ({ rootState }, account: Account) => {
|
||||||
const client = new Mastodon(rootState.TimelineSpace.account.accessToken!, rootState.TimelineSpace.account.baseURL + '/api/v1')
|
const client = new Mastodon(rootState.TimelineSpace.account.accessToken!, rootState.TimelineSpace.account.baseURL + '/api/v1')
|
||||||
return client.post(`/accounts/${account.id}/block`)
|
return client.post(`/accounts/${account.id}/block`)
|
||||||
|
},
|
||||||
|
vote: async({ rootState }, params: VoteParam): Promise<Poll> => {
|
||||||
|
const client = new Mastodon(rootState.TimelineSpace.account.accessToken!, rootState.TimelineSpace.account.baseURL + '/api/v1')
|
||||||
|
const res = await client.post<Poll>(`/polls/${params.id}/votes`, {
|
||||||
|
choices: params.choices
|
||||||
|
})
|
||||||
|
return res.data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue