refs #3301 Rewrite TimelineSpace/Contents/SideBar/AccountProfile with composition API

This commit is contained in:
AkiraFukushima 2022-06-30 23:20:15 +09:00
parent 5016f992cd
commit 9fdd69ad0a
No known key found for this signature in database
GPG Key ID: B6E51BAC4DE1A957
1 changed files with 176 additions and 146 deletions

View File

@ -8,14 +8,14 @@
role="article" role="article"
aria-label="account profile" aria-label="account profile"
> >
<div class="header-background" v-bind:style="{ backgroundImage: 'url(' + account.header + ')' }"> <div class="header-background" v-bind:style="{ backgroundImage: 'url(' + account?.header + ')' }">
<div class="header"> <div class="header">
<div class="relationship" v-if="relationship !== null && relationship !== '' && !isOwnProfile"> <div class="relationship" v-if="relationship !== null && !isOwnProfile">
<div class="follower-status"> <div class="follower-status">
<el-tag class="status" size="small" v-if="relationship.followed_by">{{ $t('side_bar.account_profile.follows_you') }}</el-tag> <el-tag class="status" size="small" v-if="relationship.followed_by">{{ $t('side_bar.account_profile.follows_you') }}</el-tag>
<el-tag class="status" size="default" v-else>{{ $t('side_bar.account_profile.doesnt_follow_you') }}</el-tag> <el-tag class="status" size="default" v-else>{{ $t('side_bar.account_profile.doesnt_follow_you') }}</el-tag>
</div> </div>
<div class="notify" v-if="relationship !== null && relationship !== '' && !isOwnProfile"> <div class="notify" v-if="relationship !== null && !isOwnProfile">
<div <div
v-if="relationship.notifying" v-if="relationship.notifying"
class="unsubscribe" class="unsubscribe"
@ -31,7 +31,7 @@
</div> </div>
<div class="user-info"> <div class="user-info">
<div class="more" v-if="relationship !== null && relationship !== '' && !isOwnProfile"> <div class="more" v-if="relationship !== null && !isOwnProfile">
<el-popover placement="bottom" width="200" trigger="click" popper-class="account-menu-popper"> <el-popover placement="bottom" width="200" trigger="click" popper-class="account-menu-popper">
<ul class="menu-list"> <ul class="menu-list">
<li role="button" @click="openBrowser(account)"> <li role="button" @click="openBrowser(account)">
@ -62,9 +62,9 @@
</el-popover> </el-popover>
</div> </div>
<div class="icon" role="presentation"> <div class="icon" role="presentation">
<FailoverImg :src="account.avatar" :alt="`Avatar of ${account.username}`" /> <FailoverImg :src="account?.avatar" :alt="`Avatar of ${account?.username}`" />
</div> </div>
<div class="follow-status" v-if="relationship !== null && relationship !== '' && !isOwnProfile"> <div class="follow-status" v-if="relationship !== null && !isOwnProfile">
<div v-if="relationship.following" class="unfollow" @click="unfollow(account)" :title="$t('side_bar.account_profile.unfollow')"> <div v-if="relationship.following" class="unfollow" @click="unfollow(account)" :title="$t('side_bar.account_profile.unfollow')">
<font-awesome-icon icon="user-xmark" size="xl" /> <font-awesome-icon icon="user-xmark" size="xl" />
</div> </div>
@ -79,7 +79,7 @@
<div class="username"> <div class="username">
<bdi v-html="username(account)"></bdi> <bdi v-html="username(account)"></bdi>
</div> </div>
<div class="account">@{{ account.acct }}</div> <div class="account">@{{ account?.acct }}</div>
<div class="note" v-html="note(account)" @click.capture.prevent="noteClick"></div> <div class="note" v-html="note(account)" @click.capture.prevent="noteClick"></div>
</div> </div>
</div> </div>
@ -94,7 +94,7 @@
</dl> </dl>
</div> </div>
<div class="metadata"> <div class="metadata">
<dl v-for="(data, index) in account.fields" :key="index"> <dl v-for="(data, index) in account?.fields" :key="index">
<dt> <dt>
{{ data.name }} {{ data.name }}
</dt> </dt>
@ -102,16 +102,16 @@
</dl> </dl>
</div> </div>
<el-row class="basic-info"> <el-row class="basic-info">
<el-col :span="8" :class="activeTab === 1 ? 'info info-active' : 'info'" @click="changeTab"> <el-col :span="8" :class="activeTab === 1 ? 'info info-active' : 'info'">
<el-button type="text" class="tab" @click="changeTab(1)"> <el-button type="text" class="tab" @click="changeTab(1)">
<div class="title">{{ $t('side_bar.account_profile.toots') }}</div> <div class="title">{{ $t('side_bar.account_profile.toots') }}</div>
<div class="count">{{ account.statuses_count }}</div> <div class="count">{{ account?.statuses_count }}</div>
</el-button> </el-button>
</el-col> </el-col>
<el-col :span="8" :class="activeTab === 2 ? 'info info-active' : 'info'"> <el-col :span="8" :class="activeTab === 2 ? 'info info-active' : 'info'">
<el-button type="text" class="tab" @click="changeTab(2)"> <el-button type="text" class="tab" @click="changeTab(2)">
<div class="title">{{ $t('side_bar.account_profile.follows') }}</div> <div class="title">{{ $t('side_bar.account_profile.follows') }}</div>
<div class="count">{{ account.following_count }}</div> <div class="count">{{ account?.following_count }}</div>
</el-button> </el-button>
</el-col> </el-col>
<el-col :span="8" :class="activeTab === 3 ? 'info info-active' : 'info'"> <el-col :span="8" :class="activeTab === 3 ? 'info info-active' : 'info'">
@ -119,7 +119,7 @@
<div class="title"> <div class="title">
{{ $t('side_bar.account_profile.followers') }} {{ $t('side_bar.account_profile.followers') }}
</div> </div>
<div class="count">{{ account.followers_count }}</div> <div class="count">{{ account?.followers_count }}</div>
</el-button> </el-button>
</el-col> </el-col>
</el-row> </el-row>
@ -131,16 +131,23 @@
</div> </div>
</template> </template>
<script> <script lang="ts">
import { mapState, mapGetters } from 'vuex' import { defineComponent, computed, ref, watch } from 'vue'
import { findLink } from '~/src/renderer/utils/tootParser' import { ElMessage } from 'element-plus'
import emojify from '~/src/renderer/utils/emojify' import { Entity } from 'megalodon'
import Timeline from './AccountProfile/Timeline' import { useI18next } from 'vue3-i18next'
import Follows from './AccountProfile/Follows' import { findLink } from '@/utils/tootParser'
import Followers from './AccountProfile/Followers' import emojify from '@/utils/emojify'
import FailoverImg from '~/src/renderer/components/atoms/FailoverImg' import Timeline from './AccountProfile/Timeline.vue'
import Follows from './AccountProfile/Follows.vue'
import Followers from './AccountProfile/Followers.vue'
import FailoverImg from '@/components/atoms/FailoverImg.vue'
import { useStore } from '@/store'
import { ACTION_TYPES, MUTATION_TYPES } from '@/store/TimelineSpace/Contents/SideBar/AccountProfile'
import { ACTION_TYPES as LIST_MEMBERSHIP_ACTION } from '@/store/TimelineSpace/Modals/ListMembership'
import { ACTION_TYPES as MUTE_ACTION } from '@/store/TimelineSpace/Modals/MuteConfirm'
export default { export default defineComponent({
name: 'account-profile', name: 'account-profile',
components: { components: {
Timeline, Timeline,
@ -148,142 +155,165 @@ export default {
Followers, Followers,
FailoverImg FailoverImg
}, },
data() { setup(_, ctx) {
return { const space = 'TimelineSpace/Contents/SideBar/AccountProfile'
activeTab: 1 const store = useStore()
} const i18n = useI18next()
},
computed: { const activeTab = ref<number>(1)
...mapState({
theme: state => { const theme = computed(() => {
return { return {
'--theme-mask-color': state.App.theme.wrapper_mask_color, '--theme-mask-color': store.state.App.theme.wrapper_mask_color,
'--theme-border-color': state.App.theme.border_color, '--theme-border-color': store.state.App.theme.border_color,
'--theme-primary-color': state.App.theme.primary_color '--theme-primary-color': store.state.App.theme.primary_color
}
} }
}), })
...mapState('TimelineSpace/Contents/SideBar/AccountProfile', { const account = computed(() => store.state.TimelineSpace.Contents.SideBar.AccountProfile.account)
account: state => state.account, const identityProofs = computed(() => store.state.TimelineSpace.Contents.SideBar.AccountProfile.identityProofs)
identityProofs: state => state.identityProofs, const relationship = computed(() => store.state.TimelineSpace.Contents.SideBar.AccountProfile.relationship)
relationship: state => state.relationship, const loading = computed(() => store.state.TimelineSpace.Contents.SideBar.AccountProfile.loading)
loading: state => state.loading, const muting = computed(() => store.state.TimelineSpace.Contents.SideBar.AccountProfile.relationship?.muting)
muting: state => state.relationship && state.relationship.muting, const blocking = computed(() => store.state.TimelineSpace.Contents.SideBar.AccountProfile.relationship?.blocking)
blocking: state => state.relationship && state.relationship.blocking const isOwnProfile = computed(() => store.getters[`${space}/isOwnProfile`])
}),
...mapGetters('TimelineSpace/Contents/SideBar/AccountProfile', ['isOwnProfile']) watch(account, () => {
}, activeTab.value = 1
watch: { })
account: function () { watch(loading, (newVal, _oldVal) => {
this.activeTab = 1 ctx.emit('change-loading', newVal)
}, })
loading: function (newState, _oldState) {
this.$emit('change-loading', newState) const username = (account: Entity.Account) => {
}
},
methods: {
username(account) {
if (account.display_name !== '') { if (account.display_name !== '') {
return emojify(account.display_name, account.emojis) return emojify(account.display_name, account.emojis)
} else { } else {
return account.username return account.username
} }
}, }
note(account) { const note = (account: Entity.Account) => {
return emojify(account.note, account.emojis) return emojify(account.note, account.emojis)
}, }
noteClick(e) { const noteClick = (e: Event) => {
const link = findLink(e.target, 'note') const link = findLink(e.target as HTMLElement, 'note')
if (link !== null) { if (link !== null) {
window.shell.openExternal(link) ;(window as any).shell.openExternal(link)
}
},
follow(account) {
this.$store.commit('TimelineSpace/Contents/SideBar/AccountProfile/changeLoading', true)
try {
this.$store.dispatch('TimelineSpace/Contents/SideBar/AccountProfile/follow', account)
} catch (err) {
this.$message({
message: this.$t('message.follow_error'),
type: 'error'
})
} finally {
this.$store.commit('TimelineSpace/Contents/SideBar/AccountProfile/changeLoading', false)
}
},
unfollow(account) {
this.$store.commit('TimelineSpace/Contents/SideBar/AccountProfile/changeLoading', true)
try {
this.$store.dispatch('TimelineSpace/Contents/SideBar/AccountProfile/unfollow', account)
} catch (err) {
this.$message({
message: this.$t('message.unfollow_error'),
type: 'error'
})
} finally {
this.$store.commit('TimelineSpace/Contents/SideBar/AccountProfile/changeLoading', false)
}
},
changeTab(index) {
this.activeTab = index
},
openBrowser(account) {
window.shell.openExternal(account.url)
},
addToList(account) {
this.$store.dispatch('TimelineSpace/Modals/ListMembership/setAccount', account)
this.$store.dispatch('TimelineSpace/Modals/ListMembership/changeModal', true)
},
confirmMute(account) {
this.$store.dispatch('TimelineSpace/Modals/MuteConfirm/changeAccount', account)
this.$store.dispatch('TimelineSpace/Modals/MuteConfirm/changeModal', true)
},
unmute(account) {
this.$store.dispatch('TimelineSpace/Contents/SideBar/AccountProfile/unmute', account)
},
block(account) {
this.$store.dispatch('TimelineSpace/Contents/SideBar/AccountProfile/block', account)
},
unblock(account) {
this.$store.dispatch('TimelineSpace/Contents/SideBar/AccountProfile/unblock', account)
},
metadataClick(e) {
const link = findLink(e.target, 'metadata')
if (link !== null) {
return window.shell.openExternal(link)
}
},
identityOpen(link) {
return window.shell.openExternal(link)
},
subscribe(account) {
this.$store.commit('TimelineSpace/Contents/SideBar/AccountProfile/changeLoading', true)
try {
this.$store.dispatch('TimelineSpace/Contents/SideBar/AccountProfile/subscribe', account)
} catch (err) {
this.$message({
message: this.$t('message.subscribe_error'),
type: 'error'
})
} finally {
this.$store.commit('TimelineSpace/Contents/SideBar/AccountProfile/changeLoading', false)
}
},
unsubscribe(account) {
this.$store.commit('TimelineSpace/Contents/SideBar/AccountProfile/changeLoading', true)
try {
this.$store.dispatch('TimelineSpace/Contents/SideBar/AccountProfile/unsubscribe', account)
} catch (err) {
this.$message({
message: this.$t('message.unsubscribe_error'),
type: 'error'
})
} finally {
this.$store.commit('TimelineSpace/Contents/SideBar/AccountProfile/changeLoading', false)
} }
} }
const follow = (account: Entity.Account) => {
store.commit(`${space}/${MUTATION_TYPES.CHANGE_LOADING}`, true)
try {
store.dispatch(`${space}/${ACTION_TYPES.FOLLOW}`, account)
} catch (err) {
ElMessage({
message: i18n.t('message.follow_error'),
type: 'error'
})
} finally {
store.commit(`${space}/${MUTATION_TYPES.CHANGE_LOADING}`, false)
}
}
const unfollow = (account: Entity.Account) => {
store.commit(`${space}/${MUTATION_TYPES.CHANGE_LOADING}`, true)
try {
store.dispatch(`${space}/${ACTION_TYPES.UNFOLLOW}`, account)
} catch (err) {
ElMessage({
message: i18n.t('message.unfollow_error'),
type: 'error'
})
} finally {
store.commit(`${space}/${MUTATION_TYPES.CHANGE_LOADING}`, false)
}
}
const changeTab = (payload: number) => {
activeTab.value = payload
}
const openBrowser = (account: Entity.Account) => {
;(window as any).shell.openExternal(account.url)
}
const addToList = (account: Entity.Account) => {
store.dispatch(`TimelineSpace/Modals/ListMembership/${LIST_MEMBERSHIP_ACTION.SET_ACCOUNT}`, account)
store.dispatch(`TimelineSpace/Modals/ListMembership/${LIST_MEMBERSHIP_ACTION.CHANGE_MODAL}`, true)
}
const confirmMute = (account: Entity.Account) => {
store.dispatch(`TimelineSpace/Modals/MuteConfirm/${MUTE_ACTION.CHANGE_ACCOUNT}`, account)
store.dispatch(`TimelineSpace/Modals/MuteConfirm/${MUTE_ACTION.CHANGE_MODAL}`, true)
}
const unmute = (account: Entity.Account) => {
store.dispatch(`${space}/${ACTION_TYPES.UNMUTE}`, account)
}
const block = (account: Entity.Account) => {
store.dispatch(`${space}/${ACTION_TYPES.BLOCK}`, account)
}
const unblock = (account: Entity.Account) => {
store.dispatch(`${space}/${ACTION_TYPES.UNBLOCK}`, account)
}
const metadataClick = (e: Event) => {
const link = findLink(e.target as HTMLElement, 'metadata')
if (link !== null) {
return (window as any).shell.openExternal(link)
}
}
const identityOpen = (link: string) => {
return (window as any).shell.openExternal(link)
}
const subscribe = (account: Entity.Account) => {
store.commit(`${space}/${MUTATION_TYPES.CHANGE_LOADING}`, true)
try {
store.dispatch(`${space}/${ACTION_TYPES.SUBSCRIBE}`, account)
} catch (err) {
ElMessage({
message: i18n.t('message.subscribe_error'),
type: 'error'
})
} finally {
store.commit(`${space}/${MUTATION_TYPES.CHANGE_LOADING}`, false)
}
}
const unsubscribe = (account: Entity.Account) => {
store.commit(`${space}/${MUTATION_TYPES.CHANGE_LOADING}`, true)
try {
store.dispatch(`${space}/${ACTION_TYPES.UNSBSCRIBE}`, account)
} catch (err) {
ElMessage({
message: i18n.t('message.unsubscribe_error'),
type: 'error'
})
} finally {
store.commit(`${space}/${MUTATION_TYPES.CHANGE_LOADING}`, false)
}
}
return {
activeTab,
loading,
account,
relationship,
isOwnProfile,
muting,
blocking,
identityProofs,
theme,
username,
note,
noteClick,
changeTab,
unsubscribe,
subscribe,
openBrowser,
addToList,
unmute,
confirmMute,
unblock,
block,
unfollow,
follow,
metadataClick,
identityOpen
}
} }
} })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>