forked from Mirrors/elk
727d05915f
* fix: rtl arrows on settings page * fix: border on settings page for RTL languages * fix: RTL fixes for logo, search box and logout icon * fix: RTL layout bugs in conversations * chore: remove rtl setting icon * improve arabic locale * add new entries to arabic locale * chore: include number format * fix: RTL layout on several pages * fix: RTL layout of account header and sign in modal * fix: always display account handle in LTR * fix: move character counter in publish widget to left side for RTL * fix: remove border-ss-none unocss rule * fix: many RTL fixes * fix: RTL fixes for many pages * fix: use viewer's direction in all content * chore: use new arabic plural rules * chore: flip arrow on main content header * chore: fix StatusPoll and show_new_items for zh-TW * chore: StatusPoll tooltip on bottom * chore: add `en` variants to i18n conf * chore: update entry to use new plural rule * fix: automatic content direction for status * fix: direction for account handle * fix: direction of polls Co-authored-by: userquin <userquin@gmail.com> Co-authored-by: Jean-Paul Khawam <jeanpaulkhawam@protonmail.com> Co-authored-by: Daniel Roe <daniel@roe.dev>
81 lines
3.3 KiB
Vue
81 lines
3.3 KiB
Vue
<script setup lang="ts">
|
|
import type { Status } from 'masto'
|
|
|
|
const { status } = defineProps<{
|
|
status: Status
|
|
}>()
|
|
const poll = reactive({ ...status.poll! })
|
|
|
|
function toPercentage(num: number) {
|
|
const percentage = 100 * num
|
|
return `${percentage.toFixed(1).replace(/\.?0+$/, '')}%`
|
|
}
|
|
const timeAgoOptions = useTimeAgoOptions()
|
|
const expiredTimeAgo = useTimeAgo(poll.expiresAt!, timeAgoOptions)
|
|
const expiredTimeFormatted = useFormattedDateTime(poll.expiresAt!)
|
|
const { formatHumanReadableNumber, formatNumber, formatPercentage, forSR } = useHumanReadableNumber()
|
|
|
|
const masto = useMasto()
|
|
async function vote(e: Event) {
|
|
const formData = new FormData(e.target as HTMLFormElement)
|
|
const choices = formData.getAll('choices') as string[]
|
|
|
|
// Update the poll optimistically
|
|
for (const [index, option] of poll.options.entries()) {
|
|
if (choices.includes(String(index)))
|
|
option.votesCount = (option.votesCount || 0) + 1
|
|
}
|
|
poll.voted = true
|
|
poll.votesCount++
|
|
poll.votersCount = (poll.votersCount || 0) + 1
|
|
cacheStatus({ ...status, poll }, undefined, true)
|
|
|
|
await masto.poll.vote(poll.id, { choices })
|
|
}
|
|
|
|
const votersCount = $computed(() => poll.votersCount ?? 0)
|
|
const votersCountHR = $computed(() => formatHumanReadableNumber(votersCount))
|
|
const votersCountNumber = $computed(() => formatNumber(votersCount))
|
|
const votersCountSR = $computed(() => forSR(votersCount))
|
|
</script>
|
|
|
|
<template>
|
|
<div flex flex-col w-full items-stretch gap-3 dir="auto">
|
|
<form v-if="!poll.voted && !poll.expired" flex flex-col gap-4 accent-primary @click.stop="noop" @submit.prevent="vote">
|
|
<label v-for="(option, index) of poll.options" :key="index" flex items-center gap-2 px-2>
|
|
<input name="choices" :value="index" :type="poll.multiple ? 'checkbox' : 'radio'">
|
|
{{ option.title }}
|
|
</label>
|
|
<button btn-solid>
|
|
{{ $t('action.vote') }}
|
|
</button>
|
|
</form>
|
|
<template v-else>
|
|
<div v-for="(option, index) of poll.options" :key="index" py-1 relative :style="{ '--bar-width': toPercentage((option.votesCount || 0) / poll.votesCount) }">
|
|
<div flex justify-between pb-2 w-full>
|
|
<span inline-flex align-items>
|
|
{{ option.title }}
|
|
<span v-if="poll.voted && poll.ownVotes?.includes(index)" ms-2 mt-1 inline-block i-ri:checkbox-circle-line />
|
|
</span>
|
|
<span text-primary-active> {{ formatPercentage(votersCount > 0 ? (option.votesCount || 0) / votersCount : 0) }}</span>
|
|
</div>
|
|
<div class="bg-gray/40" rounded-l-sm rounded-r-lg h-5px w-full>
|
|
<div bg-primary-active h-full class="w-[var(--bar-width)]" />
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<div text-sm flex="~ inline" gap-x-1>
|
|
<i18n-t keypath="status.poll.count" :plural="votersCount">
|
|
<CommonTooltip v-if="votersCountSR" :content="votersCountNumber" placement="bottom">
|
|
<span aria-hidden="true">{{ votersCountHR }}</span>
|
|
<span sr-only>{{ votersCountNumber }}</span>
|
|
</CommonTooltip>
|
|
<span v-else>{{ votersCountNumber }}</span>
|
|
</i18n-t>
|
|
·
|
|
<CommonTooltip :content="expiredTimeFormatted" class="inline-block" placement="right">
|
|
<time :datetime="poll.expiresAt!">{{ $t(poll.expired ? 'status.poll.finished' : 'status.poll.ends', [expiredTimeAgo]) }}</time>
|
|
</CommonTooltip>
|
|
</div>
|
|
</div>
|
|
</template>
|