Use bus and constants icons
This commit is contained in:
parent
95fa082b94
commit
271dd81d9e
|
@ -0,0 +1,14 @@
|
||||||
|
import Vue from 'vue'
|
||||||
|
import { Component, Prop } from 'vue-property-decorator'
|
||||||
|
|
||||||
|
export interface IEmit {
|
||||||
|
$emit: (name: string, arg: any) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component
|
||||||
|
export default class LocalBusMixin<O, B extends O & IEmit> extends Vue {
|
||||||
|
|
||||||
|
@Prop(Object)
|
||||||
|
readonly bus!: B
|
||||||
|
|
||||||
|
}
|
|
@ -8,16 +8,20 @@ a.account(target="_blank" :href="account.url")
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Component, Mixins, Prop } from 'vue-property-decorator'
|
import { Component, Mixins, Prop } from 'vue-property-decorator'
|
||||||
|
|
||||||
import ShowMediaMixin from '@/components/ShowMediaMixin'
|
import BusMixin from './BusMixin'
|
||||||
import { ParseEmojisMixin } from './ParseEmojisMixin'
|
import { ParseEmojisMixin } from './ParseEmojisMixin'
|
||||||
import { Account as IAccount } from './Types'
|
import { Account as IAccount } from './Types'
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
export default class Account extends Mixins(ParseEmojisMixin, ShowMediaMixin) {
|
export default class Account extends Mixins(ParseEmojisMixin, BusMixin) {
|
||||||
|
|
||||||
@Prop(Object)
|
@Prop(Object)
|
||||||
readonly account!: IAccount
|
readonly account!: IAccount
|
||||||
|
|
||||||
|
get showMedia() {
|
||||||
|
return this.bus.showMedia
|
||||||
|
}
|
||||||
|
|
||||||
avatarStyle(avatar: string) {
|
avatarStyle(avatar: string) {
|
||||||
return {
|
return {
|
||||||
'background-image': `url(${avatar})`
|
'background-image': `url(${avatar})`
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { Component } from 'vue-property-decorator'
|
||||||
|
|
||||||
|
import LocalBusMixin from '@/components/LocalBusMixin'
|
||||||
|
import { BusOptions } from './Types'
|
||||||
|
|
||||||
|
@Component
|
||||||
|
export default class BusMixin extends LocalBusMixin<BusOptions, any> { }
|
||||||
|
|
||||||
|
export const LocalEvents = {
|
||||||
|
Mark: 'mark',
|
||||||
|
Vote: 'vote',
|
||||||
|
Context: 'context'
|
||||||
|
}
|
|
@ -4,34 +4,34 @@
|
||||||
.header(v-if="hasNotifications") Accueil
|
.header(v-if="hasNotifications") Accueil
|
||||||
success-loadable.list(:loadable="statues")
|
success-loadable.list(:loadable="statues")
|
||||||
template(v-for="status in statues.get()")
|
template(v-for="status in statues.get()")
|
||||||
status(v-if="showStatus(status)" :key="status.id" :status="status" :showMedia="options.showMedia" @mark="onStatusMark" @vote="onPollVote" @context="onShowContext")
|
status(v-if="showStatus(status)" :key="status.id" :status="status" :bus="bus")
|
||||||
.status(v-show="statues.loadingMore")
|
.status(v-show="statues.loadingMore")
|
||||||
.service-loader
|
.service-loader
|
||||||
|
|
||||||
.context(v-if="hasContext")
|
.context(v-if="hasContext")
|
||||||
.header(@click="closeContext")
|
.header(@click="closeContext")
|
||||||
| Context
|
| Context
|
||||||
span.date(@click.stop.prevent="closeContext") ❌
|
span.date(@click.stop.prevent="closeContext") {{ icons.close }}
|
||||||
.list
|
.list
|
||||||
.ancestors
|
.ancestors
|
||||||
template(v-if="targetContext.isSuccess")
|
template(v-if="targetContext.isSuccess")
|
||||||
status(v-for="status in targetContext.get().ancestors" :key="status.id" :status="status" :showMedia="options.showMedia" @mark="onStatusMark" @vote="onPollVote" @context="onShowContext")
|
status(v-for="status in targetContext.get().ancestors" :key="status.id" :status="status" :bus="bus")
|
||||||
.service-loader(v-else)
|
.service-loader(v-else)
|
||||||
status.selected(:status="targetStatus" :showMedia="options.showMedia" @mark="onStatusMark" @vote="onPollVote" @context="closeContext")
|
status.selected(:status="targetStatus" :bus="bus")
|
||||||
.descendants
|
.descendants
|
||||||
template(v-if="targetContext.isSuccess")
|
template(v-if="targetContext.isSuccess")
|
||||||
status(v-for="status in targetContext.get().descendants" :key="status.id" :status="status" :showMedia="options.showMedia" @mark="onStatusMark" @vote="onPollVote" @context="onShowContext")
|
status(v-for="status in targetContext.get().descendants" :key="status.id" :status="status" :bus="bus")
|
||||||
.service-loader(v-else)
|
.service-loader(v-else)
|
||||||
|
|
||||||
.notifications(v-if="hasNotifications")
|
.notifications(v-if="hasNotifications")
|
||||||
.header
|
.header
|
||||||
| Notifications
|
| Notifications
|
||||||
span.date(@click.stop.prevent="onNotificationsClear") ❌
|
span.date(@click.stop.prevent="onNotificationsClear") {{ icons.close }}
|
||||||
.list
|
.list
|
||||||
notification(v-for="notification in notifications.get()" :key="notification.id" :notification="notification"
|
notification(v-for="notification in notifications.get()" :key="notification.id" :notification="notification"
|
||||||
:showMedia="options.showMedia" @dismiss="onNotificationDismiss" @mark="onStatusMark" @vote="onPollVote" @context="onShowContext")
|
@dismiss="onNotificationDismiss" :bus="bus")
|
||||||
|
|
||||||
.compose-toggle(@click="showCompose = !showCompose") 🖉
|
.compose-toggle(@click="showCompose = !showCompose") {{ icons.compose }}
|
||||||
.emoji-list(v-if="options.showMedia" v-show="showCompose && showEmojis")
|
.emoji-list(v-if="options.showMedia" v-show="showCompose && showEmojis")
|
||||||
img.emoji(v-for="emoji in emojis.get()" @click="addEmoji(emoji.shortcode)" :src="emoji.static_url" :alt="emoji.shortcode" :title="emoji.shortcode")
|
img.emoji(v-for="emoji in emojis.get()" @click="addEmoji(emoji.shortcode)" :src="emoji.static_url" :alt="emoji.shortcode" :title="emoji.shortcode")
|
||||||
.compose(v-show="showCompose")
|
.compose(v-show="showCompose")
|
||||||
|
@ -48,26 +48,26 @@
|
||||||
input(v-show="compose.sensitive" v-model="compose.spoiler_text" placeholder="content warning")
|
input(v-show="compose.sensitive" v-model="compose.spoiler_text" placeholder="content warning")
|
||||||
.visibility
|
.visibility
|
||||||
select(v-model="compose.visibility")
|
select(v-model="compose.visibility")
|
||||||
option(value="public") ◍
|
option(v-for="(icon, value) in visibilities" :value="value") {{ icon }}
|
||||||
option(value="unlisted") 👁
|
|
||||||
option(value="private") ⚿
|
|
||||||
option(value="direct") ✉
|
|
||||||
span.note {{ compose.visibility }}
|
span.note {{ compose.visibility }}
|
||||||
button(@click="sendStatus") Toot
|
button(@click="sendStatus") Toot
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import axios, { AxiosResponse } from 'axios'
|
import axios, { AxiosResponse } from 'axios'
|
||||||
import { Component, Mixins, Prop } from 'vue-property-decorator'
|
import { Component, Mixins, Prop, Vue, Watch } from 'vue-property-decorator'
|
||||||
|
|
||||||
|
import LocalBusMixin from '@/components/LocalBusMixin'
|
||||||
import ServiceClient from '@/components/ServiceClient'
|
import ServiceClient from '@/components/ServiceClient'
|
||||||
import Lists from '@/helpers/lists/Lists'
|
import Lists from '@/helpers/lists/Lists'
|
||||||
import AxiosLoadable from '@/helpers/loadable/AxiosLoadable'
|
import AxiosLoadable from '@/helpers/loadable/AxiosLoadable'
|
||||||
import AxiosLoadableMore from '@/helpers/loadable/AxiosLoadableMore'
|
import AxiosLoadableMore from '@/helpers/loadable/AxiosLoadableMore'
|
||||||
|
import { LocalEvents } from './BusMixin'
|
||||||
|
import { Icons, Visibility } from './Icons'
|
||||||
import { AUTH, getHeaders, getRest } from './Mastodon.vue'
|
import { AUTH, getHeaders, getRest } from './Mastodon.vue'
|
||||||
import Notification from './Notification.vue'
|
import Notification from './Notification.vue'
|
||||||
import Status from './Status.vue'
|
import Status from './Status.vue'
|
||||||
import { Context, Emoji, MarkStatus, Notification as INotification, Options, Poll, PollVote, Status as IStatus, StatusPost, TimelineType } from './Types'
|
import { BusOptions, Context, Emoji, MarkStatus, Notification as INotification, Options, Poll, PollVote, Status as IStatus, StatusPost, TimelineType } from './Types'
|
||||||
|
|
||||||
const STREAMS = {
|
const STREAMS = {
|
||||||
home: 'user',
|
home: 'user',
|
||||||
|
@ -97,6 +97,11 @@ export default class Client extends Mixins<ServiceClient<Options>>(ServiceClient
|
||||||
}
|
}
|
||||||
showEmojis = false // MAYBE: show tabs with unicode emoticons
|
showEmojis = false // MAYBE: show tabs with unicode emoticons
|
||||||
|
|
||||||
|
bus = new Vue({ data: {
|
||||||
|
showMedia: this.options.showMedia,
|
||||||
|
showCounts: this.options.showCounts
|
||||||
|
} })
|
||||||
|
|
||||||
get hasNotifications() {
|
get hasNotifications() {
|
||||||
if(!this.notifications.isSuccess) {
|
if(!this.notifications.isSuccess) {
|
||||||
return false
|
return false
|
||||||
|
@ -114,12 +119,31 @@ export default class Client extends Mixins<ServiceClient<Options>>(ServiceClient
|
||||||
return this.targetStatus && !this.targetContext.hasError
|
return this.targetStatus && !this.targetContext.hasError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get visibilities() {
|
||||||
|
return Visibility
|
||||||
|
}
|
||||||
|
|
||||||
|
get icons() {
|
||||||
|
return Icons
|
||||||
|
}
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
this.$watch('options.timeline', this.init, { immediate: true })
|
new Map<string, (arg: any) => void>([
|
||||||
|
[ LocalEvents.Mark, this.onStatusMark ],
|
||||||
|
[ LocalEvents.Vote, this.onPollVote ],
|
||||||
|
[ LocalEvents.Context, this.onHandleContext ]
|
||||||
|
]).forEach((handler, name) => this.bus.$on(name, handler))
|
||||||
|
|
||||||
this.notifications.load(this.get<INotification[]>('/notifications'))
|
this.notifications.load(this.get<INotification[]>('/notifications'))
|
||||||
this.emojis.load(this.get<Emoji[]>('/custom_emojis'), res => Lists.sort(res.data, e => e.shortcode, Lists.stringCompare))
|
this.emojis.load(this.get<Emoji[]>('/custom_emojis'), res => Lists.sort(res.data, e => e.shortcode, Lists.stringCompare))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Watch('options', { deep: true })
|
||||||
|
change(o: any) {
|
||||||
|
Object.keys(this.bus.$data).forEach(key => this.bus.$data[key] = o[key])
|
||||||
|
}
|
||||||
|
|
||||||
|
@Watch('options.timeline', { immediate: true })
|
||||||
init() {
|
init() {
|
||||||
this.statues.load(this.getTimeline())
|
this.statues.load(this.getTimeline())
|
||||||
this.setupStream()
|
this.setupStream()
|
||||||
|
@ -190,7 +214,12 @@ export default class Client extends Mixins<ServiceClient<Options>>(ServiceClient
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
onShowContext(status: IStatus) {
|
onHandleContext(status: IStatus) {
|
||||||
|
if(this.targetStatus && this.targetStatus.id === status.id) {
|
||||||
|
this.closeContext()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
this.statues.with(sts => {
|
this.statues.with(sts => {
|
||||||
this.targetStatus = status
|
this.targetStatus = status
|
||||||
this.targetContext.load(this.get(`/statuses/${status.id}/context`), undefined, true)
|
this.targetContext.load(this.get(`/statuses/${status.id}/context`), undefined, true)
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
export const Visibility = {
|
||||||
|
public: '◍',
|
||||||
|
unlisted: '👁',
|
||||||
|
private: '⚿',
|
||||||
|
direct: '✉'
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Notification = {
|
||||||
|
mention: '✉',
|
||||||
|
reblog: '⟳',
|
||||||
|
favourite: '⚝',
|
||||||
|
follow: '👁'
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Icons = {
|
||||||
|
compose: '🖉',
|
||||||
|
close: '❌',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Context = {
|
||||||
|
full: '⮃',
|
||||||
|
up: '⮥',
|
||||||
|
down: '⮦',
|
||||||
|
no: '⭿'
|
||||||
|
}
|
|
@ -5,13 +5,14 @@
|
||||||
| {{ serviceName }}:
|
| {{ serviceName }}:
|
||||||
loadable-inline(:loadable="account")
|
loadable-inline(:loadable="account")
|
||||||
template(#success)
|
template(#success)
|
||||||
span(v-html="parseEmojis(account.data.display_name, account.data.emojis, params.showMedia) + '@' + server", params.showMedia)
|
span(v-html="parseEmojis(account.data.display_name, account.data.emojis, params.showMedia) + '@' + server")
|
||||||
template(#settings)
|
template(#settings)
|
||||||
setting-boolean(:id="'reconnect'" :title="'Reconnect'" :value="params.reconnect" @change="saveOptionCouple")
|
setting-boolean(:id="'reconnect'" :title="'Reconnect'" :value="params.reconnect" @change="saveOptionCouple")
|
||||||
setting-boolean(:id="'reblog'" :title="'Show reblogs'" :value="params.reblog" @change="saveOptionCouple")
|
setting-boolean(:id="'reblog'" :title="'Show reblogs'" :value="params.reblog" @change="saveOptionCouple")
|
||||||
setting-boolean(:id="'reply'" :title="'Show replies'" :value="params.reply" @change="saveOptionCouple")
|
setting-boolean(:id="'reply'" :title="'Show replies'" :value="params.reply" @change="saveOptionCouple")
|
||||||
setting-int(:id="'buffer'" :title="'Buffer size'" :value="params.buffer" @change="saveOptionCouple")
|
setting-int(:id="'buffer'" :title="'Buffer size'" :value="params.buffer" @change="saveOptionCouple")
|
||||||
setting-boolean(:id="'showMedia'" :title="'Show medias'" :value="params.showMedia" @change="saveOptionCouple")
|
setting-boolean(:id="'showMedia'" :title="'Show medias'" :value="params.showMedia" @change="saveOptionCouple")
|
||||||
|
setting-boolean(:id="'showCounts'" :title="'Show counts'" :value="params.showCounts" @change="saveOptionCouple")
|
||||||
setting-select(:id="'timeline'" :title="'Timeline'" :value="params.timeline" @change="saveOptionCouple" :options="['home', 'local', 'public']")
|
setting-select(:id="'timeline'" :title="'Timeline'" :value="params.timeline" @change="saveOptionCouple" :options="['home', 'local', 'public']")
|
||||||
loadable-block.service-content(:loadable="account")
|
loadable-block.service-content(:loadable="account")
|
||||||
template(#success)
|
template(#success)
|
||||||
|
@ -58,7 +59,7 @@ export default class Mastodon extends Mixins<AccountService<Account, object>>(Ac
|
||||||
|
|
||||||
get params(): Options {
|
get params(): Options {
|
||||||
return { timeout: 5000, reconnect: false, buffer: 20, reblog: true, reply: false,
|
return { timeout: 5000, reconnect: false, buffer: 20, reblog: true, reply: false,
|
||||||
showMedia: true, timeline: 'home', ...this.options }
|
showMedia: true, showCounts: true, timeline: 'home', ...this.options }
|
||||||
}
|
}
|
||||||
|
|
||||||
get isSetup() {
|
get isSetup() {
|
||||||
|
|
|
@ -1,55 +1,46 @@
|
||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
.notification
|
.notification
|
||||||
account(:account="notification.account" :showMedia="showMedia")
|
account(:account="notification.account" :bus="bus")
|
||||||
|
|
||||||
span.colored.text-icon.letter(v-if="notification.type == 'mention'") ✉
|
|
||||||
span.colored.text-icon.letter(v-if="notification.type == 'reblog'") ⟳
|
|
||||||
span.colored.text-icon.letter(v-if="notification.type == 'favourite'") ⚝
|
|
||||||
|
|
||||||
|
span.colored.text-icon.letter {{ notificationTypeIcon }}
|
||||||
span.date {{ fromNow(notification.created_at) }}
|
span.date {{ fromNow(notification.created_at) }}
|
||||||
|
|
||||||
.content
|
.content
|
||||||
template(v-if="notification.type == 'follow'") Vous suit
|
template(v-if="notification.type == 'follow'") Vous suit
|
||||||
status.reblog(v-else-if="notification.status" :status="notification.status"
|
status.reblog(v-else-if="notification.status" :status="notification.status"
|
||||||
:showMedia="showMedia" :withAccount="notification.type != 'mention'" @mark="passMark" @vote="passVote" @context="passContext")
|
:withAccount="notification.type != 'mention'" :bus="bus")
|
||||||
|
|
||||||
a.date(@click.stop.prevent="makeDismiss" style="margin-top: -1em") ❌
|
a.date(@click.stop.prevent="makeDismiss" style="margin-top: -1em") {{ closeIcon }}
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Component, Emit, Mixins, Prop } from 'vue-property-decorator'
|
import { Component, Emit, Mixins, Prop } from 'vue-property-decorator'
|
||||||
|
|
||||||
import FromNowMixin from '@/components/FromNowMixin'
|
import FromNowMixin from '@/components/FromNowMixin'
|
||||||
import ShowMediaMixin from '@/components/ShowMediaMixin'
|
|
||||||
import Account from './Account.vue'
|
import Account from './Account.vue'
|
||||||
|
import BusMixin from './BusMixin'
|
||||||
|
import { Icons, Notification as NotificationIcons } from './Icons'
|
||||||
import Status from './Status.vue'
|
import Status from './Status.vue'
|
||||||
import { MarkStatus, Notification as INotification, PollVote, Status as IStatus } from './Types'
|
import { MarkStatus, Notification as INotification, PollVote, Status as IStatus } from './Types'
|
||||||
|
|
||||||
@Component({ components: { Account, Status } })
|
@Component({ components: { Account, Status } })
|
||||||
export default class Notification extends Mixins(ShowMediaMixin, FromNowMixin) {
|
export default class Notification extends Mixins(FromNowMixin, BusMixin) {
|
||||||
|
|
||||||
@Prop(Object)
|
@Prop(Object)
|
||||||
readonly notification!: INotification
|
readonly notification!: INotification
|
||||||
|
|
||||||
|
get notificationTypeIcon() {
|
||||||
|
return NotificationIcons[this.notification.type] || '?'
|
||||||
|
}
|
||||||
|
|
||||||
|
get closeIcon() {
|
||||||
|
return Icons.close
|
||||||
|
}
|
||||||
|
|
||||||
@Emit('dismiss')
|
@Emit('dismiss')
|
||||||
makeDismiss() {
|
makeDismiss() {
|
||||||
return this.notification.id
|
return this.notification.id
|
||||||
}
|
}
|
||||||
|
|
||||||
@Emit('mark')
|
|
||||||
passMark(action: MarkStatus) {
|
|
||||||
return action
|
|
||||||
}
|
|
||||||
|
|
||||||
@Emit('vote')
|
|
||||||
passVote(action: PollVote) {
|
|
||||||
return action
|
|
||||||
}
|
|
||||||
|
|
||||||
@Emit('context')
|
|
||||||
passContext(status: IStatus) {
|
|
||||||
return status
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<template lang="pug">
|
<template lang="pug">
|
||||||
.status
|
.status
|
||||||
account(v-if="withAccount" :account="status.account" :showMedia="showMedia")
|
account(v-if="withAccount" :account="status.account" :bus="bus")
|
||||||
|
|
||||||
span.text-icon.letter(v-if="status.reblog") ⟳
|
span.text-icon.letter(v-if="status.reblog") {{ reblogIcon }}
|
||||||
|
|
||||||
a.date(target="_blank" :href="status.uri") {{ fromNow(status.created_at) }}
|
a.date(target="_blank" :href="status.uri") {{ fromNow(status.created_at) }}
|
||||||
|
|
||||||
|
@ -12,9 +12,10 @@
|
||||||
{{ status.spoiler_text || 'Spoiler' }} {{ status.sensitive ? '→' : '↓' }}
|
{{ status.spoiler_text || 'Spoiler' }} {{ status.sensitive ? '→' : '↓' }}
|
||||||
div(v-if="!status.spoiler_text || !status.sensitive")
|
div(v-if="!status.spoiler_text || !status.sensitive")
|
||||||
.text(v-html="parseEmojis(status.content, status.emojis, showMedia)")
|
.text(v-html="parseEmojis(status.content, status.emojis, showMedia)")
|
||||||
|
|
||||||
.poll(v-if="status.poll")
|
.poll(v-if="status.poll")
|
||||||
.date {{ fromNow(status.poll.expires_at) }}
|
.date {{ fromNow(status.poll.expires_at) }}
|
||||||
form.options(@submit.prevent="makeVote(status, $event.target.elements)")
|
form.options(@submit.prevent="makeVote($event.target.elements)")
|
||||||
.option(v-for="option in status.poll.options")
|
.option(v-for="option in status.poll.options")
|
||||||
input(v-if="!status.poll.expired && !status.poll.voted" :type="status.poll.multiple ? 'checkbox' : 'radio'" :id="status.poll.id + option.title" :value="option.title" :name="status.poll.id")
|
input(v-if="!status.poll.expired && !status.poll.voted" :type="status.poll.multiple ? 'checkbox' : 'radio'" :id="status.poll.id + option.title" :value="option.title" :name="status.poll.id")
|
||||||
label(:for="status.poll.id + option.title")
|
label(:for="status.poll.id + option.title")
|
||||||
|
@ -23,12 +24,14 @@
|
||||||
button(v-if="status.poll.voted") voted
|
button(v-if="status.poll.voted") voted
|
||||||
button(v-else-if="status.poll.expired") expired
|
button(v-else-if="status.poll.expired") expired
|
||||||
input(v-else type="submit" value="vote")
|
input(v-else type="submit" value="vote")
|
||||||
|
|
||||||
a.media(v-for="media in status.media_attachments" :href="media.url" target="_blank")
|
a.media(v-for="media in status.media_attachments" :href="media.url" target="_blank")
|
||||||
template(v-if="showMedia")
|
template(v-if="bus.showMedia")
|
||||||
img(v-if="media.type == 'image' || media.type == 'gifv'" :src="media.preview_url" :alt="media.description" :title="media.description")
|
img(v-if="media.type == 'image' || media.type == 'gifv'" :src="media.preview_url" :alt="media.description" :title="media.description")
|
||||||
template(v-else) Wrong type
|
template(v-else) Wrong type
|
||||||
.gif(v-if="media.type == 'gifv'") GIF
|
.gif(v-if="media.type == 'gifv'") GIF
|
||||||
template(v-else) Hidden media {{ media.description }}
|
template(v-else) Hidden media {{ media.description }}
|
||||||
|
|
||||||
a.card(v-if="status.card" :href="status.card.url" target="_blank")
|
a.card(v-if="status.card" :href="status.card.url" target="_blank")
|
||||||
a.provider(v-if="status.card.provider_name" :src="status.card.provider_url" target="_blank") {{ status.card.provider_name }}
|
a.provider(v-if="status.card.provider_name" :src="status.card.provider_url" target="_blank") {{ status.card.provider_name }}
|
||||||
.title {{ status.card.title }}
|
.title {{ status.card.title }}
|
||||||
|
@ -36,38 +39,29 @@
|
||||||
template(v-if="status.card.image")
|
template(v-if="status.card.image")
|
||||||
img(v-if="showMedia" :src="status.card.image")
|
img(v-if="showMedia" :src="status.card.image")
|
||||||
a(v-else-if="status.card.type == 'photo'" :src="status.card.image" target="_blank") Hidden media
|
a(v-else-if="status.card.type == 'photo'" :src="status.card.image" target="_blank") Hidden media
|
||||||
status.reblog(v-else :status="status.reblog" :showMedia="showMedia" @mark="passMark" @vote="passVote" @context="passContext")
|
|
||||||
|
status.reblog(v-else :status="status.reblog" :bus="bus")
|
||||||
|
|
||||||
.meta(v-if="!status.reblog")
|
.meta(v-if="!status.reblog")
|
||||||
a.replies(@click.stop.prevent="makeReply(status)")
|
status-meta(v-for="meta in metas" :key="meta.name" :meta="meta" :bus="bus")
|
||||||
span.text-icon ✉
|
a {{ statusVisibilityIcon }}
|
||||||
| {{ status.replies_count }}
|
a.fil(@click.stop.prevent="showContext")
|
||||||
a.reblogs(:class="{ colored: status.reblogged }" @click.stop.prevent="makeReblog(status)")
|
| {{ contextIcon }}
|
||||||
span.text-icon ⟳
|
|
||||||
| {{ status.reblogs_count }}
|
|
||||||
a.favourites(:class="{ colored: status.favourited }" @click.stop.prevent="makeFav(status)")
|
|
||||||
span.text-icon ⚝
|
|
||||||
| {{ status.favourites_count }}
|
|
||||||
a.visibility
|
|
||||||
template(v-if="status.visibility == 'public'") ◍
|
|
||||||
template(v-else-if="status.visibility == 'unlisted'") 👁
|
|
||||||
template(v-else-if="status.visibility == 'private'") ⚿
|
|
||||||
template(v-else-if="status.visibility == 'direct'") ✉
|
|
||||||
a.fil(@click.stop.prevent="passContext(status)")
|
|
||||||
span.text-icon ⮃
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Component, Emit, Mixins, Prop } from 'vue-property-decorator'
|
import { Component, Emit, Mixins, Prop } from 'vue-property-decorator'
|
||||||
|
|
||||||
import FromNowMixin from '@/components/FromNowMixin'
|
import FromNowMixin from '@/components/FromNowMixin'
|
||||||
import ShowMediaMixin from '@/components/ShowMediaMixin'
|
|
||||||
import Account from './Account.vue'
|
import Account from './Account.vue'
|
||||||
|
import BusMixin, { LocalEvents } from './BusMixin'
|
||||||
|
import { Context, Notification, Visibility } from './Icons'
|
||||||
import { ParseEmojisMixin } from './ParseEmojisMixin'
|
import { ParseEmojisMixin } from './ParseEmojisMixin'
|
||||||
|
import StatusMeta from './StatusMeta.vue'
|
||||||
import { Card, MarkStatus, MarkStatusType, Poll, PollVote, Status as IStatus } from './Types'
|
import { Card, MarkStatus, MarkStatusType, Poll, PollVote, Status as IStatus } from './Types'
|
||||||
|
|
||||||
@Component({ components: { Account } })
|
@Component({ components: { Account, StatusMeta } })
|
||||||
export default class Status extends Mixins(ParseEmojisMixin, ShowMediaMixin, FromNowMixin) {
|
export default class Status extends Mixins(ParseEmojisMixin, FromNowMixin, BusMixin) {
|
||||||
|
|
||||||
@Prop(Object)
|
@Prop(Object)
|
||||||
readonly status!: IStatus
|
readonly status!: IStatus
|
||||||
|
@ -75,44 +69,61 @@ export default class Status extends Mixins(ParseEmojisMixin, ShowMediaMixin, Fro
|
||||||
@Prop({ type: Boolean, default: true })
|
@Prop({ type: Boolean, default: true })
|
||||||
readonly withAccount!: boolean
|
readonly withAccount!: boolean
|
||||||
|
|
||||||
@Emit('mark')
|
get statusVisibilityIcon() {
|
||||||
passMark(action: MarkStatus) {
|
return Visibility[this.status.visibility] || '?'
|
||||||
return action
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Emit('vote')
|
get reblogIcon() {
|
||||||
passVote(action: PollVote) {
|
return Notification.reblog
|
||||||
return action
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Emit('context')
|
get contextIcon() {
|
||||||
passContext(status: IStatus) {
|
if(this.status.in_reply_to_id) {
|
||||||
return status
|
return Context[this.status.replies_count ? 'full' : 'up']
|
||||||
}
|
} else {
|
||||||
|
return Context[this.status.replies_count ? 'down' : 'no']
|
||||||
makeVote(status: IStatus, elements: HTMLInputElement[]) {
|
|
||||||
const choices = Object.values(elements).filter(e => e.checked).map(e => e.value)
|
|
||||||
if(choices.length > 0) {
|
|
||||||
this.passVote({ id: status.id, poll: status.poll!.id, choices })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
makeMark(status: IStatus, action: string, undo: boolean) {
|
get showMedia() {
|
||||||
this.passMark({
|
return this.bus.$data.showMedia
|
||||||
id: status.id, type: (undo ? 'un' : '') + action as MarkStatusType
|
}
|
||||||
|
|
||||||
|
get metas() {
|
||||||
|
return [
|
||||||
|
{ name: 'reply', click: this.makeReply, active: false, icon: Notification.mention, count: this.status.replies_count },
|
||||||
|
{ name: 'reblog', click: this.makeReblog, active: this.status.reblogged, icon: Notification.reblog, count: this.status.reblogs_count },
|
||||||
|
{ name: 'fav', click: this.makeFav, active: this.status.favourited, icon: Notification.favourite, count: this.status.favourites_count }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
makeVote(elements: HTMLInputElement[]) {
|
||||||
|
const choices = Object.values(elements).filter(e => e.checked).map(e => e.value)
|
||||||
|
if(choices.length > 0) {
|
||||||
|
this.bus.$emit(LocalEvents.Vote, { id: this.status.id, poll: this.status.poll!.id, choices })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
makeMark(action: string, undo: boolean) {
|
||||||
|
this.bus.$emit(LocalEvents.Mark, {
|
||||||
|
id: this.status.id, type: (undo ? 'un' : '') + action as MarkStatusType
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
makeReblog(status: IStatus) {
|
makeReblog() {
|
||||||
this.makeMark(status, 'reblog', status.reblogged)
|
this.makeMark('reblog', this.status.reblogged)
|
||||||
}
|
}
|
||||||
|
|
||||||
makeFav(status: IStatus) {
|
makeFav() {
|
||||||
this.makeMark(status, 'favourite', status.favourited)
|
this.makeMark('favourite', this.status.favourited)
|
||||||
}
|
}
|
||||||
|
|
||||||
makeReply(status: IStatus) {
|
showContext() {
|
||||||
throw status.id // TODO:
|
this.bus.$emit(LocalEvents.Context, this.status)
|
||||||
|
}
|
||||||
|
|
||||||
|
makeReply() {
|
||||||
|
throw this // TODO:
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
<template lang="pug">
|
||||||
|
a(:class="{ colored: meta.active }" @click.stop.prevent="meta.click")
|
||||||
|
span.text-icon {{ meta.icon }}
|
||||||
|
template(v-if="showCounts") {{ meta.count }}
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { Component, Mixins, Prop } from 'vue-property-decorator'
|
||||||
|
|
||||||
|
import BusMixin from './BusMixin'
|
||||||
|
|
||||||
|
@Component
|
||||||
|
export default class StatusMeta extends Mixins(BusMixin) {
|
||||||
|
|
||||||
|
@Prop(Object)
|
||||||
|
readonly meta!: object
|
||||||
|
|
||||||
|
get showCounts() {
|
||||||
|
return this.bus.$data.showCounts
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -11,13 +11,17 @@ export interface Account {
|
||||||
|
|
||||||
export type TimelineType = 'home' | 'local' | 'public'
|
export type TimelineType = 'home' | 'local' | 'public'
|
||||||
|
|
||||||
export interface Options {
|
export interface BusOptions {
|
||||||
|
showMedia: boolean
|
||||||
|
showCounts: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Options extends BusOptions {
|
||||||
timeout: number
|
timeout: number
|
||||||
reconnect: boolean
|
reconnect: boolean
|
||||||
buffer: number
|
buffer: number
|
||||||
reblog: boolean
|
reblog: boolean
|
||||||
reply: boolean
|
reply: boolean
|
||||||
showMedia: boolean
|
|
||||||
timeline: TimelineType
|
timeline: TimelineType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,10 +103,11 @@ export interface Context {
|
||||||
descendants: Status[]
|
descendants: Status[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type NotificationType = 'follow' | 'mention' | 'reblog' | 'favourite'
|
||||||
export interface Notification {
|
export interface Notification {
|
||||||
id: number
|
id: number
|
||||||
account: Account
|
account: Account
|
||||||
type: string
|
type: NotificationType
|
||||||
created_at: string
|
created_at: string
|
||||||
status?: Status
|
status?: Status
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue