Fix errors in Vue3

This commit is contained in:
AkiraFukushima 2022-04-19 21:05:32 +09:00
parent 95242cf758
commit 218cb96c3a
No known key found for this signature in database
GPG Key ID: B6E51BAC4DE1A957
24 changed files with 724 additions and 1807 deletions

View File

@ -4,12 +4,8 @@
<el-header> <el-header>
<el-row> <el-row>
<el-col :span="24" class="close"> <el-col :span="24" class="close">
<el-button <el-button type="text" @click="close" class="close-button">
type="text" <font-awesome-icon icon="x-mark"></font-awesome-icon>
:icon="ElIconClose"
@click="close"
class="close-button"
>
</el-button> </el-button>
</el-col> </el-col>
</el-row> </el-row>
@ -37,12 +33,7 @@
<el-input></el-input> <el-input></el-input>
</el-form-item> </el-form-item>
<el-form-item class="submit"> <el-form-item class="submit">
<el-button <el-button type="primary" @click="authorizeSubmit" v-loading="submitting" element-loading-background="rgba(0, 0, 0, 0.8)">
type="primary"
@click="authorizeSubmit"
v-loading="submitting"
element-loading-background="rgba(0, 0, 0, 0.8)"
>
{{ $t('authorize.submit') }} {{ $t('authorize.submit') }}
</el-button> </el-button>
</el-form-item> </el-form-item>
@ -53,27 +44,25 @@
</template> </template>
<script> <script>
import { Close as ElIconClose } from '@element-plus/icons'
export default { export default {
data() { data() {
return { return {
authorizeForm: { authorizeForm: {
code: null, code: null
}, },
submitting: false, submitting: false
ElIconClose,
} }
}, },
name: 'authorize', name: 'authorize',
props: { props: {
url: { url: {
type: String, type: String,
default: '', default: ''
}, },
sns: { sns: {
type: String, type: String,
default: 'mastodon', default: 'mastodon'
}, }
}, },
mounted() { mounted() {
console.log(this.url) console.log(this.url)
@ -84,32 +73,32 @@ export default {
this.$store this.$store
.dispatch('Authorize/submit', { .dispatch('Authorize/submit', {
code: this.authorizeForm.code, code: this.authorizeForm.code,
sns: this.sns, sns: this.sns
}) })
.finally(() => { .finally(() => {
this.submitting = false this.submitting = false
}) })
.then((id) => { .then(id => {
this.$router.push({ path: `/${id}/home` }) this.$router.push({ path: `/${id}/home` })
}) })
.catch((err) => { .catch(err => {
if (err.name === 'DuplicateRecordError') { if (err.name === 'DuplicateRecordError') {
this.$message({ this.$message({
message: this.$t('message.authorize_duplicate_error'), message: this.$t('message.authorize_duplicate_error'),
type: 'error', type: 'error'
}) })
} else { } else {
this.$message({ this.$message({
message: this.$t('message.authorize_error'), message: this.$t('message.authorize_error'),
type: 'error', type: 'error'
}) })
} }
}) })
}, },
close() { close() {
return this.$router.push({ path: '/', query: { redirect: 'home' } }) return this.$router.push({ path: '/', query: { redirect: 'home' } })
}, }
}, }
} }
</script> </script>

View File

@ -18,13 +18,13 @@
v-bind:key="account._id" v-bind:key="account._id"
role="menuitem" role="menuitem"
> >
<el-icon v-if="account.avatar === undefined || account.avatar === null || account.avatar === ''"><el-icon-menu /></el-icon> <font-awesome-icon icon="circle-user" v-if="account.avatar === undefined || account.avatar === null || account.avatar === ''" />
<FailoverImg v-else :src="account.avatar" class="avatar" :title="account.username + '@' + account.domain" /> <FailoverImg v-else :src="account.avatar" class="avatar" :title="account.username + '@' + account.domain" />
<FailoverImg :src="`${account.baseURL}/favicon.ico`" :failoverSrc="`${account.baseURL}/favicon.png`" class="instance-icon" /> <FailoverImg :src="`${account.baseURL}/favicon.ico`" :failoverSrc="`${account.baseURL}/favicon.png`" class="instance-icon" />
<span slot="title">{{ account.domain }}</span> <span slot="title">{{ account.domain }}</span>
</el-menu-item> </el-menu-item>
<el-menu-item index="/login" :title="$t('global_header.add_new_account')" role="menuitem"> <el-menu-item index="/login" :title="$t('global_header.add_new_account')" role="menuitem">
<el-icon><el-icon-plus /></el-icon> <font-awesome-icon icon="plus" />
<span slot="new">New</span> <span slot="new">New</span>
</el-menu-item> </el-menu-item>
</el-menu> </el-menu>
@ -35,16 +35,13 @@
</template> </template>
<script> <script>
import { Menu as ElIconMenu, Plus as ElIconPlus } from '@element-plus/icons'
import { mapState } from 'vuex' import { mapState } from 'vuex'
import FailoverImg from '~/src/renderer/components/atoms/FailoverImg' import FailoverImg from '~/src/renderer/components/atoms/FailoverImg'
import { StreamingError } from '~/src/errors/streamingError' import { StreamingError } from '~/src/errors/streamingError'
export default { export default {
components: { components: {
FailoverImg, FailoverImg
ElIconMenu,
ElIconPlus
}, },
name: 'global-header', name: 'global-header',
computed: { computed: {

View File

@ -3,7 +3,9 @@
<el-header> <el-header>
<el-row> <el-row>
<el-col :span="24" class="close"> <el-col :span="24" class="close">
<el-button type="text" :icon="ElIconClose" @click="close" class="close-button"> </el-button> <el-button type="text" @click="close" class="close-button">
<font-awesome-icon icon="xmark" />
</el-button>
</el-col> </el-col>
</el-row> </el-row>
</el-header> </el-header>
@ -15,16 +17,10 @@
</template> </template>
<script> <script>
import { Close as ElIconClose } from '@element-plus/icons'
import LoginForm from './Login/LoginForm' import LoginForm from './Login/LoginForm'
import { mapState } from 'vuex' import { mapState } from 'vuex'
export default { export default {
data() {
return {
ElIconClose
}
},
name: 'login', name: 'login',
components: { LoginForm }, components: { LoginForm },
computed: { computed: {

View File

@ -6,13 +6,9 @@
<h1>{{ $t('preferences.title') }}</h1> <h1>{{ $t('preferences.title') }}</h1>
</el-col> </el-col>
<el-col :span="1"> <el-col :span="1">
<el-button <el-button type="text" @click="close" class="close-button" role="button">
type="text" <font-awesome-icon icon="xmark" />
:icon="ElIconClose" </el-button>
@click="close"
class="close-button"
role="button"
></el-button>
</el-col> </el-col>
</el-row> </el-row>
</el-header> </el-header>
@ -60,21 +56,15 @@
</template> </template>
<script> <script>
import { Close as ElIconClose } from '@element-plus/icons'
import { mapState } from 'vuex' import { mapState } from 'vuex'
export default { export default {
data() {
return {
ElIconClose,
}
},
name: 'preferences', name: 'preferences',
computed: { computed: {
...mapState({ ...mapState({
primaryColor: (state) => state.App.theme.primary_color, primaryColor: state => state.App.theme.primary_color,
backgroundColor: (state) => state.App.theme.background_color, backgroundColor: state => state.App.theme.background_color
}), })
}, },
methods: { methods: {
close() { close() {
@ -82,8 +72,8 @@ export default {
}, },
activeRoute() { activeRoute() {
return this.$route.path return this.$route.path
}, }
}, }
} }
</script> </script>

View File

@ -17,7 +17,7 @@
<el-table-column :label="$t('preferences.account.association')"> <el-table-column :label="$t('preferences.account.association')">
<template #default="scope"> <template #default="scope">
<el-button @click.prevent="removeAccount(scope.$index, accounts)" type="text" class="action"> <el-button @click.prevent="removeAccount(scope.$index, accounts)" type="text" class="action">
<el-icon><el-icon-close /></el-icon> <font-awesome-icon icon="xmark" />
{{ $t('preferences.account.remove_association') }} {{ $t('preferences.account.remove_association') }}
</el-button> </el-button>
</template> </template>
@ -25,20 +25,14 @@
<el-table-column :label="$t('preferences.account.order')" width="60"> <el-table-column :label="$t('preferences.account.order')" width="60">
<template #default="scope"> <template #default="scope">
<div class="allow-up"> <div class="allow-up">
<el-button <el-button class="arrow-up action" type="text" @click.prevent="forward(scope.$index, accounts)">
class="arrow-up action" <font-awesome-icon icon="arrow-up" />
type="text" </el-button>
:icon="ElIconArrowUp"
@click.prevent="forward(scope.$index, accounts)"
></el-button>
</div> </div>
<div class="allow-down"> <div class="allow-down">
<el-button <el-button class="arrow-down action" type="text" @click.prevent="backward(scope.$index, accounts)">
class="arrow-down action" <font-awesome-icon icon="arrow-down" />
type="text" </el-button>
:icon="ElIconArrowDown"
@click.prevent="backward(scope.$index, accounts)"
></el-button>
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
@ -59,21 +53,15 @@
</template> </template>
<script> <script>
import { Close as ElIconClose, ArrowUp as ElIconArrowUp, ArrowDown as ElIconArrowDown } from '@element-plus/icons'
import { mapState } from 'vuex' import { mapState } from 'vuex'
export default { export default {
data() { data() {
return { return {
openRemoveDialog: false, openRemoveDialog: false,
deletePopoverVisible: false, deletePopoverVisible: false
ElIconArrowUp,
ElIconArrowDown
} }
}, },
components: {
ElIconClose
},
name: 'account', name: 'account',
computed: { computed: {
...mapState({ ...mapState({

View File

@ -6,13 +6,9 @@
<h1>{{ $t('settings.title') }}</h1> <h1>{{ $t('settings.title') }}</h1>
</el-col> </el-col>
<el-col :span="1"> <el-col :span="1">
<el-button <el-button type="text" @click="close" class="close-button" role="button">
type="text" <font-awesome-icon icon="xmark" />
:icon="ElIconClose" </el-button>
@click="close"
class="close-button"
role="button"
></el-button>
</el-col> </el-col>
</el-row> </el-row>
</el-header> </el-header>
@ -48,21 +44,15 @@
</template> </template>
<script> <script>
import { Close as ElIconClose } from '@element-plus/icons'
import { mapState } from 'vuex' import { mapState } from 'vuex'
export default { export default {
data() {
return {
ElIconClose,
}
},
name: 'Settings', name: 'Settings',
computed: { computed: {
...mapState({ ...mapState({
primaryColor: (state) => state.App.theme.primary_color, primaryColor: state => state.App.theme.primary_color,
backgroundColor: (state) => state.App.theme.background_color, backgroundColor: state => state.App.theme.background_color
}), })
}, },
created() { created() {
this.$store.commit('Settings/changeAccountID', this.id()) this.$store.commit('Settings/changeAccountID', this.id())
@ -77,8 +67,8 @@ export default {
}, },
activeRoute() { activeRoute() {
return this.$route.path return this.$route.path
}, }
}, }
} }
</script> </script>

View File

@ -1,28 +1,9 @@
<template> <template>
<div <div id="bookmarks" v-shortkey="shortcutEnabled ? { next: ['j'] } : {}" @shortkey="handleKey">
id="bookmarks" <div v-shortkey="{ linux: ['ctrl', 'r'], mac: ['meta', 'r'] }" @shortkey="reload()"></div>
v-shortkey="shortcutEnabled ? { next: ['j'] } : {}" <DynamicScroller :items="bookmarks" :min-item-size="60" id="scroller" class="scroller" ref="scroller">
@shortkey="handleKey"
>
<div
v-shortkey="{ linux: ['ctrl', 'r'], mac: ['meta', 'r'] }"
@shortkey="reload()"
></div>
<DynamicScroller
:items="bookmarks"
:min-item-size="60"
id="scroller"
class="scroller"
ref="scroller"
>
<template v-slot="{ item, index, active }"> <template v-slot="{ item, index, active }">
<DynamicScrollerItem <DynamicScrollerItem :item="item" :active="active" :size-dependencies="[item.uri]" :data-index="index" :watchData="true">
:item="item"
:active="active"
:size-dependencies="[item.uri]"
:data-index="index"
:watchData="true"
>
<toot <toot
:message="item" :message="item"
:focused="item.uri === focusedId" :focused="item.uri === focusedId"
@ -38,18 +19,15 @@
</DynamicScrollerItem> </DynamicScrollerItem>
</template> </template>
</DynamicScroller> </DynamicScroller>
<div <div :class="openSideBar ? 'upper-with-side-bar' : 'upper'" v-show="!heading">
:class="openSideBar ? 'upper-with-side-bar' : 'upper'" <el-button type="primary" @click="upper" circle>
v-show="!heading" <font-awesome-icon icon="arrow-up" />
>
<el-button type="primary" :icon="ElIconArrowUp" @click="upper" circle>
</el-button> </el-button>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import { ArrowUp as ElIconArrowUp } from '@element-plus/icons'
import { mapState, mapGetters } from 'vuex' import { mapState, mapGetters } from 'vuex'
import Toot from '@/components/organisms/Toot' import Toot from '@/components/organisms/Toot'
import reloadable from '~/src/renderer/components/mixins/reloadable' import reloadable from '~/src/renderer/components/mixins/reloadable'
@ -59,8 +37,7 @@ export default {
data() { data() {
return { return {
heading: true, heading: true,
focusedId: null, focusedId: null
ElIconArrowUp,
} }
}, },
name: 'bookmarks', name: 'bookmarks',
@ -68,25 +45,25 @@ export default {
mixins: [reloadable], mixins: [reloadable],
computed: { computed: {
...mapState('TimelineSpace', { ...mapState('TimelineSpace', {
account: (state) => state.account, account: state => state.account
}), }),
...mapState('App', { ...mapState('App', {
backgroundColor: (state) => state.theme.background_color, backgroundColor: state => state.theme.background_color
}), }),
...mapState('TimelineSpace/HeaderMenu', { ...mapState('TimelineSpace/HeaderMenu', {
startReload: (state) => state.reload, startReload: state => state.reload
}), }),
...mapState('TimelineSpace/Contents/SideBar', { ...mapState('TimelineSpace/Contents/SideBar', {
openSideBar: (state) => state.openSideBar, openSideBar: state => state.openSideBar
}), }),
...mapState('TimelineSpace/Contents/Bookmarks', { ...mapState('TimelineSpace/Contents/Bookmarks', {
bookmarks: (state) => state.bookmarks, bookmarks: state => state.bookmarks,
lazyLoading: (state) => state.lazyLoading, lazyLoading: state => state.lazyLoading
}), }),
...mapGetters('TimelineSpace/Modals', ['modalOpened']), ...mapGetters('TimelineSpace/Modals', ['modalOpened']),
shortcutEnabled: function () { shortcutEnabled: function () {
return !this.focusedId && !this.modalOpened return !this.focusedId && !this.modalOpened
}, }
}, },
created() { created() {
this.$store.commit('TimelineSpace/Contents/changeLoading', true) this.$store.commit('TimelineSpace/Contents/changeLoading', true)
@ -95,7 +72,7 @@ export default {
.catch(() => { .catch(() => {
this.$message({ this.$message({
message: this.$t('message.bookmark_fetch_error'), message: this.$t('message.bookmark_fetch_error'),
type: 'error', type: 'error'
}) })
}) })
.finally(() => { .finally(() => {
@ -103,9 +80,7 @@ export default {
}) })
}, },
mounted() { mounted() {
document document.getElementById('scroller').addEventListener('scroll', this.onScroll)
.getElementById('scroller')
.addEventListener('scroll', this.onScroll)
Event.$on('focus-timeline', () => { Event.$on('focus-timeline', () => {
// If focusedId does not change, we have to refresh focusedId because Toot component watch change events. // If focusedId does not change, we have to refresh focusedId because Toot component watch change events.
const previousFocusedId = this.focusedId const previousFocusedId = this.focusedId
@ -120,13 +95,8 @@ export default {
}, },
destroyed() { destroyed() {
this.$store.commit('TimelineSpace/Contents/Bookmarks/updateBookmarks', []) this.$store.commit('TimelineSpace/Contents/Bookmarks/updateBookmarks', [])
if ( if (document.getElementById('scroller') !== undefined && document.getElementById('scroller') !== null) {
document.getElementById('scroller') !== undefined && document.getElementById('scroller').removeEventListener('scroll', this.onScroll)
document.getElementById('scroller') !== null
) {
document
.getElementById('scroller')
.removeEventListener('scroll', this.onScroll)
document.getElementById('scroller').scrollTop = 0 document.getElementById('scroller').scrollTop = 0
} }
}, },
@ -144,7 +114,7 @@ export default {
} else if (newState === null && !this.heading) { } else if (newState === null && !this.heading) {
this.heading = true this.heading = true
} }
}, }
}, },
methods: { methods: {
updateToot(message) { updateToot(message) {
@ -155,21 +125,15 @@ export default {
}, },
onScroll(event) { onScroll(event) {
if ( if (
event.target.clientHeight + event.target.scrollTop >= event.target.clientHeight + event.target.scrollTop >= document.getElementById('scroller').scrollHeight - 10 &&
document.getElementById('scroller').scrollHeight - 10 &&
!this.lazyloading !this.lazyloading
) { ) {
this.$store this.$store.dispatch('TimelineSpace/Contents/Bookmarks/lazyFetchBookmarks', this.bookmarks[this.bookmarks.length - 1]).catch(() => {
.dispatch( this.$message({
'TimelineSpace/Contents/Bookmarks/lazyFetchBookmarks', message: this.$t('message.bookmark_fetch_error'),
this.bookmarks[this.bookmarks.length - 1] type: 'error'
)
.catch(() => {
this.$message({
message: this.$t('message.bookmark_fetch_error'),
type: 'error',
})
}) })
})
} }
// for upper // for upper
if (event.target.scrollTop > 10 && this.heading) { if (event.target.scrollTop > 10 && this.heading) {
@ -182,14 +146,12 @@ export default {
this.$store.commit('TimelineSpace/changeLoading', true) this.$store.commit('TimelineSpace/changeLoading', true)
try { try {
const account = await this.reloadable() const account = await this.reloadable()
await this.$store await this.$store.dispatch('TimelineSpace/Contents/Bookmarks/fetchBookmarks', account).catch(() => {
.dispatch('TimelineSpace/Contents/Bookmarks/fetchBookmarks', account) this.$message({
.catch(() => { message: this.$t('message.bookmark_fetch_error'),
this.$message({ type: 'error'
message: this.$t('message.bookmark_fetch_error'),
type: 'error',
})
}) })
})
} finally { } finally {
this.$store.commit('TimelineSpace/changeLoading', false) this.$store.commit('TimelineSpace/changeLoading', false)
} }
@ -199,9 +161,7 @@ export default {
this.focusedId = null this.focusedId = null
}, },
focusNext() { focusNext() {
const currentIndex = this.bookmarks.findIndex( const currentIndex = this.bookmarks.findIndex(toot => this.focusedId === toot.uri)
(toot) => this.focusedId === toot.uri
)
if (currentIndex === -1) { if (currentIndex === -1) {
this.focusedId = this.bookmarks[0].uri this.focusedId = this.bookmarks[0].uri
} else if (currentIndex < this.bookmarks.length) { } else if (currentIndex < this.bookmarks.length) {
@ -209,9 +169,7 @@ export default {
} }
}, },
focusPrev() { focusPrev() {
const currentIndex = this.bookmarks.findIndex( const currentIndex = this.bookmarks.findIndex(toot => this.focusedId === toot.uri)
(toot) => this.focusedId === toot.uri
)
if (currentIndex === 0) { if (currentIndex === 0) {
this.focusedId = null this.focusedId = null
} else if (currentIndex > 0) { } else if (currentIndex > 0) {
@ -230,8 +188,8 @@ export default {
this.focusedId = this.bookmarks[0].uri this.focusedId = this.bookmarks[0].uri
break break
} }
}, }
}, }
} }
</script> </script>

View File

@ -1,28 +1,9 @@
<template> <template>
<div <div id="directmessages" v-shortkey="shortcutEnabled ? { next: ['j'] } : {}" @shortkey="handleKey">
id="directmessages" <div v-shortkey="{ linux: ['ctrl', 'r'], mac: ['meta', 'r'] }" @shortkey="reload()"></div>
v-shortkey="shortcutEnabled ? { next: ['j'] } : {}" <DynamicScroller :items="timeline" :min-item-size="86" id="scroller" class="scroller" ref="scroller">
@shortkey="handleKey"
>
<div
v-shortkey="{ linux: ['ctrl', 'r'], mac: ['meta', 'r'] }"
@shortkey="reload()"
></div>
<DynamicScroller
:items="timeline"
:min-item-size="86"
id="scroller"
class="scroller"
ref="scroller"
>
<template v-slot="{ item, index, active }"> <template v-slot="{ item, index, active }">
<DynamicScrollerItem <DynamicScrollerItem :item="item" :active="active" :size-dependencies="[item.uri]" :data-index="index" :watchData="true">
:item="item"
:active="active"
:size-dependencies="[item.uri]"
:data-index="index"
:watchData="true"
>
<toot <toot
:message="item" :message="item"
:focused="item.uri + item.id === focusedId" :focused="item.uri + item.id === focusedId"
@ -40,18 +21,15 @@
</DynamicScrollerItem> </DynamicScrollerItem>
</template> </template>
</DynamicScroller> </DynamicScroller>
<div <div :class="openSideBar ? 'upper-with-side-bar' : 'upper'" v-show="!heading">
:class="openSideBar ? 'upper-with-side-bar' : 'upper'" <el-button type="primary" @click="upper" circle>
v-show="!heading" <font-awesome-icon icon="arrow-up" />
>
<el-button type="primary" :icon="ElIconArrowUp" @click="upper" circle>
</el-button> </el-button>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import { ArrowUp as ElIconArrowUp } from '@element-plus/icons'
import { mapState, mapGetters } from 'vuex' import { mapState, mapGetters } from 'vuex'
import moment from 'moment' import moment from 'moment'
import Toot from '~/src/renderer/components/organisms/Toot' import Toot from '~/src/renderer/components/organisms/Toot'
@ -66,8 +44,7 @@ export default {
scrollPosition: null, scrollPosition: null,
observer: null, observer: null,
scrollTime: null, scrollTime: null,
resizeTime: null, resizeTime: null
ElIconArrowUp,
} }
}, },
name: 'directmessages', name: 'directmessages',
@ -75,17 +52,16 @@ export default {
mixins: [reloadable], mixins: [reloadable],
computed: { computed: {
...mapState('TimelineSpace/Contents/DirectMessages', { ...mapState('TimelineSpace/Contents/DirectMessages', {
timeline: (state) => state.timeline, timeline: state => state.timeline,
lazyLoading: (state) => state.lazyLoading, lazyLoading: state => state.lazyLoading,
heading: (state) => state.heading, heading: state => state.heading,
scrolling: (state) => state.scrolling, scrolling: state => state.scrolling
}), }),
...mapState({ ...mapState({
openSideBar: (state) => state.TimelineSpace.Contents.SideBar.openSideBar, openSideBar: state => state.TimelineSpace.Contents.SideBar.openSideBar,
backgroundColor: (state) => state.App.theme.background_color, backgroundColor: state => state.App.theme.background_color,
startReload: (state) => state.TimelineSpace.HeaderMenu.reload, startReload: state => state.TimelineSpace.HeaderMenu.reload,
unreadNotification: (state) => unreadNotification: state => state.TimelineSpace.timelineSetting.unreadNotification
state.TimelineSpace.timelineSetting.unreadNotification,
}), }),
...mapGetters('TimelineSpace/Modals', ['modalOpened']), ...mapGetters('TimelineSpace/Modals', ['modalOpened']),
shortcutEnabled: function () { shortcutEnabled: function () {
@ -96,23 +72,16 @@ export default {
return true return true
} }
// Sometimes toots are deleted, so perhaps focused toot don't exist. // Sometimes toots are deleted, so perhaps focused toot don't exist.
const currentIndex = this.timeline.findIndex( const currentIndex = this.timeline.findIndex(toot => this.focusedId === toot.uri + toot.id)
(toot) => this.focusedId === toot.uri + toot.id
)
return currentIndex === -1 return currentIndex === -1
}, }
}, },
async mounted() { async mounted() {
this.$store.commit( this.$store.commit('TimelineSpace/SideMenu/changeUnreadDirectMessagesTimeline', false)
'TimelineSpace/SideMenu/changeUnreadDirectMessagesTimeline', document.getElementById('scroller').addEventListener('scroll', this.onScroll)
false
)
document
.getElementById('scroller')
.addEventListener('scroll', this.onScroll)
if (!this.unreadNotification.direct) { if (!this.unreadNotification.direct) {
this.$store.commit('TimelineSpace/Contents/changeLoading', true) this.$store.commit('TimelineSpace/Contents/changeLoading', true)
await this.initialize().finally((_) => { await this.initialize().finally(_ => {
this.$store.commit('TimelineSpace/Contents/changeLoading', false) this.$store.commit('TimelineSpace/Contents/changeLoading', false)
}) })
} }
@ -130,31 +99,18 @@ export default {
this.scrollPosition.prepare() this.scrollPosition.prepare()
this.observer = new ResizeObserver(() => { this.observer = new ResizeObserver(() => {
if ( if (this.scrollPosition && !this.heading && !this.lazyLoading && !this.scrolling) {
this.scrollPosition &&
!this.heading &&
!this.lazyLoading &&
!this.scrolling
) {
this.resizeTime = moment() this.resizeTime = moment()
this.scrollPosition.restore() this.scrollPosition.restore()
} }
}) })
const scrollWrapper = el.getElementsByClassName( const scrollWrapper = el.getElementsByClassName('vue-recycle-scroller__item-wrapper')[0]
'vue-recycle-scroller__item-wrapper'
)[0]
this.observer.observe(scrollWrapper) this.observer.observe(scrollWrapper)
}, },
beforeUpdate() { beforeUpdate() {
if ( if (this.$store.state.TimelineSpace.SideMenu.unreadDirectMessagesTimeline && this.heading) {
this.$store.state.TimelineSpace.SideMenu.unreadDirectMessagesTimeline && this.$store.commit('TimelineSpace/SideMenu/changeUnreadDirectMessagesTimeline', false)
this.heading
) {
this.$store.commit(
'TimelineSpace/SideMenu/changeUnreadDirectMessagesTimeline',
false
)
} }
if (this.scrollPosition) { if (this.scrollPosition) {
this.scrollPosition.prepare() this.scrollPosition.prepare()
@ -169,21 +125,13 @@ export default {
this.observer.disconnect() this.observer.disconnect()
}, },
destroyed() { destroyed() {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/DirectMessages/changeHeading', true)
'TimelineSpace/Contents/DirectMessages/changeHeading',
true
)
this.$store.commit('TimelineSpace/Contents/DirectMessages/archiveTimeline') this.$store.commit('TimelineSpace/Contents/DirectMessages/archiveTimeline')
if (!this.unreadNotification.direct) { if (!this.unreadNotification.direct) {
this.$store.commit('TimelineSpace/Contents/DirectMessages/clearTimeline') this.$store.commit('TimelineSpace/Contents/DirectMessages/clearTimeline')
} }
if ( if (document.getElementById('scroller') !== undefined && document.getElementById('scroller') !== null) {
document.getElementById('scroller') !== undefined && document.getElementById('scroller').removeEventListener('scroll', this.onScroll)
document.getElementById('scroller') !== null
) {
document
.getElementById('scroller')
.removeEventListener('scroll', this.onScroll)
document.getElementById('scroller').scrollTop = 0 document.getElementById('scroller').scrollTop = 0
} }
}, },
@ -197,28 +145,20 @@ export default {
}, },
focusedId: function (newState, _oldState) { focusedId: function (newState, _oldState) {
if (newState && this.heading) { if (newState && this.heading) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/DirectMessages/changeHeading', false)
'TimelineSpace/Contents/DirectMessages/changeHeading',
false
)
} else if (newState === null && !this.heading) { } else if (newState === null && !this.heading) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/DirectMessages/changeHeading', true)
'TimelineSpace/Contents/DirectMessages/changeHeading',
true
)
} }
}, }
}, },
methods: { methods: {
async initialize() { async initialize() {
await this.$store await this.$store.dispatch('TimelineSpace/Contents/DirectMessages/fetchTimeline').catch(_ => {
.dispatch('TimelineSpace/Contents/DirectMessages/fetchTimeline') this.$message({
.catch((_) => { message: this.$t('message.timeline_fetch_error'),
this.$message({ type: 'error'
message: this.$t('message.timeline_fetch_error'),
type: 'error',
})
}) })
})
await this.$store.dispatch('TimelineSpace/bindDirectMessagesStreaming') await this.$store.dispatch('TimelineSpace/bindDirectMessagesStreaming')
this.$store.dispatch('TimelineSpace/startDirectMessagesStreaming') this.$store.dispatch('TimelineSpace/startDirectMessagesStreaming')
}, },
@ -228,82 +168,54 @@ export default {
} }
this.scrollTime = moment() this.scrollTime = moment()
if (!this.scrolling) { if (!this.scrolling) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/DirectMessages/changeScrolling', true)
'TimelineSpace/Contents/DirectMessages/changeScrolling',
true
)
} }
// for lazyLoading // for lazyLoading
if ( if (
event.target.clientHeight + event.target.scrollTop >= event.target.clientHeight + event.target.scrollTop >= document.getElementById('scroller').scrollHeight - 10 &&
document.getElementById('scroller').scrollHeight - 10 &&
!this.lazyloading !this.lazyloading
) { ) {
this.$store this.$store
.dispatch( .dispatch('TimelineSpace/Contents/DirectMessages/lazyFetchTimeline', this.timeline[this.timeline.length - 1])
'TimelineSpace/Contents/DirectMessages/lazyFetchTimeline', .then(statuses => {
this.timeline[this.timeline.length - 1]
)
.then((statuses) => {
if (statuses === null) { if (statuses === null) {
return return
} }
if (statuses.length > 0) { if (statuses.length > 0) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/DirectMessages/changeScrolling', true)
'TimelineSpace/Contents/DirectMessages/changeScrolling',
true
)
setTimeout(() => { setTimeout(() => {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/DirectMessages/changeScrolling', false)
'TimelineSpace/Contents/DirectMessages/changeScrolling',
false
)
}, 500) }, 500)
} }
}) })
.catch(() => { .catch(() => {
this.$message({ this.$message({
message: this.$t('message.timeline_fetch_error'), message: this.$t('message.timeline_fetch_error'),
type: 'error', type: 'error'
}) })
}) })
} }
if (event.target.scrollTop > 10 && this.heading) { if (event.target.scrollTop > 10 && this.heading) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/DirectMessages/changeHeading', false)
'TimelineSpace/Contents/DirectMessages/changeHeading',
false
)
} else if (event.target.scrollTop <= 10 && !this.heading) { } else if (event.target.scrollTop <= 10 && !this.heading) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/DirectMessages/changeHeading', true)
'TimelineSpace/Contents/DirectMessages/changeHeading',
true
)
} }
setTimeout(() => { setTimeout(() => {
const now = moment() const now = moment()
if (now.diff(this.scrollTime) >= 150) { if (now.diff(this.scrollTime) >= 150) {
this.scrollTime = null this.scrollTime = null
this.$store.commit( this.$store.commit('TimelineSpace/Contents/DirectMessages/changeScrolling', false)
'TimelineSpace/Contents/DirectMessages/changeScrolling',
false
)
} }
}, 150) }, 150)
}, },
updateToot(message) { updateToot(message) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/DirectMessages/updateToot', message)
'TimelineSpace/Contents/DirectMessages/updateToot',
message
)
}, },
deleteToot(message) { deleteToot(message) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/DirectMessages/deleteToot', message.id)
'TimelineSpace/Contents/DirectMessages/deleteToot',
message.id
)
}, },
async reload() { async reload() {
this.$store.commit('TimelineSpace/changeLoading', true) this.$store.commit('TimelineSpace/changeLoading', true)
@ -318,27 +230,19 @@ export default {
this.focusedId = null this.focusedId = null
}, },
focusNext() { focusNext() {
const currentIndex = this.timeline.findIndex( const currentIndex = this.timeline.findIndex(toot => this.focusedId === toot.uri + toot.id)
(toot) => this.focusedId === toot.uri + toot.id
)
if (currentIndex === -1) { if (currentIndex === -1) {
this.focusedId = this.timeline[0].uri + this.timeline[0].id this.focusedId = this.timeline[0].uri + this.timeline[0].id
} else if (currentIndex < this.timeline.length) { } else if (currentIndex < this.timeline.length) {
this.focusedId = this.focusedId = this.timeline[currentIndex + 1].uri + this.timeline[currentIndex + 1].id
this.timeline[currentIndex + 1].uri +
this.timeline[currentIndex + 1].id
} }
}, },
focusPrev() { focusPrev() {
const currentIndex = this.timeline.findIndex( const currentIndex = this.timeline.findIndex(toot => this.focusedId === toot.uri + toot.id)
(toot) => this.focusedId === toot.uri + toot.id
)
if (currentIndex === 0) { if (currentIndex === 0) {
this.focusedId = null this.focusedId = null
} else if (currentIndex > 0) { } else if (currentIndex > 0) {
this.focusedId = this.focusedId = this.timeline[currentIndex - 1].uri + this.timeline[currentIndex - 1].id
this.timeline[currentIndex - 1].uri +
this.timeline[currentIndex - 1].id
} }
}, },
focusToot(message) { focusToot(message) {
@ -355,18 +259,12 @@ export default {
} }
}, },
sizeChanged() { sizeChanged() {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/DirectMessages/changeScrolling', true)
'TimelineSpace/Contents/DirectMessages/changeScrolling',
true
)
setTimeout(() => { setTimeout(() => {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/DirectMessages/changeScrolling', false)
'TimelineSpace/Contents/DirectMessages/changeScrolling',
false
)
}, 500) }, 500)
}, }
}, }
} }
</script> </script>

View File

@ -1,28 +1,9 @@
<template> <template>
<div <div id="favourites" v-shortkey="shortcutEnabled ? { next: ['j'] } : {}" @shortkey="handleKey">
id="favourites" <div v-shortkey="{ linux: ['ctrl', 'r'], mac: ['meta', 'r'] }" @shortkey="reload()"></div>
v-shortkey="shortcutEnabled ? { next: ['j'] } : {}" <DynamicScroller :items="favourites" :min-item-size="60" id="scroller" class="scroller" ref="scroller">
@shortkey="handleKey"
>
<div
v-shortkey="{ linux: ['ctrl', 'r'], mac: ['meta', 'r'] }"
@shortkey="reload()"
></div>
<DynamicScroller
:items="favourites"
:min-item-size="60"
id="scroller"
class="scroller"
ref="scroller"
>
<template v-slot="{ item, index, active }"> <template v-slot="{ item, index, active }">
<DynamicScrollerItem <DynamicScrollerItem :item="item" :active="active" :size-dependencies="[item.uri]" :data-index="index" :watchData="true">
:item="item"
:active="active"
:size-dependencies="[item.uri]"
:data-index="index"
:watchData="true"
>
<toot <toot
:message="item" :message="item"
:focused="item.uri === focusedId" :focused="item.uri === focusedId"
@ -39,18 +20,15 @@
</DynamicScrollerItem> </DynamicScrollerItem>
</template> </template>
</DynamicScroller> </DynamicScroller>
<div <div :class="openSideBar ? 'upper-with-side-bar' : 'upper'" v-show="!heading">
:class="openSideBar ? 'upper-with-side-bar' : 'upper'"
v-show="!heading"
>
<el-button type="primary" :icon="ElIconArrowUp" @click="upper" circle> <el-button type="primary" :icon="ElIconArrowUp" @click="upper" circle>
<font-awesome-icon icon="arrow-up" />
</el-button> </el-button>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import { ArrowUp as ElIconArrowUp } from '@element-plus/icons'
import { mapState, mapGetters } from 'vuex' import { mapState, mapGetters } from 'vuex'
import Toot from '~/src/renderer/components/organisms/Toot' import Toot from '~/src/renderer/components/organisms/Toot'
import reloadable from '~/src/renderer/components/mixins/reloadable' import reloadable from '~/src/renderer/components/mixins/reloadable'
@ -60,8 +38,7 @@ export default {
data() { data() {
return { return {
heading: true, heading: true,
focusedId: null, focusedId: null
ElIconArrowUp,
} }
}, },
name: 'favourites', name: 'favourites',
@ -69,30 +46,26 @@ export default {
mixins: [reloadable], mixins: [reloadable],
computed: { computed: {
...mapState({ ...mapState({
openSideBar: (state) => state.TimelineSpace.Contents.SideBar.openSideBar, openSideBar: state => state.TimelineSpace.Contents.SideBar.openSideBar,
backgroundColor: (state) => state.App.theme.background_color, backgroundColor: state => state.App.theme.background_color,
startReload: (state) => state.TimelineSpace.HeaderMenu.reload, startReload: state => state.TimelineSpace.HeaderMenu.reload,
account: (state) => state.TimelineSpace.account, account: state => state.TimelineSpace.account,
favourites: (state) => state.TimelineSpace.Contents.Favourites.favourites, favourites: state => state.TimelineSpace.Contents.Favourites.favourites,
lazyLoading: (state) => lazyLoading: state => state.TimelineSpace.Contents.Favourites.lazyLoading
state.TimelineSpace.Contents.Favourites.lazyLoading,
}), }),
...mapGetters('TimelineSpace/Modals', ['modalOpened']), ...mapGetters('TimelineSpace/Modals', ['modalOpened']),
shortcutEnabled: function () { shortcutEnabled: function () {
return !this.focusedId && !this.modalOpened return !this.focusedId && !this.modalOpened
}, }
}, },
created() { created() {
this.$store.commit('TimelineSpace/Contents/changeLoading', true) this.$store.commit('TimelineSpace/Contents/changeLoading', true)
this.$store this.$store
.dispatch( .dispatch('TimelineSpace/Contents/Favourites/fetchFavourites', this.account)
'TimelineSpace/Contents/Favourites/fetchFavourites',
this.account
)
.catch(() => { .catch(() => {
this.$message({ this.$message({
message: this.$t('message.favourite_fetch_error'), message: this.$t('message.favourite_fetch_error'),
type: 'error', type: 'error'
}) })
}) })
.finally(() => { .finally(() => {
@ -100,9 +73,7 @@ export default {
}) })
}, },
mounted() { mounted() {
document document.getElementById('scroller').addEventListener('scroll', this.onScroll)
.getElementById('scroller')
.addEventListener('scroll', this.onScroll)
Event.$on('focus-timeline', () => { Event.$on('focus-timeline', () => {
// If focusedId does not change, we have to refresh focusedId because Toot component watch change events. // If focusedId does not change, we have to refresh focusedId because Toot component watch change events.
const previousFocusedId = this.focusedId const previousFocusedId = this.focusedId
@ -117,13 +88,8 @@ export default {
}, },
destroyed() { destroyed() {
this.$store.commit('TimelineSpace/Contents/Favourites/updateFavourites', []) this.$store.commit('TimelineSpace/Contents/Favourites/updateFavourites', [])
if ( if (document.getElementById('scroller') !== undefined && document.getElementById('scroller') !== null) {
document.getElementById('scroller') !== undefined && document.getElementById('scroller').removeEventListener('scroll', this.onScroll)
document.getElementById('scroller') !== null
) {
document
.getElementById('scroller')
.removeEventListener('scroll', this.onScroll)
document.getElementById('scroller').scrollTop = 0 document.getElementById('scroller').scrollTop = 0
} }
}, },
@ -141,36 +107,26 @@ export default {
} else if (newState === null && !this.heading) { } else if (newState === null && !this.heading) {
this.heading = true this.heading = true
} }
}, }
}, },
methods: { methods: {
updateToot(message) { updateToot(message) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Favourites/updateToot', message)
'TimelineSpace/Contents/Favourites/updateToot',
message
)
}, },
deleteToot(message) { deleteToot(message) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Favourites/deleteToot', message)
'TimelineSpace/Contents/Favourites/deleteToot',
message
)
}, },
onScroll(event) { onScroll(event) {
if ( if (
event.target.clientHeight + event.target.scrollTop >= event.target.clientHeight + event.target.scrollTop >= document.getElementById('scroller').scrollHeight - 10 &&
document.getElementById('scroller').scrollHeight - 10 &&
!this.lazyloading !this.lazyloading
) { ) {
this.$store this.$store
.dispatch( .dispatch('TimelineSpace/Contents/Favourites/lazyFetchFavourites', this.favourites[this.favourites.length - 1])
'TimelineSpace/Contents/Favourites/lazyFetchFavourites',
this.favourites[this.favourites.length - 1]
)
.catch(() => { .catch(() => {
this.$message({ this.$message({
message: this.$t('message.favourite_fetch_error'), message: this.$t('message.favourite_fetch_error'),
type: 'error', type: 'error'
}) })
}) })
} }
@ -185,17 +141,12 @@ export default {
this.$store.commit('TimelineSpace/changeLoading', true) this.$store.commit('TimelineSpace/changeLoading', true)
try { try {
const account = await this.reloadable() const account = await this.reloadable()
await this.$store await this.$store.dispatch('TimelineSpace/Contents/Favourites/fetchFavourites', account).catch(() => {
.dispatch( this.$message({
'TimelineSpace/Contents/Favourites/fetchFavourites', message: this.$t('message.favourite_fetch_error'),
account type: 'error'
)
.catch(() => {
this.$message({
message: this.$t('message.favourite_fetch_error'),
type: 'error',
})
}) })
})
} finally { } finally {
this.$store.commit('TimelineSpace/changeLoading', false) this.$store.commit('TimelineSpace/changeLoading', false)
} }
@ -205,9 +156,7 @@ export default {
this.focusedId = null this.focusedId = null
}, },
focusNext() { focusNext() {
const currentIndex = this.favourites.findIndex( const currentIndex = this.favourites.findIndex(toot => this.focusedId === toot.uri)
(toot) => this.focusedId === toot.uri
)
if (currentIndex === -1) { if (currentIndex === -1) {
this.focusedId = this.favourites[0].uri this.focusedId = this.favourites[0].uri
} else if (currentIndex < this.favourites.length) { } else if (currentIndex < this.favourites.length) {
@ -215,9 +164,7 @@ export default {
} }
}, },
focusPrev() { focusPrev() {
const currentIndex = this.favourites.findIndex( const currentIndex = this.favourites.findIndex(toot => this.focusedId === toot.uri)
(toot) => this.focusedId === toot.uri
)
if (currentIndex === 0) { if (currentIndex === 0) {
this.focusedId = null this.focusedId = null
} else if (currentIndex > 0) { } else if (currentIndex > 0) {
@ -236,8 +183,8 @@ export default {
this.focusedId = this.favourites[0].uri this.focusedId = this.favourites[0].uri
break break
} }
}, }
}, }
} }
</script> </script>

View File

@ -1,29 +1,9 @@
<template> <template>
<div <div name="tag" class="tag-timeline" v-shortkey="shortcutEnabled ? { next: ['j'] } : {}" @shortkey="handleKey">
name="tag" <div v-shortkey="{ linux: ['ctrl', 'r'], mac: ['meta', 'r'] }" @shortkey="reload()"></div>
class="tag-timeline" <DynamicScroller :items="timeline" :min-item-size="86" id="scroller" class="scroller" ref="scroller">
v-shortkey="shortcutEnabled ? { next: ['j'] } : {}"
@shortkey="handleKey"
>
<div
v-shortkey="{ linux: ['ctrl', 'r'], mac: ['meta', 'r'] }"
@shortkey="reload()"
></div>
<DynamicScroller
:items="timeline"
:min-item-size="86"
id="scroller"
class="scroller"
ref="scroller"
>
<template v-slot="{ item, index, active }"> <template v-slot="{ item, index, active }">
<DynamicScrollerItem <DynamicScrollerItem :item="item" :active="active" :size-dependencies="[item.uri]" :data-index="index" :watchData="true">
:item="item"
:active="active"
:size-dependencies="[item.uri]"
:data-index="index"
:watchData="true"
>
<toot <toot
:message="item" :message="item"
:focused="item.uri + item.id === focusedId" :focused="item.uri + item.id === focusedId"
@ -41,18 +21,15 @@
</DynamicScrollerItem> </DynamicScrollerItem>
</template> </template>
</DynamicScroller> </DynamicScroller>
<div <div :class="openSideBar ? 'upper-with-side-bar' : 'upper'" v-show="!heading">
:class="openSideBar ? 'upper-with-side-bar' : 'upper'" <el-button type="primary" @click="upper" circle>
v-show="!heading" <font-awesome-icon icon="arrow-up" />
>
<el-button type="primary" :icon="ElIconArrowUp" @click="upper" circle>
</el-button> </el-button>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import { ArrowUp as ElIconArrowUp } from '@element-plus/icons'
import { mapState, mapGetters } from 'vuex' import { mapState, mapGetters } from 'vuex'
import moment from 'moment' import moment from 'moment'
import Toot from '~/src/renderer/components/organisms/Toot' import Toot from '~/src/renderer/components/organisms/Toot'
@ -67,8 +44,7 @@ export default {
scrollPosition: null, scrollPosition: null,
observer: null, observer: null,
scrollTime: null, scrollTime: null,
resizeTime: null, resizeTime: null
ElIconArrowUp,
} }
}, },
name: 'tag', name: 'tag',
@ -77,14 +53,13 @@ export default {
props: ['tag'], props: ['tag'],
computed: { computed: {
...mapState({ ...mapState({
openSideBar: (state) => state.TimelineSpace.Contents.SideBar.openSideBar, openSideBar: state => state.TimelineSpace.Contents.SideBar.openSideBar,
backgroundColor: (state) => state.App.theme.background_color, backgroundColor: state => state.App.theme.background_color,
startReload: (state) => state.TimelineSpace.HeaderMenu.reload, startReload: state => state.TimelineSpace.HeaderMenu.reload,
timeline: (state) => state.TimelineSpace.Contents.Hashtag.Tag.timeline, timeline: state => state.TimelineSpace.Contents.Hashtag.Tag.timeline,
lazyLoading: (state) => lazyLoading: state => state.TimelineSpace.Contents.Hashtag.Tag.lazyLoading,
state.TimelineSpace.Contents.Hashtag.Tag.lazyLoading, heading: state => state.TimelineSpace.Contents.Hashtag.Tag.heading,
heading: (state) => state.TimelineSpace.Contents.Hashtag.Tag.heading, scrolling: state => state.TimelineSpace.Contents.Hashtag.Tag.scrolling
scrolling: (state) => state.TimelineSpace.Contents.Hashtag.Tag.scrolling,
}), }),
...mapGetters('TimelineSpace/Modals', ['modalOpened']), ...mapGetters('TimelineSpace/Modals', ['modalOpened']),
shortcutEnabled: function () { shortcutEnabled: function () {
@ -95,20 +70,16 @@ export default {
return true return true
} }
// Sometimes toots are deleted, so perhaps focused toot don't exist. // Sometimes toots are deleted, so perhaps focused toot don't exist.
const currentIndex = this.timeline.findIndex( const currentIndex = this.timeline.findIndex(toot => this.focusedId === toot.uri + toot.id)
(toot) => this.focusedId === toot.uri + toot.id
)
return currentIndex === -1 return currentIndex === -1
}, }
}, },
mounted() { mounted() {
this.$store.commit('TimelineSpace/Contents/changeLoading', true) this.$store.commit('TimelineSpace/Contents/changeLoading', true)
this.load(this.tag).finally(() => { this.load(this.tag).finally(() => {
this.$store.commit('TimelineSpace/Contents/changeLoading', false) this.$store.commit('TimelineSpace/Contents/changeLoading', false)
}) })
document document.getElementById('scroller').addEventListener('scroll', this.onScroll)
.getElementById('scroller')
.addEventListener('scroll', this.onScroll)
Event.$on('focus-timeline', () => { Event.$on('focus-timeline', () => {
// If focusedId does not change, we have to refresh focusedId because Toot component watch change events. // If focusedId does not change, we have to refresh focusedId because Toot component watch change events.
@ -123,20 +94,13 @@ export default {
this.scrollPosition.prepare() this.scrollPosition.prepare()
this.observer = new ResizeObserver(() => { this.observer = new ResizeObserver(() => {
if ( if (this.scrollPosition && !this.heading && !this.lazyLoading && !this.scrolling) {
this.scrollPosition &&
!this.heading &&
!this.lazyLoading &&
!this.scrolling
) {
this.resizeTime = moment() this.resizeTime = moment()
this.scrollPosition.restore() this.scrollPosition.restore()
} }
}) })
const scrollWrapper = el.getElementsByClassName( const scrollWrapper = el.getElementsByClassName('vue-recycle-scroller__item-wrapper')[0]
'vue-recycle-scroller__item-wrapper'
)[0]
this.observer.observe(scrollWrapper) this.observer.observe(scrollWrapper)
}, },
beforeUpdate() { beforeUpdate() {
@ -161,17 +125,11 @@ export default {
}, },
focusedId: function (newState, _oldState) { focusedId: function (newState, _oldState) {
if (newState && this.heading) { if (newState && this.heading) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Hashtag/Tag/changeHeading', false)
'TimelineSpace/Contents/Hashtag/Tag/changeHeading',
false
)
} else if (newState === null && !this.heading) { } else if (newState === null && !this.heading) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Hashtag/Tag/changeHeading', true)
'TimelineSpace/Contents/Hashtag/Tag/changeHeading',
true
)
} }
}, }
}, },
beforeDestroy() { beforeDestroy() {
this.$store.dispatch('TimelineSpace/Contents/Hashtag/Tag/stopStreaming') this.$store.dispatch('TimelineSpace/Contents/Hashtag/Tag/stopStreaming')
@ -181,38 +139,26 @@ export default {
}, },
methods: { methods: {
async load(tag) { async load(tag) {
await this.$store await this.$store.dispatch('TimelineSpace/Contents/Hashtag/Tag/fetch', tag).catch(() => {
.dispatch('TimelineSpace/Contents/Hashtag/Tag/fetch', tag) this.$message({
.catch(() => { message: this.$t('message.timeline_fetch_error'),
this.$message({ type: 'error'
message: this.$t('message.timeline_fetch_error'),
type: 'error',
})
}) })
this.$store })
.dispatch('TimelineSpace/Contents/Hashtag/Tag/startStreaming', tag) this.$store.dispatch('TimelineSpace/Contents/Hashtag/Tag/startStreaming', tag).catch(() => {
.catch(() => { this.$message({
this.$message({ message: this.$t('message.start_streaming_error'),
message: this.$t('message.start_streaming_error'), type: 'error'
type: 'error',
})
}) })
})
return true return true
}, },
reset() { reset() {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Hashtag/Tag/changeHeading', true)
'TimelineSpace/Contents/Hashtag/Tag/changeHeading',
true
)
this.$store.commit('TimelineSpace/Contents/Hashtag/Tag/archiveTimeline') this.$store.commit('TimelineSpace/Contents/Hashtag/Tag/archiveTimeline')
this.$store.commit('TimelineSpace/Contents/Hashtag/Tag/clearTimeline') this.$store.commit('TimelineSpace/Contents/Hashtag/Tag/clearTimeline')
if ( if (document.getElementById('scroller') !== undefined && document.getElementById('scroller') !== null) {
document.getElementById('scroller') !== undefined && document.getElementById('scroller').removeEventListener('scroll', this.onScroll)
document.getElementById('scroller') !== null
) {
document
.getElementById('scroller')
.removeEventListener('scroll', this.onScroll)
document.getElementById('scroller').scrollTop = 0 document.getElementById('scroller').scrollTop = 0
} }
}, },
@ -220,10 +166,7 @@ export default {
this.$store.commit('TimelineSpace/Contents/Hashtag/Tag/updateToot', toot) this.$store.commit('TimelineSpace/Contents/Hashtag/Tag/updateToot', toot)
}, },
deleteToot(toot) { deleteToot(toot) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Hashtag/Tag/deleteToot', toot.id)
'TimelineSpace/Contents/Hashtag/Tag/deleteToot',
toot.id
)
}, },
onScroll(event) { onScroll(event) {
if (moment().diff(this.resizeTime) < 500) { if (moment().diff(this.resizeTime) < 500) {
@ -231,67 +174,48 @@ export default {
} }
this.scrollTime = moment() this.scrollTime = moment()
if (!this.scrolling) { if (!this.scrolling) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Hashtag/Tag/changeScrolling', true)
'TimelineSpace/Contents/Hashtag/Tag/changeScrolling',
true
)
} }
if ( if (
event.target.clientHeight + event.target.scrollTop >= event.target.clientHeight + event.target.scrollTop >= document.getElementById('scroller').scrollHeight - 10 &&
document.getElementById('scroller').scrollHeight - 10 &&
!this.lazyloading !this.lazyloading
) { ) {
this.$store this.$store
.dispatch('TimelineSpace/Contents/Hashtag/Tag/lazyFetchTimeline', { .dispatch('TimelineSpace/Contents/Hashtag/Tag/lazyFetchTimeline', {
tag: this.tag, tag: this.tag,
status: this.timeline[this.timeline.length - 1], status: this.timeline[this.timeline.length - 1]
}) })
.then((statuses) => { .then(statuses => {
if (statuses === null) { if (statuses === null) {
return return
} }
if (statuses.length > 0) { if (statuses.length > 0) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Hashtag/Tag/changeScrolling', true)
'TimelineSpace/Contents/Hashtag/Tag/changeScrolling',
true
)
setTimeout(() => { setTimeout(() => {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Hashtag/Tag/changeScrolling', false)
'TimelineSpace/Contents/Hashtag/Tag/changeScrolling',
false
)
}, 500) }, 500)
} }
}) })
.catch(() => { .catch(() => {
this.$message({ this.$message({
message: this.$t('message.timeline_fetch_error'), message: this.$t('message.timeline_fetch_error'),
type: 'error', type: 'error'
}) })
}) })
} }
if (event.target.scrollTop > 10 && this.heading) { if (event.target.scrollTop > 10 && this.heading) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Hashtag/Tag/changeHeading', false)
'TimelineSpace/Contents/Hashtag/Tag/changeHeading',
false
)
} else if (event.target.scrollTop <= 10 && !this.heading) { } else if (event.target.scrollTop <= 10 && !this.heading) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Hashtag/Tag/changeHeading', true)
'TimelineSpace/Contents/Hashtag/Tag/changeHeading',
true
)
} }
setTimeout(() => { setTimeout(() => {
const now = moment() const now = moment()
if (now.diff(this.scrollTime) >= 150) { if (now.diff(this.scrollTime) >= 150) {
this.scrollTime = null this.scrollTime = null
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Hashtag/Tag/changeScrolling', false)
'TimelineSpace/Contents/Hashtag/Tag/changeScrolling',
false
)
} }
}, 150) }, 150)
}, },
@ -300,25 +224,19 @@ export default {
this.$store.commit('TimelineSpace/changeLoading', true) this.$store.commit('TimelineSpace/changeLoading', true)
try { try {
await this.reloadable() await this.reloadable()
await this.$store.dispatch( await this.$store.dispatch('TimelineSpace/Contents/Hashtag/Tag/stopStreaming')
'TimelineSpace/Contents/Hashtag/Tag/stopStreaming' await this.$store.dispatch('TimelineSpace/Contents/Hashtag/Tag/fetch', tag).catch(() => {
) this.$message({
await this.$store message: this.$t('message.timeline_fetch_error'),
.dispatch('TimelineSpace/Contents/Hashtag/Tag/fetch', tag) type: 'error'
.catch(() => {
this.$message({
message: this.$t('message.timeline_fetch_error'),
type: 'error',
})
}) })
this.$store })
.dispatch('TimelineSpace/Contents/Hashtag/Tag/startStreaming', tag) this.$store.dispatch('TimelineSpace/Contents/Hashtag/Tag/startStreaming', tag).catch(() => {
.catch(() => { this.$message({
this.$message({ message: this.$t('message.start_streaming_error'),
message: this.$t('message.start_streaming_error'), type: 'error'
type: 'error',
})
}) })
})
} finally { } finally {
this.$store.commit('TimelineSpace/changeLoading', false) this.$store.commit('TimelineSpace/changeLoading', false)
} }
@ -328,27 +246,19 @@ export default {
this.focusedId = null this.focusedId = null
}, },
focusNext() { focusNext() {
const currentIndex = this.timeline.findIndex( const currentIndex = this.timeline.findIndex(toot => this.focusedId === toot.uri + toot.id)
(toot) => this.focusedId === toot.uri + toot.id
)
if (currentIndex === -1) { if (currentIndex === -1) {
this.focusedId = this.timeline[0].uri + this.timeline[0].id this.focusedId = this.timeline[0].uri + this.timeline[0].id
} else if (currentIndex < this.timeline.length) { } else if (currentIndex < this.timeline.length) {
this.focusedId = this.focusedId = this.timeline[currentIndex + 1].uri + this.timeline[currentIndex + 1].id
this.timeline[currentIndex + 1].uri +
this.timeline[currentIndex + 1].id
} }
}, },
focusPrev() { focusPrev() {
const currentIndex = this.timeline.findIndex( const currentIndex = this.timeline.findIndex(toot => this.focusedId === toot.uri + toot.id)
(toot) => this.focusedId === toot.uri + toot.id
)
if (currentIndex === 0) { if (currentIndex === 0) {
this.focusedId = null this.focusedId = null
} else if (currentIndex > 0) { } else if (currentIndex > 0) {
this.focusedId = this.focusedId = this.timeline[currentIndex - 1].uri + this.timeline[currentIndex - 1].id
this.timeline[currentIndex - 1].uri +
this.timeline[currentIndex - 1].id
} }
}, },
focusToot(message) { focusToot(message) {
@ -365,18 +275,12 @@ export default {
} }
}, },
sizeChanged() { sizeChanged() {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Hashtag/Tag/changeScrolling', true)
'TimelineSpace/Contents/Hashtag/Tag/changeScrolling',
true
)
setTimeout(() => { setTimeout(() => {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Hashtag/Tag/changeScrolling', false)
'TimelineSpace/Contents/Hashtag/Tag/changeScrolling',
false
)
}, 500) }, 500)
}, }
}, }
} }
</script> </script>

View File

@ -1,45 +1,15 @@
<template> <template>
<div <div id="home" v-shortkey="shortcutEnabled ? { next: ['j'] } : {}" @shortkey="handleKey">
id="home" <div v-shortkey="{ linux: ['ctrl', 'r'], mac: ['meta', 'r'] }" @shortkey="reload()"></div>
v-shortkey="shortcutEnabled ? { next: ['j'] } : {}" <DynamicScroller :items="filteredTimeline" :min-item-size="86" id="scroller" class="scroller" ref="scroller">
@shortkey="handleKey"
>
<div
v-shortkey="{ linux: ['ctrl', 'r'], mac: ['meta', 'r'] }"
@shortkey="reload()"
></div>
<DynamicScroller
:items="filteredTimeline"
:min-item-size="86"
id="scroller"
class="scroller"
ref="scroller"
>
<template v-slot="{ item, index, active }"> <template v-slot="{ item, index, active }">
<template v-if="item.id === 'loading-card'"> <template v-if="item.id === 'loading-card'">
<DynamicScrollerItem <DynamicScrollerItem :item="item" :active="active" :size-dependencies="[item.id]" :data-index="index" :watchData="true">
:item="item" <StatusLoading :since_id="item.since_id" :max_id="item.max_id" :loading="loadingMore" @load_since="fetchTimelineSince" />
:active="active"
:size-dependencies="[item.id]"
:data-index="index"
:watchData="true"
>
<StatusLoading
:since_id="item.since_id"
:max_id="item.max_id"
:loading="loadingMore"
@load_since="fetchTimelineSince"
/>
</DynamicScrollerItem> </DynamicScrollerItem>
</template> </template>
<template v-else> <template v-else>
<DynamicScrollerItem <DynamicScrollerItem :item="item" :active="active" :size-dependencies="[item.uri]" :data-index="index" :watchData="true">
:item="item"
:active="active"
:size-dependencies="[item.uri]"
:data-index="index"
:watchData="true"
>
<toot <toot
:message="item" :message="item"
:focused="item.uri + item.id === focusedId" :focused="item.uri + item.id === focusedId"
@ -59,18 +29,15 @@
</template> </template>
</DynamicScroller> </DynamicScroller>
<div <div :class="openSideBar ? 'upper-with-side-bar' : 'upper'" v-show="!heading">
:class="openSideBar ? 'upper-with-side-bar' : 'upper'" <el-button type="primary" @click="upper" circle>
v-show="!heading" <font-awesome-icon icon="arrow-up" />
>
<el-button type="primary" :icon="ElIconArrowUp" @click="upper" circle>
</el-button> </el-button>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import { ArrowUp as ElIconArrowUp } from '@element-plus/icons'
import { mapState, mapGetters } from 'vuex' import { mapState, mapGetters } from 'vuex'
import moment from 'moment' import moment from 'moment'
import Toot from '~/src/renderer/components/organisms/Toot' import Toot from '~/src/renderer/components/organisms/Toot'
@ -87,8 +54,7 @@ export default {
observer: null, observer: null,
scrollTime: null, scrollTime: null,
resizeTime: null, resizeTime: null,
loadingMore: false, loadingMore: false
ElIconArrowUp,
} }
}, },
name: 'home', name: 'home',
@ -96,17 +62,17 @@ export default {
mixins: [reloadable], mixins: [reloadable],
computed: { computed: {
...mapState('TimelineSpace/Contents/Home', { ...mapState('TimelineSpace/Contents/Home', {
timeline: (state) => state.timeline, timeline: state => state.timeline,
lazyLoading: (state) => state.lazyLoading, lazyLoading: state => state.lazyLoading,
heading: (state) => state.heading, heading: state => state.heading,
showReblogs: (state) => state.showReblogs, showReblogs: state => state.showReblogs,
showReplies: (state) => state.showReplies, showReplies: state => state.showReplies,
scrolling: (state) => state.scrolling, scrolling: state => state.scrolling
}), }),
...mapState({ ...mapState({
backgroundColor: (state) => state.App.theme.background_color, backgroundColor: state => state.App.theme.background_color,
openSideBar: (state) => state.TimelineSpace.Contents.SideBar.openSideBar, openSideBar: state => state.TimelineSpace.Contents.SideBar.openSideBar,
startReload: (state) => state.TimelineSpace.HeaderMenu.reload, startReload: state => state.TimelineSpace.HeaderMenu.reload
}), }),
...mapGetters('TimelineSpace/Modals', ['modalOpened']), ...mapGetters('TimelineSpace/Modals', ['modalOpened']),
...mapGetters('TimelineSpace/Contents/Home', ['filters']), ...mapGetters('TimelineSpace/Contents/Home', ['filters']),
@ -118,13 +84,11 @@ export default {
return true return true
} }
// Sometimes toots are deleted, so perhaps focused toot don't exist. // Sometimes toots are deleted, so perhaps focused toot don't exist.
const currentIndex = this.timeline.findIndex( const currentIndex = this.timeline.findIndex(toot => this.focusedId === toot.uri + toot.id)
(toot) => this.focusedId === toot.uri + toot.id
)
return currentIndex === -1 return currentIndex === -1
}, },
filteredTimeline() { filteredTimeline() {
return this.timeline.filter((toot) => { return this.timeline.filter(toot => {
if (toot.in_reply_to_id) { if (toot.in_reply_to_id) {
return this.showReplies return this.showReplies
} else if (toot.reblog) { } else if (toot.reblog) {
@ -133,13 +97,11 @@ export default {
return true return true
} }
}) })
}, }
}, },
mounted() { mounted() {
this.$store.commit('TimelineSpace/SideMenu/changeUnreadHomeTimeline', false) this.$store.commit('TimelineSpace/SideMenu/changeUnreadHomeTimeline', false)
document document.getElementById('scroller').addEventListener('scroll', this.onScroll)
.getElementById('scroller')
.addEventListener('scroll', this.onScroll)
Event.$on('focus-timeline', () => { Event.$on('focus-timeline', () => {
// If focusedId does not change, we have to refresh focusedId because Toot component watch change events. // If focusedId does not change, we have to refresh focusedId because Toot component watch change events.
const previousFocusedId = this.focusedId const previousFocusedId = this.focusedId
@ -157,32 +119,18 @@ export default {
this.scrollPosition.prepare() this.scrollPosition.prepare()
this.observer = new ResizeObserver(() => { this.observer = new ResizeObserver(() => {
if ( if (this.loadingMore || (this.scrollPosition && !this.heading && !this.lazyLoading && !this.scrolling)) {
this.loadingMore ||
(this.scrollPosition &&
!this.heading &&
!this.lazyLoading &&
!this.scrolling)
) {
this.resizeTime = moment() this.resizeTime = moment()
this.scrollPosition.restore() this.scrollPosition.restore()
} }
}) })
const scrollWrapper = el.getElementsByClassName( const scrollWrapper = el.getElementsByClassName('vue-recycle-scroller__item-wrapper')[0]
'vue-recycle-scroller__item-wrapper'
)[0]
this.observer.observe(scrollWrapper) this.observer.observe(scrollWrapper)
}, },
beforeUpdate() { beforeUpdate() {
if ( if (this.$store.state.TimelineSpace.SideMenu.unreadHomeTimeline && this.heading) {
this.$store.state.TimelineSpace.SideMenu.unreadHomeTimeline && this.$store.commit('TimelineSpace/SideMenu/changeUnreadHomeTimeline', false)
this.heading
) {
this.$store.commit(
'TimelineSpace/SideMenu/changeUnreadHomeTimeline',
false
)
} }
if (this.scrollPosition) { if (this.scrollPosition) {
this.scrollPosition.prepare() this.scrollPosition.prepare()
@ -195,13 +143,8 @@ export default {
destroyed() { destroyed() {
this.$store.commit('TimelineSpace/Contents/Home/changeHeading', true) this.$store.commit('TimelineSpace/Contents/Home/changeHeading', true)
this.$store.commit('TimelineSpace/Contents/Home/archiveTimeline') this.$store.commit('TimelineSpace/Contents/Home/archiveTimeline')
if ( if (document.getElementById('scroller') !== undefined && document.getElementById('scroller') !== null) {
document.getElementById('scroller') !== undefined && document.getElementById('scroller').removeEventListener('scroll', this.onScroll)
document.getElementById('scroller') !== null
) {
document
.getElementById('scroller')
.removeEventListener('scroll', this.onScroll)
document.getElementById('scroller').scrollTop = 0 document.getElementById('scroller').scrollTop = 0
} }
}, },
@ -224,7 +167,7 @@ export default {
if (this.heading && newState.length > 0) { if (this.heading && newState.length > 0) {
this.$store.dispatch('TimelineSpace/Contents/Home/saveMarker') this.$store.dispatch('TimelineSpace/Contents/Home/saveMarker')
} }
}, }
}, },
methods: { methods: {
onScroll(event) { onScroll(event) {
@ -238,36 +181,26 @@ export default {
// for lazyLoading // for lazyLoading
if ( if (
event.target.clientHeight + event.target.scrollTop >= event.target.clientHeight + event.target.scrollTop >= document.getElementById('scroller').scrollHeight - 10 &&
document.getElementById('scroller').scrollHeight - 10 &&
!this.lazyloading !this.lazyloading
) { ) {
this.$store this.$store
.dispatch( .dispatch('TimelineSpace/Contents/Home/lazyFetchTimeline', this.timeline[this.timeline.length - 1])
'TimelineSpace/Contents/Home/lazyFetchTimeline', .then(statuses => {
this.timeline[this.timeline.length - 1]
)
.then((statuses) => {
if (statuses === null) { if (statuses === null) {
return return
} }
if (statuses.length > 0) { if (statuses.length > 0) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Home/changeScrolling', true)
'TimelineSpace/Contents/Home/changeScrolling',
true
)
setTimeout(() => { setTimeout(() => {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Home/changeScrolling', false)
'TimelineSpace/Contents/Home/changeScrolling',
false
)
}, 500) }, 500)
} }
}) })
.catch(() => { .catch(() => {
this.$message({ this.$message({
message: this.$t('message.timeline_fetch_error'), message: this.$t('message.timeline_fetch_error'),
type: 'error', type: 'error'
}) })
}) })
} }
@ -282,10 +215,7 @@ export default {
const now = moment() const now = moment()
if (now.diff(this.scrollTime) >= 150) { if (now.diff(this.scrollTime) >= 150) {
this.scrollTime = null this.scrollTime = null
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Home/changeScrolling', false)
'TimelineSpace/Contents/Home/changeScrolling',
false
)
} }
}, 150) }, 150)
}, },
@ -297,13 +227,11 @@ export default {
}, },
fetchTimelineSince(since_id) { fetchTimelineSince(since_id) {
this.loadingMore = true this.loadingMore = true
this.$store this.$store.dispatch('TimelineSpace/Contents/Home/fetchTimelineSince', since_id).finally(() => {
.dispatch('TimelineSpace/Contents/Home/fetchTimelineSince', since_id) setTimeout(() => {
.finally(() => { this.loadingMore = false
setTimeout(() => { }, 500)
this.loadingMore = false })
}, 500)
})
}, },
async reload() { async reload() {
this.$store.commit('TimelineSpace/changeLoading', true) this.$store.commit('TimelineSpace/changeLoading', true)
@ -318,27 +246,19 @@ export default {
this.focusedId = null this.focusedId = null
}, },
focusNext() { focusNext() {
const currentIndex = this.timeline.findIndex( const currentIndex = this.timeline.findIndex(toot => this.focusedId === toot.uri + toot.id)
(toot) => this.focusedId === toot.uri + toot.id
)
if (currentIndex === -1) { if (currentIndex === -1) {
this.focusedId = this.timeline[0].uri + this.timeline[0].id this.focusedId = this.timeline[0].uri + this.timeline[0].id
} else if (currentIndex < this.timeline.length) { } else if (currentIndex < this.timeline.length) {
this.focusedId = this.focusedId = this.timeline[currentIndex + 1].uri + this.timeline[currentIndex + 1].id
this.timeline[currentIndex + 1].uri +
this.timeline[currentIndex + 1].id
} }
}, },
focusPrev() { focusPrev() {
const currentIndex = this.timeline.findIndex( const currentIndex = this.timeline.findIndex(toot => this.focusedId === toot.uri + toot.id)
(toot) => this.focusedId === toot.uri + toot.id
)
if (currentIndex === 0) { if (currentIndex === 0) {
this.focusedId = null this.focusedId = null
} else if (currentIndex > 0) { } else if (currentIndex > 0) {
this.focusedId = this.focusedId = this.timeline[currentIndex - 1].uri + this.timeline[currentIndex - 1].id
this.timeline[currentIndex - 1].uri +
this.timeline[currentIndex - 1].id
} }
}, },
focusToot(message) { focusToot(message) {
@ -359,8 +279,8 @@ export default {
setTimeout(() => { setTimeout(() => {
this.$store.commit('TimelineSpace/Contents/Home/changeScrolling', false) this.$store.commit('TimelineSpace/Contents/Home/changeScrolling', false)
}, 500) }, 500)
}, }
}, }
} }
</script> </script>

View File

@ -1,29 +1,9 @@
<template> <template>
<div <div name="list" class="list-timeline" v-shortkey="shortcutEnabled ? { next: ['j'] } : {}" @shortkey="handleKey">
name="list" <div v-shortkey="{ linux: ['ctrl', 'r'], mac: ['meta', 'r'] }" @shortkey="reload()"></div>
class="list-timeline" <DynamicScroller :items="timeline" :min-item-size="86" id="scroller" class="scroller" ref="scroller">
v-shortkey="shortcutEnabled ? { next: ['j'] } : {}"
@shortkey="handleKey"
>
<div
v-shortkey="{ linux: ['ctrl', 'r'], mac: ['meta', 'r'] }"
@shortkey="reload()"
></div>
<DynamicScroller
:items="timeline"
:min-item-size="86"
id="scroller"
class="scroller"
ref="scroller"
>
<template v-slot="{ item, index, active }"> <template v-slot="{ item, index, active }">
<DynamicScrollerItem <DynamicScrollerItem :item="item" :active="active" :size-dependencies="[item.uri]" :data-index="index" :watchData="true">
:item="item"
:active="active"
:size-dependencies="[item.uri]"
:data-index="index"
:watchData="true"
>
<toot <toot
:message="item" :message="item"
:focused="item.uri + item.id === focusedId" :focused="item.uri + item.id === focusedId"
@ -41,18 +21,15 @@
</DynamicScrollerItem> </DynamicScrollerItem>
</template> </template>
</DynamicScroller> </DynamicScroller>
<div <div :class="openSideBar ? 'upper-with-side-bar' : 'upper'" v-show="!heading">
:class="openSideBar ? 'upper-with-side-bar' : 'upper'" <el-button type="primary" @click="upper" circle>
v-show="!heading" <font-awesome-icon icon="arrow-up" />
>
<el-button type="primary" :icon="ElIconArrowUp" @click="upper" circle>
</el-button> </el-button>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import { ArrowUp as ElIconArrowUp } from '@element-plus/icons'
import { mapState, mapGetters } from 'vuex' import { mapState, mapGetters } from 'vuex'
import moment from 'moment' import moment from 'moment'
import Toot from '~/src/renderer/components/organisms/Toot' import Toot from '~/src/renderer/components/organisms/Toot'
@ -67,8 +44,7 @@ export default {
scrollPosition: null, scrollPosition: null,
observer: null, observer: null,
scrollTime: null, scrollTime: null,
resizeTime: null, resizeTime: null
ElIconArrowUp,
} }
}, },
name: 'list', name: 'list',
@ -77,14 +53,13 @@ export default {
mixins: [reloadable], mixins: [reloadable],
computed: { computed: {
...mapState({ ...mapState({
openSideBar: (state) => state.TimelineSpace.Contents.SideBar.openSideBar, openSideBar: state => state.TimelineSpace.Contents.SideBar.openSideBar,
backgroundColor: (state) => state.App.theme.background_color, backgroundColor: state => state.App.theme.background_color,
startReload: (state) => state.TimelineSpace.HeaderMenu.reload, startReload: state => state.TimelineSpace.HeaderMenu.reload,
timeline: (state) => state.TimelineSpace.Contents.Lists.Show.timeline, timeline: state => state.TimelineSpace.Contents.Lists.Show.timeline,
lazyLoading: (state) => lazyLoading: state => state.TimelineSpace.Contents.Lists.Show.lazyLoading,
state.TimelineSpace.Contents.Lists.Show.lazyLoading, heading: state => state.TimelineSpace.Contents.Lists.Show.heading,
heading: (state) => state.TimelineSpace.Contents.Lists.Show.heading, scrolling: state => state.TimelineSpace.Contents.Lists.Show.scrolling
scrolling: (state) => state.TimelineSpace.Contents.Lists.Show.scrolling,
}), }),
...mapGetters('TimelineSpace/Modals', ['modalOpened']), ...mapGetters('TimelineSpace/Modals', ['modalOpened']),
shortcutEnabled: function () { shortcutEnabled: function () {
@ -95,11 +70,9 @@ export default {
return true return true
} }
// Sometimes toots are deleted, so perhaps focused toot don't exist. // Sometimes toots are deleted, so perhaps focused toot don't exist.
const currentIndex = this.timeline.findIndex( const currentIndex = this.timeline.findIndex(toot => this.focusedId === toot.uri + toot.id)
(toot) => this.focusedId === toot.uri + toot.id
)
return currentIndex === -1 return currentIndex === -1
}, }
}, },
created() { created() {
this.$store.commit('TimelineSpace/Contents/changeLoading', true) this.$store.commit('TimelineSpace/Contents/changeLoading', true)
@ -108,9 +81,7 @@ export default {
}) })
}, },
mounted() { mounted() {
document document.getElementById('scroller').addEventListener('scroll', this.onScroll)
.getElementById('scroller')
.addEventListener('scroll', this.onScroll)
Event.$on('focus-timeline', () => { Event.$on('focus-timeline', () => {
// If focusedId does not change, we have to refresh focusedId because Toot component watch change events. // If focusedId does not change, we have to refresh focusedId because Toot component watch change events.
const previousFocusedId = this.focusedId const previousFocusedId = this.focusedId
@ -124,20 +95,13 @@ export default {
this.scrollPosition.prepare() this.scrollPosition.prepare()
this.observer = new ResizeObserver(() => { this.observer = new ResizeObserver(() => {
if ( if (this.scrollPosition && !this.heading && !this.lazyLoading && !this.scrolling) {
this.scrollPosition &&
!this.heading &&
!this.lazyLoading &&
!this.scrolling
) {
this.resizeTime = moment() this.resizeTime = moment()
this.scrollPosition.restore() this.scrollPosition.restore()
} }
}) })
const scrollWrapper = el.getElementsByClassName( const scrollWrapper = el.getElementsByClassName('vue-recycle-scroller__item-wrapper')[0]
'vue-recycle-scroller__item-wrapper'
)[0]
this.observer.observe(scrollWrapper) this.observer.observe(scrollWrapper)
}, },
beforeUpdate() { beforeUpdate() {
@ -161,17 +125,11 @@ export default {
}, },
focusedId: function (newState, _oldState) { focusedId: function (newState, _oldState) {
if (newState && this.heading) { if (newState && this.heading) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Lists/Show/changeHeading', false)
'TimelineSpace/Contents/Lists/Show/changeHeading',
false
)
} else if (newState === null && !this.heading) { } else if (newState === null && !this.heading) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Lists/Show/changeHeading', true)
'TimelineSpace/Contents/Lists/Show/changeHeading',
true
)
} }
}, }
}, },
beforeDestroy() { beforeDestroy() {
this.$store.dispatch('TimelineSpace/Contents/Lists/Show/stopStreaming') this.$store.dispatch('TimelineSpace/Contents/Lists/Show/stopStreaming')
@ -181,56 +139,35 @@ export default {
this.$store.commit('TimelineSpace/Contents/Lists/Show/changeHeading', true) this.$store.commit('TimelineSpace/Contents/Lists/Show/changeHeading', true)
this.$store.commit('TimelineSpace/Contents/Lists/Show/archiveTimeline') this.$store.commit('TimelineSpace/Contents/Lists/Show/archiveTimeline')
this.$store.commit('TimelineSpace/Contents/Lists/Show/clearTimeline') this.$store.commit('TimelineSpace/Contents/Lists/Show/clearTimeline')
if ( if (document.getElementById('scroller') !== undefined && document.getElementById('scroller') !== null) {
document.getElementById('scroller') !== undefined && document.getElementById('scroller').removeEventListener('scroll', this.onScroll)
document.getElementById('scroller') !== null
) {
document
.getElementById('scroller')
.removeEventListener('scroll', this.onScroll)
document.getElementById('scroller').scrollTop = 0 document.getElementById('scroller').scrollTop = 0
} }
}, },
methods: { methods: {
async load() { async load() {
await this.$store.dispatch( await this.$store.dispatch('TimelineSpace/Contents/Lists/Show/stopStreaming')
'TimelineSpace/Contents/Lists/Show/stopStreaming'
)
try { try {
await this.$store.dispatch( await this.$store.dispatch('TimelineSpace/Contents/Lists/Show/fetchTimeline', this.list_id)
'TimelineSpace/Contents/Lists/Show/fetchTimeline',
this.list_id
)
} catch (err) { } catch (err) {
this.$message({ this.$message({
message: this.$t('message.timeline_fetch_error'), message: this.$t('message.timeline_fetch_error'),
type: 'error', type: 'error'
}) })
} }
this.$store this.$store.dispatch('TimelineSpace/Contents/Lists/Show/startStreaming', this.list_id).catch(() => {
.dispatch( this.$message({
'TimelineSpace/Contents/Lists/Show/startStreaming', message: this.$t('message.start_streaming_error'),
this.list_id type: 'error'
)
.catch(() => {
this.$message({
message: this.$t('message.start_streaming_error'),
type: 'error',
})
}) })
})
return 'started' return 'started'
}, },
updateToot(message) { updateToot(message) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Lists/Show/updateToot', message)
'TimelineSpace/Contents/Lists/Show/updateToot',
message
)
}, },
deleteToot(message) { deleteToot(message) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Lists/Show/deleteToot', message.id)
'TimelineSpace/Contents/Lists/Show/deleteToot',
message.id
)
}, },
onScroll(event) { onScroll(event) {
if (moment().diff(this.resizeTime) < 500) { if (moment().diff(this.resizeTime) < 500) {
@ -238,67 +175,48 @@ export default {
} }
this.scrollTime = moment() this.scrollTime = moment()
if (!this.scrolling) { if (!this.scrolling) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Lists/Show/changeScrolling', true)
'TimelineSpace/Contents/Lists/Show/changeScrolling',
true
)
} }
if ( if (
event.target.clientHeight + event.target.scrollTop >= event.target.clientHeight + event.target.scrollTop >= document.getElementById('scroller').scrollHeight - 10 &&
document.getElementById('scroller').scrollHeight - 10 &&
!this.lazyloading !this.lazyloading
) { ) {
this.$store this.$store
.dispatch('TimelineSpace/Contents/Lists/Show/lazyFetchTimeline', { .dispatch('TimelineSpace/Contents/Lists/Show/lazyFetchTimeline', {
list_id: this.list_id, list_id: this.list_id,
status: this.timeline[this.timeline.length - 1], status: this.timeline[this.timeline.length - 1]
}) })
.then((statuses) => { .then(statuses => {
if (statuses === null) { if (statuses === null) {
return return
} }
if (statuses.length > 0) { if (statuses.length > 0) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Lists/Show/changeScrolling', true)
'TimelineSpace/Contents/Lists/Show/changeScrolling',
true
)
setTimeout(() => { setTimeout(() => {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Lists/Show/changeScrolling', false)
'TimelineSpace/Contents/Lists/Show/changeScrolling',
false
)
}, 500) }, 500)
} }
}) })
.catch(() => { .catch(() => {
this.$message({ this.$message({
message: this.$t('message.timeline_fetch_error'), message: this.$t('message.timeline_fetch_error'),
type: 'error', type: 'error'
}) })
}) })
} }
if (event.target.scrollTop > 10 && this.heading) { if (event.target.scrollTop > 10 && this.heading) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Lists/Show/changeHeading', false)
'TimelineSpace/Contents/Lists/Show/changeHeading',
false
)
} else if (event.target.scrollTop <= 10 && !this.heading) { } else if (event.target.scrollTop <= 10 && !this.heading) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Lists/Show/changeHeading', true)
'TimelineSpace/Contents/Lists/Show/changeHeading',
true
)
} }
setTimeout(() => { setTimeout(() => {
const now = moment() const now = moment()
if (now.diff(this.scrollTime) >= 150) { if (now.diff(this.scrollTime) >= 150) {
this.scrollTime = null this.scrollTime = null
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Lists/Show/changeScrolling', false)
'TimelineSpace/Contents/Lists/Show/changeScrolling',
false
)
} }
}, 150) }, 150)
}, },
@ -306,31 +224,19 @@ export default {
this.$store.commit('TimelineSpace/changeLoading', true) this.$store.commit('TimelineSpace/changeLoading', true)
try { try {
await this.reloadable() await this.reloadable()
await this.$store.dispatch( await this.$store.dispatch('TimelineSpace/Contents/Lists/Show/stopStreaming')
'TimelineSpace/Contents/Lists/Show/stopStreaming' await this.$store.dispatch('TimelineSpace/Contents/Lists/Show/fetchTimeline', this.list_id).catch(() => {
) this.$message({
await this.$store message: this.$t('message.timeline_fetch_error'),
.dispatch( type: 'error'
'TimelineSpace/Contents/Lists/Show/fetchTimeline',
this.list_id
)
.catch(() => {
this.$message({
message: this.$t('message.timeline_fetch_error'),
type: 'error',
})
}) })
this.$store })
.dispatch( this.$store.dispatch('TimelineSpace/Contents/Lists/Show/startStreaming', this.list_id).catch(() => {
'TimelineSpace/Contents/Lists/Show/startStreaming', this.$message({
this.list_id message: this.$t('message.start_streaming_error'),
) type: 'error'
.catch(() => {
this.$message({
message: this.$t('message.start_streaming_error'),
type: 'error',
})
}) })
})
} finally { } finally {
this.$store.commit('TimelineSpace/changeLoading', false) this.$store.commit('TimelineSpace/changeLoading', false)
} }
@ -340,27 +246,19 @@ export default {
this.focusedId = null this.focusedId = null
}, },
focusNext() { focusNext() {
const currentIndex = this.timeline.findIndex( const currentIndex = this.timeline.findIndex(toot => this.focusedId === toot.uri + toot.id)
(toot) => this.focusedId === toot.uri + toot.id
)
if (currentIndex === -1) { if (currentIndex === -1) {
this.focusedId = this.timeline[0].uri + this.timeline[0].id this.focusedId = this.timeline[0].uri + this.timeline[0].id
} else if (currentIndex < this.timeline.length) { } else if (currentIndex < this.timeline.length) {
this.focusedId = this.focusedId = this.timeline[currentIndex + 1].uri + this.timeline[currentIndex + 1].id
this.timeline[currentIndex + 1].uri +
this.timeline[currentIndex + 1].id
} }
}, },
focusPrev() { focusPrev() {
const currentIndex = this.timeline.findIndex( const currentIndex = this.timeline.findIndex(toot => this.focusedId === toot.uri + toot.id)
(toot) => this.focusedId === toot.uri + toot.id
)
if (currentIndex === 0) { if (currentIndex === 0) {
this.focusedId = null this.focusedId = null
} else if (currentIndex > 0) { } else if (currentIndex > 0) {
this.focusedId = this.focusedId = this.timeline[currentIndex - 1].uri + this.timeline[currentIndex - 1].id
this.timeline[currentIndex - 1].uri +
this.timeline[currentIndex - 1].id
} }
}, },
focusToot(message) { focusToot(message) {
@ -377,18 +275,12 @@ export default {
} }
}, },
sizeChanged() { sizeChanged() {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Lists/Show/changeScrolling', true)
'TimelineSpace/Contents/Lists/Show/changeScrolling',
true
)
setTimeout(() => { setTimeout(() => {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Lists/Show/changeScrolling', false)
'TimelineSpace/Contents/Lists/Show/changeScrolling',
false
)
}, 500) }, 500)
}, }
}, }
} }
</script> </script>

View File

@ -1,28 +1,9 @@
<template> <template>
<div <div id="local" v-shortkey="shortcutEnabled ? { next: ['j'] } : {}" @shortkey="handleKey">
id="local" <div v-shortkey="{ linux: ['ctrl', 'r'], mac: ['meta', 'r'] }" @shortkey="reload()"></div>
v-shortkey="shortcutEnabled ? { next: ['j'] } : {}" <DynamicScroller :items="timeline" :min-item-size="86" id="scroller" class="scroller" ref="scroller">
@shortkey="handleKey"
>
<div
v-shortkey="{ linux: ['ctrl', 'r'], mac: ['meta', 'r'] }"
@shortkey="reload()"
></div>
<DynamicScroller
:items="timeline"
:min-item-size="86"
id="scroller"
class="scroller"
ref="scroller"
>
<template v-slot="{ item, index, active }"> <template v-slot="{ item, index, active }">
<DynamicScrollerItem <DynamicScrollerItem :item="item" :active="active" :size-dependencies="[item.uri]" :data-index="index" :watchData="true">
:item="item"
:active="active"
:size-dependencies="[item.uri]"
:data-index="index"
:watchData="true"
>
<toot <toot
:message="item" :message="item"
:focused="item.uri + item.id === focusedId" :focused="item.uri + item.id === focusedId"
@ -40,18 +21,15 @@
</DynamicScrollerItem> </DynamicScrollerItem>
</template> </template>
</DynamicScroller> </DynamicScroller>
<div <div :class="openSideBar ? 'upper-with-side-bar' : 'upper'" v-show="!heading">
:class="openSideBar ? 'upper-with-side-bar' : 'upper'" <el-button type="primary" @click="upper" circle>
v-show="!heading" <font-awesome-icon icon="arrow-up" />
>
<el-button type="primary" :icon="ElIconArrowUp" @click="upper" circle>
</el-button> </el-button>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import { ArrowUp as ElIconArrowUp } from '@element-plus/icons'
import { mapState, mapGetters } from 'vuex' import { mapState, mapGetters } from 'vuex'
import moment from 'moment' import moment from 'moment'
import Toot from '~/src/renderer/components/organisms/Toot' import Toot from '~/src/renderer/components/organisms/Toot'
@ -66,8 +44,7 @@ export default {
scrollPosition: null, scrollPosition: null,
observer: null, observer: null,
scrollTime: null, scrollTime: null,
resizeTime: null, resizeTime: null
ElIconArrowUp,
} }
}, },
name: 'local', name: 'local',
@ -75,16 +52,16 @@ export default {
mixins: [reloadable], mixins: [reloadable],
computed: { computed: {
...mapState('TimelineSpace/Contents/Local', { ...mapState('TimelineSpace/Contents/Local', {
timeline: (state) => state.timeline, timeline: state => state.timeline,
lazyLoading: (state) => state.lazyLoading, lazyLoading: state => state.lazyLoading,
heading: (state) => state.heading, heading: state => state.heading,
scrolling: (state) => state.scrolling, scrolling: state => state.scrolling
}), }),
...mapState({ ...mapState({
openSideBar: (state) => state.TimelineSpace.Contents.SideBar.openSideBar, openSideBar: state => state.TimelineSpace.Contents.SideBar.openSideBar,
backgroundColor: (state) => state.App.theme.background_color, backgroundColor: state => state.App.theme.background_color,
startReload: (state) => state.TimelineSpace.HeaderMenu.reload, startReload: state => state.TimelineSpace.HeaderMenu.reload,
unreadNotification: (state) => state.TimelineSpace.unreadNotification, unreadNotification: state => state.TimelineSpace.unreadNotification
}), }),
...mapGetters('TimelineSpace/Modals', ['modalOpened']), ...mapGetters('TimelineSpace/Modals', ['modalOpened']),
shortcutEnabled: function () { shortcutEnabled: function () {
@ -95,23 +72,16 @@ export default {
return true return true
} }
// Sometimes toots are deleted, so perhaps focused toot don't exist. // Sometimes toots are deleted, so perhaps focused toot don't exist.
const currentIndex = this.timeline.findIndex( const currentIndex = this.timeline.findIndex(toot => this.focusedId === toot.uri + toot.id)
(toot) => this.focusedId === toot.uri + toot.id
)
return currentIndex === -1 return currentIndex === -1
}, }
}, },
async mounted() { async mounted() {
this.$store.commit( this.$store.commit('TimelineSpace/SideMenu/changeUnreadLocalTimeline', false)
'TimelineSpace/SideMenu/changeUnreadLocalTimeline', document.getElementById('scroller').addEventListener('scroll', this.onScroll)
false
)
document
.getElementById('scroller')
.addEventListener('scroll', this.onScroll)
if (!this.unreadNotification.local) { if (!this.unreadNotification.local) {
this.$store.commit('TimelineSpace/Contents/changeLoading', true) this.$store.commit('TimelineSpace/Contents/changeLoading', true)
await this.initialize().finally((_) => { await this.initialize().finally(_ => {
this.$store.commit('TimelineSpace/Contents/changeLoading', false) this.$store.commit('TimelineSpace/Contents/changeLoading', false)
}) })
} }
@ -129,31 +99,18 @@ export default {
this.scrollPosition.prepare() this.scrollPosition.prepare()
this.observer = new ResizeObserver(() => { this.observer = new ResizeObserver(() => {
if ( if (this.scrollPosition && !this.heading && !this.lazyLoading && !this.scrolling) {
this.scrollPosition &&
!this.heading &&
!this.lazyLoading &&
!this.scrolling
) {
this.resizeTime = moment() this.resizeTime = moment()
this.scrollPosition.restore() this.scrollPosition.restore()
} }
}) })
const scrollWrapper = el.getElementsByClassName( const scrollWrapper = el.getElementsByClassName('vue-recycle-scroller__item-wrapper')[0]
'vue-recycle-scroller__item-wrapper'
)[0]
this.observer.observe(scrollWrapper) this.observer.observe(scrollWrapper)
}, },
beforeUpdate() { beforeUpdate() {
if ( if (this.$store.state.TimelineSpace.SideMenu.unreadLocalTimeline && this.heading) {
this.$store.state.TimelineSpace.SideMenu.unreadLocalTimeline && this.$store.commit('TimelineSpace/SideMenu/changeUnreadLocalTimeline', false)
this.heading
) {
this.$store.commit(
'TimelineSpace/SideMenu/changeUnreadLocalTimeline',
false
)
} }
if (this.scrollPosition) { if (this.scrollPosition) {
this.scrollPosition.prepare() this.scrollPosition.prepare()
@ -173,13 +130,8 @@ export default {
if (!this.unreadNotification.local) { if (!this.unreadNotification.local) {
this.$store.commit('TimelineSpace/Contents/Local/clearTimeline') this.$store.commit('TimelineSpace/Contents/Local/clearTimeline')
} }
if ( if (document.getElementById('scroller') !== undefined && document.getElementById('scroller') !== null) {
document.getElementById('scroller') !== undefined && document.getElementById('scroller').removeEventListener('scroll', this.onScroll)
document.getElementById('scroller') !== null
) {
document
.getElementById('scroller')
.removeEventListener('scroll', this.onScroll)
document.getElementById('scroller').scrollTop = 0 document.getElementById('scroller').scrollTop = 0
} }
}, },
@ -197,18 +149,16 @@ export default {
} else if (newState === null && !this.heading) { } else if (newState === null && !this.heading) {
this.$store.commit('TimelineSpace/Contents/Local/changeHeading', true) this.$store.commit('TimelineSpace/Contents/Local/changeHeading', true)
} }
}, }
}, },
methods: { methods: {
async initialize() { async initialize() {
await this.$store await this.$store.dispatch('TimelineSpace/Contents/Local/fetchLocalTimeline').catch(_ => {
.dispatch('TimelineSpace/Contents/Local/fetchLocalTimeline') this.$message({
.catch((_) => { message: this.$t('message.timeline_fetch_error'),
this.$message({ type: 'error'
message: this.$t('message.timeline_fetch_error'),
type: 'error',
})
}) })
})
await this.$store.dispatch('TimelineSpace/bindLocalStreaming') await this.$store.dispatch('TimelineSpace/bindLocalStreaming')
this.$store.dispatch('TimelineSpace/startLocalStreaming') this.$store.dispatch('TimelineSpace/startLocalStreaming')
}, },
@ -228,36 +178,26 @@ export default {
} }
if ( if (
event.target.clientHeight + event.target.scrollTop >= event.target.clientHeight + event.target.scrollTop >= document.getElementById('scroller').scrollHeight - 10 &&
document.getElementById('scroller').scrollHeight - 10 &&
!this.lazyloading !this.lazyloading
) { ) {
this.$store this.$store
.dispatch( .dispatch('TimelineSpace/Contents/Local/lazyFetchTimeline', this.timeline[this.timeline.length - 1])
'TimelineSpace/Contents/Local/lazyFetchTimeline', .then(statuses => {
this.timeline[this.timeline.length - 1]
)
.then((statuses) => {
if (statuses === null) { if (statuses === null) {
return return
} }
if (statuses.length > 0) { if (statuses.length > 0) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Local/changeScrolling', true)
'TimelineSpace/Contents/Local/changeScrolling',
true
)
setTimeout(() => { setTimeout(() => {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Local/changeScrolling', false)
'TimelineSpace/Contents/Local/changeScrolling',
false
)
}, 500) }, 500)
} }
}) })
.catch(() => { .catch(() => {
this.$message({ this.$message({
message: this.$t('message.timeline_fetch_error'), message: this.$t('message.timeline_fetch_error'),
type: 'error', type: 'error'
}) })
}) })
} }
@ -271,10 +211,7 @@ export default {
const now = moment() const now = moment()
if (now.diff(this.scrollTime) >= 150) { if (now.diff(this.scrollTime) >= 150) {
this.scrollTime = null this.scrollTime = null
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Local/changeScrolling', false)
'TimelineSpace/Contents/Local/changeScrolling',
false
)
} }
}, 150) }, 150)
}, },
@ -291,27 +228,19 @@ export default {
this.focusedId = null this.focusedId = null
}, },
focusNext() { focusNext() {
const currentIndex = this.timeline.findIndex( const currentIndex = this.timeline.findIndex(toot => this.focusedId === toot.uri + toot.id)
(toot) => this.focusedId === toot.uri + toot.id
)
if (currentIndex === -1) { if (currentIndex === -1) {
this.focusedId = this.timeline[0].uri + this.timeline[0].id this.focusedId = this.timeline[0].uri + this.timeline[0].id
} else if (currentIndex < this.timeline.length) { } else if (currentIndex < this.timeline.length) {
this.focusedId = this.focusedId = this.timeline[currentIndex + 1].uri + this.timeline[currentIndex + 1].id
this.timeline[currentIndex + 1].uri +
this.timeline[currentIndex + 1].id
} }
}, },
focusPrev() { focusPrev() {
const currentIndex = this.timeline.findIndex( const currentIndex = this.timeline.findIndex(toot => this.focusedId === toot.uri + toot.id)
(toot) => this.focusedId === toot.uri + toot.id
)
if (currentIndex === 0) { if (currentIndex === 0) {
this.focusedId = null this.focusedId = null
} else if (currentIndex > 0) { } else if (currentIndex > 0) {
this.focusedId = this.focusedId = this.timeline[currentIndex - 1].uri + this.timeline[currentIndex - 1].id
this.timeline[currentIndex - 1].uri +
this.timeline[currentIndex - 1].id
} }
}, },
focusToot(message) { focusToot(message) {
@ -330,13 +259,10 @@ export default {
sizeChanged() { sizeChanged() {
this.$store.commit('TimelineSpace/Contents/Local/changeScrolling', true) this.$store.commit('TimelineSpace/Contents/Local/changeScrolling', true)
setTimeout(() => { setTimeout(() => {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Local/changeScrolling', false)
'TimelineSpace/Contents/Local/changeScrolling',
false
)
}, 500) }, 500)
}, }
}, }
} }
</script> </script>

View File

@ -1,45 +1,15 @@
<template> <template>
<div <div id="mentions" v-shortkey="shortcutEnabled ? { next: ['j'] } : {}" @shortkey="handleKey">
id="mentions" <div v-shortkey="{ linux: ['ctrl', 'r'], mac: ['meta', 'r'] }" @shortkey="reload()"></div>
v-shortkey="shortcutEnabled ? { next: ['j'] } : {}" <DynamicScroller :items="mentions" :min-item-size="86" id="scroller" class="scroller" ref="scroller">
@shortkey="handleKey"
>
<div
v-shortkey="{ linux: ['ctrl', 'r'], mac: ['meta', 'r'] }"
@shortkey="reload()"
></div>
<DynamicScroller
:items="mentions"
:min-item-size="86"
id="scroller"
class="scroller"
ref="scroller"
>
<template v-slot="{ item, index, active }"> <template v-slot="{ item, index, active }">
<template v-if="item.id === 'loading-card'"> <template v-if="item.id === 'loading-card'">
<DynamicScrollerItem <DynamicScrollerItem :item="item" :active="active" :size-dependencies="[item.id]" :data-index="index" :watchData="true">
:item="item" <StatusLoading :since_id="item.since_id" :max_id="item.max_id" :loading="loadingMore" @load_since="fetchMentionsSince" />
:active="active"
:size-dependencies="[item.id]"
:data-index="index"
:watchData="true"
>
<StatusLoading
:since_id="item.since_id"
:max_id="item.max_id"
:loading="loadingMore"
@load_since="fetchMentionsSince"
/>
</DynamicScrollerItem> </DynamicScrollerItem>
</template> </template>
<template v-else> <template v-else>
<DynamicScrollerItem <DynamicScrollerItem :item="item" :active="active" :size-dependencies="[item.url]" :data-index="index" :watchData="true">
:item="item"
:active="active"
:size-dependencies="[item.url]"
:data-index="index"
:watchData="true"
>
<notification <notification
:message="item" :message="item"
:focused="item.id === focusedId" :focused="item.id === focusedId"
@ -57,18 +27,15 @@
</template> </template>
</template> </template>
</DynamicScroller> </DynamicScroller>
<div <div :class="openSideBar ? 'upper-with-side-bar' : 'upper'" v-show="!heading">
:class="openSideBar ? 'upper-with-side-bar' : 'upper'" <el-button type="primary" @click="upper" circle>
v-show="!heading" <font-awesome-icon icon="arrow-up" />
>
<el-button type="primary" :icon="ElIconArrowUp" @click="upper" circle>
</el-button> </el-button>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import { ArrowUp as ElIconArrowUp } from '@element-plus/icons'
import { mapState, mapGetters } from 'vuex' import { mapState, mapGetters } from 'vuex'
import moment from 'moment' import moment from 'moment'
import Notification from '~/src/renderer/components/organisms/Notification' import Notification from '~/src/renderer/components/organisms/Notification'
@ -85,8 +52,7 @@ export default {
observer: null, observer: null,
scrollTime: null, scrollTime: null,
resizeTime: null, resizeTime: null,
loadingMore: false, loadingMore: false
ElIconArrowUp,
} }
}, },
name: 'mentions', name: 'mentions',
@ -94,18 +60,18 @@ export default {
mixins: [reloadable], mixins: [reloadable],
computed: { computed: {
...mapState('App', { ...mapState('App', {
backgroundColor: (state) => state.theme.background_color, backgroundColor: state => state.theme.background_color
}), }),
...mapState('TimelineSpace/HeaderMenu', { ...mapState('TimelineSpace/HeaderMenu', {
startReload: (state) => state.reload, startReload: state => state.reload
}), }),
...mapState('TimelineSpace/Contents/SideBar', { ...mapState('TimelineSpace/Contents/SideBar', {
openSideBar: (state) => state.openSideBar, openSideBar: state => state.openSideBar
}), }),
...mapState('TimelineSpace/Contents/Mentions', { ...mapState('TimelineSpace/Contents/Mentions', {
lazyLoading: (state) => state.lazyLoading, lazyLoading: state => state.lazyLoading,
heading: (state) => state.heading, heading: state => state.heading,
scrolling: (state) => state.scrolling, scrolling: state => state.scrolling
}), }),
...mapGetters('TimelineSpace/Modals', ['modalOpened']), ...mapGetters('TimelineSpace/Modals', ['modalOpened']),
...mapGetters('TimelineSpace/Contents/Mentions', ['mentions']), ...mapGetters('TimelineSpace/Contents/Mentions', ['mentions']),
@ -117,17 +83,13 @@ export default {
return true return true
} }
// Sometimes toots are deleted, so perhaps focused toot don't exist. // Sometimes toots are deleted, so perhaps focused toot don't exist.
const currentIndex = this.mentions.findIndex( const currentIndex = this.mentions.findIndex(toot => this.focusedId === toot.id)
(toot) => this.focusedId === toot.id
)
return currentIndex === -1 return currentIndex === -1
}, }
}, },
mounted() { mounted() {
this.$store.commit('TimelineSpace/SideMenu/changeUnreadMentions', false) this.$store.commit('TimelineSpace/SideMenu/changeUnreadMentions', false)
document document.getElementById('scroller').addEventListener('scroll', this.onScroll)
.getElementById('scroller')
.addEventListener('scroll', this.onScroll)
Event.$on('focus-timeline', () => { Event.$on('focus-timeline', () => {
// If focusedId does not change, we have to refresh focusedId because Toot component watch change events. // If focusedId does not change, we have to refresh focusedId because Toot component watch change events.
const previousFocusedId = this.focusedId const previousFocusedId = this.focusedId
@ -145,28 +107,17 @@ export default {
this.scrollPosition.prepare() this.scrollPosition.prepare()
this.observer = new ResizeObserver(() => { this.observer = new ResizeObserver(() => {
if ( if (this.loadingMore || (this.scrollPosition && !this.heading && !this.lazyLoading && !this.scrolling)) {
this.loadingMore ||
(this.scrollPosition &&
!this.heading &&
!this.lazyLoading &&
!this.scrolling)
) {
this.resizeTime = moment() this.resizeTime = moment()
this.scrollPosition.restore() this.scrollPosition.restore()
} }
}) })
const scrollWrapper = el.getElementsByClassName( const scrollWrapper = el.getElementsByClassName('vue-recycle-scroller__item-wrapper')[0]
'vue-recycle-scroller__item-wrapper'
)[0]
this.observer.observe(scrollWrapper) this.observer.observe(scrollWrapper)
}, },
beforeUpdate() { beforeUpdate() {
if ( if (this.$store.state.TimelineSpace.SideMenu.unreadMentions && this.heading) {
this.$store.state.TimelineSpace.SideMenu.unreadMentions &&
this.heading
) {
this.$store.commit('TimelineSpace/SideMenu/changeUnreadMentions', false) this.$store.commit('TimelineSpace/SideMenu/changeUnreadMentions', false)
} }
if (this.scrollPosition) { if (this.scrollPosition) {
@ -180,13 +131,8 @@ export default {
destroyed() { destroyed() {
this.$store.commit('TimelineSpace/Contents/Mentions/changeHeading', true) this.$store.commit('TimelineSpace/Contents/Mentions/changeHeading', true)
this.$store.commit('TimelineSpace/Contents/Mentions/archiveMentions') this.$store.commit('TimelineSpace/Contents/Mentions/archiveMentions')
if ( if (document.getElementById('scroller') !== undefined && document.getElementById('scroller') !== null) {
document.getElementById('scroller') !== undefined && document.getElementById('scroller').removeEventListener('scroll', this.onScroll)
document.getElementById('scroller') !== null
) {
document
.getElementById('scroller')
.removeEventListener('scroll', this.onScroll)
document.getElementById('scroller').scrollTop = 0 document.getElementById('scroller').scrollTop = 0
} }
}, },
@ -200,22 +146,16 @@ export default {
}, },
focusedId: function (newState, _oldState) { focusedId: function (newState, _oldState) {
if (newState && this.heading) { if (newState && this.heading) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Mentions/changeHeading', false)
'TimelineSpace/Contents/Mentions/changeHeading',
false
)
} else if (newState === null && !this.heading) { } else if (newState === null && !this.heading) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Mentions/changeHeading', true)
'TimelineSpace/Contents/Mentions/changeHeading',
true
)
} }
}, },
mentions: function (newState, _oldState) { mentions: function (newState, _oldState) {
if (this.heading && newState.length > 0) { if (this.heading && newState.length > 0) {
this.$store.dispatch('TimelineSpace/Contents/Mentions/saveMarker') this.$store.dispatch('TimelineSpace/Contents/Mentions/saveMarker')
} }
}, }
}, },
methods: { methods: {
onScroll(event) { onScroll(event) {
@ -224,58 +164,39 @@ export default {
} }
this.scrollTime = moment() this.scrollTime = moment()
if (!this.scrolling) { if (!this.scrolling) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Mentions/changeScrolling', true)
'TimelineSpace/Contents/Mentions/changeScrolling',
true
)
} }
// for lazyLoading // for lazyLoading
if ( if (
event.target.clientHeight + event.target.scrollTop >= event.target.clientHeight + event.target.scrollTop >= document.getElementById('scroller').scrollHeight - 10 &&
document.getElementById('scroller').scrollHeight - 10 &&
!this.lazyloading !this.lazyloading
) { ) {
this.$store this.$store
.dispatch( .dispatch('TimelineSpace/Contents/Mentions/lazyFetchMentions', this.mentions[this.mentions.length - 1])
'TimelineSpace/Contents/Mentions/lazyFetchMentions', .then(statuses => {
this.mentions[this.mentions.length - 1]
)
.then((statuses) => {
if (statuses === null) { if (statuses === null) {
return return
} }
if (statuses.length > 0) { if (statuses.length > 0) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Mentions/changeScrolling', true)
'TimelineSpace/Contents/Mentions/changeScrolling',
true
)
setTimeout(() => { setTimeout(() => {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Mentions/changeScrolling', false)
'TimelineSpace/Contents/Mentions/changeScrolling',
false
)
}, 500) }, 500)
} }
}) })
.catch(() => { .catch(() => {
this.$message({ this.$message({
message: this.$t('message.timeline_fetch_error'), message: this.$t('message.timeline_fetch_error'),
type: 'error', type: 'error'
}) })
}) })
} }
if (event.target.scrollTop > 10 && this.heading) { if (event.target.scrollTop > 10 && this.heading) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Mentions/changeHeading', false)
'TimelineSpace/Contents/Mentions/changeHeading',
false
)
} else if (event.target.scrollTop <= 10 && !this.heading) { } else if (event.target.scrollTop <= 10 && !this.heading) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Mentions/changeHeading', true)
'TimelineSpace/Contents/Mentions/changeHeading',
true
)
this.$store.dispatch('TimelineSpace/Contents/Mentions/saveMarker') this.$store.dispatch('TimelineSpace/Contents/Mentions/saveMarker')
} }
@ -283,25 +204,17 @@ export default {
const now = moment() const now = moment()
if (now.diff(this.scrollTime) >= 150) { if (now.diff(this.scrollTime) >= 150) {
this.scrollTime = null this.scrollTime = null
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Mentions/changeScrolling', false)
'TimelineSpace/Contents/Mentions/changeScrolling',
false
)
} }
}, 150) }, 150)
}, },
fetchMentionsSince(since_id) { fetchMentionsSince(since_id) {
this.loadingMore = true this.loadingMore = true
this.$store this.$store.dispatch('TimelineSpace/Contents/Mentions/fetchMentionsSince', since_id).finally(() => {
.dispatch( setTimeout(() => {
'TimelineSpace/Contents/Mentions/fetchMentionsSince', this.loadingMore = false
since_id }, 500)
) })
.finally(() => {
setTimeout(() => {
this.loadingMore = false
}, 500)
})
}, },
async reload() { async reload() {
this.$store.commit('TimelineSpace/changeLoading', true) this.$store.commit('TimelineSpace/changeLoading', true)
@ -319,9 +232,7 @@ export default {
this.focusedId = null this.focusedId = null
}, },
focusNext() { focusNext() {
const currentIndex = this.mentions.findIndex( const currentIndex = this.mentions.findIndex(toot => this.focusedId === toot.id)
(toot) => this.focusedId === toot.id
)
if (currentIndex === -1) { if (currentIndex === -1) {
this.focusedId = this.mentions[0].id this.focusedId = this.mentions[0].id
} else if (currentIndex < this.mentions.length) { } else if (currentIndex < this.mentions.length) {
@ -329,9 +240,7 @@ export default {
} }
}, },
focusPrev() { focusPrev() {
const currentIndex = this.mentions.findIndex( const currentIndex = this.mentions.findIndex(toot => this.focusedId === toot.id)
(toot) => this.focusedId === toot.id
)
if (currentIndex === 0) { if (currentIndex === 0) {
this.focusedId = null this.focusedId = null
} else if (currentIndex > 0) { } else if (currentIndex > 0) {
@ -352,18 +261,12 @@ export default {
} }
}, },
sizeChanged() { sizeChanged() {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Mentions/changeScrolling', true)
'TimelineSpace/Contents/Mentions/changeScrolling',
true
)
setTimeout(() => { setTimeout(() => {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Mentions/changeScrolling', false)
'TimelineSpace/Contents/Mentions/changeScrolling',
false
)
}, 500) }, 500)
}, }
}, }
} }
</script> </script>

View File

@ -1,45 +1,15 @@
<template> <template>
<div <div id="notifications" v-shortkey="shortcutEnabled ? { next: ['j'] } : {}" @shortkey="handleKey">
id="notifications" <div v-shortkey="{ linux: ['ctrl', 'r'], mac: ['meta', 'r'] }" @shortkey="reload()"></div>
v-shortkey="shortcutEnabled ? { next: ['j'] } : {}" <DynamicScroller :items="handledNotifications" :min-item-size="20" id="scroller" class="scroller" ref="scroller">
@shortkey="handleKey"
>
<div
v-shortkey="{ linux: ['ctrl', 'r'], mac: ['meta', 'r'] }"
@shortkey="reload()"
></div>
<DynamicScroller
:items="handledNotifications"
:min-item-size="20"
id="scroller"
class="scroller"
ref="scroller"
>
<template v-slot="{ item, index, active }"> <template v-slot="{ item, index, active }">
<template v-if="item.id === 'loading-card'"> <template v-if="item.id === 'loading-card'">
<DynamicScrollerItem <DynamicScrollerItem :item="item" :active="active" :size-dependencies="[item.id]" :data-index="index" :watchData="true">
:item="item" <StatusLoading :since_id="item.since_id" :max_id="item.max_id" :loading="loadingMore" @load_since="fetchNotificationsSince" />
:active="active"
:size-dependencies="[item.id]"
:data-index="index"
:watchData="true"
>
<StatusLoading
:since_id="item.since_id"
:max_id="item.max_id"
:loading="loadingMore"
@load_since="fetchNotificationsSince"
/>
</DynamicScrollerItem> </DynamicScrollerItem>
</template> </template>
<template v-else> <template v-else>
<DynamicScrollerItem <DynamicScrollerItem :item="item" :active="active" :size-dependencies="[item.url]" :data-index="index" :watchData="true">
:item="item"
:active="active"
:size-dependencies="[item.url]"
:data-index="index"
:watchData="true"
>
<notification <notification
:message="item" :message="item"
:focused="item.id === focusedId" :focused="item.id === focusedId"
@ -56,18 +26,15 @@
</template> </template>
</template> </template>
</DynamicScroller> </DynamicScroller>
<div <div :class="openSideBar ? 'upper-with-side-bar' : 'upper'" v-show="!heading">
:class="openSideBar ? 'upper-with-side-bar' : 'upper'" <el-button type="primary" @click="upper" circle>
v-show="!heading" <font-awesome-icon icon="arrow-up" />
>
<el-button type="primary" :icon="ElIconArrowUp" @click="upper" circle>
</el-button> </el-button>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import { ArrowUp as ElIconArrowUp } from '@element-plus/icons'
import { mapState, mapGetters } from 'vuex' import { mapState, mapGetters } from 'vuex'
import moment from 'moment' import moment from 'moment'
import Notification from '~/src/renderer/components/organisms/Notification' import Notification from '~/src/renderer/components/organisms/Notification'
@ -84,8 +51,7 @@ export default {
observer: null, observer: null,
scrollTime: null, scrollTime: null,
resizeTime: null, resizeTime: null,
loadingMore: false, loadingMore: false
ElIconArrowUp,
} }
}, },
name: 'notifications', name: 'notifications',
@ -93,20 +59,17 @@ export default {
mixins: [reloadable], mixins: [reloadable],
computed: { computed: {
...mapState({ ...mapState({
openSideBar: (state) => state.TimelineSpace.Contents.SideBar.openSideBar, openSideBar: state => state.TimelineSpace.Contents.SideBar.openSideBar,
startReload: (state) => state.TimelineSpace.HeaderMenu.reload, startReload: state => state.TimelineSpace.HeaderMenu.reload,
backgroundColor: (state) => state.App.theme.background_color, backgroundColor: state => state.App.theme.background_color
}), }),
...mapState('TimelineSpace/Contents/Notifications', { ...mapState('TimelineSpace/Contents/Notifications', {
notifications: (state) => state.notifications, notifications: state => state.notifications,
lazyLoading: (state) => state.lazyLoading, lazyLoading: state => state.lazyLoading,
heading: (state) => state.heading, heading: state => state.heading,
scrolling: (state) => state.scrolling, scrolling: state => state.scrolling
}), }),
...mapGetters('TimelineSpace/Contents/Notifications', [ ...mapGetters('TimelineSpace/Contents/Notifications', ['handledNotifications', 'filters']),
'handledNotifications',
'filters',
]),
...mapGetters('TimelineSpace/Modals', ['modalOpened']), ...mapGetters('TimelineSpace/Modals', ['modalOpened']),
shortcutEnabled: function () { shortcutEnabled: function () {
if (this.modalOpened) { if (this.modalOpened) {
@ -116,21 +79,14 @@ export default {
return true return true
} }
// Sometimes notifications are deleted, so perhaps focused notification don't exist. // Sometimes notifications are deleted, so perhaps focused notification don't exist.
const currentIndex = this.handledNotifications.findIndex( const currentIndex = this.handledNotifications.findIndex(notification => this.focusedId === notification.id)
(notification) => this.focusedId === notification.id
)
return currentIndex === -1 return currentIndex === -1
}, }
}, },
mounted() { mounted() {
this.$store.commit( this.$store.commit('TimelineSpace/SideMenu/changeUnreadNotifications', false)
'TimelineSpace/SideMenu/changeUnreadNotifications',
false
)
this.$store.dispatch('TimelineSpace/Contents/Notifications/resetBadge') this.$store.dispatch('TimelineSpace/Contents/Notifications/resetBadge')
document document.getElementById('scroller').addEventListener('scroll', this.onScroll)
.getElementById('scroller')
.addEventListener('scroll', this.onScroll)
Event.$on('focus-timeline', () => { Event.$on('focus-timeline', () => {
// If focusedId does not change, we have to refresh focusedId because Toot component watch change events. // If focusedId does not change, we have to refresh focusedId because Toot component watch change events.
@ -149,32 +105,18 @@ export default {
this.scrollPosition.prepare() this.scrollPosition.prepare()
this.observer = new ResizeObserver(() => { this.observer = new ResizeObserver(() => {
if ( if (this.loadingMore || (this.scrollPosition && !this.heading && !this.lazyLoading && !this.scrolling)) {
this.loadingMore ||
(this.scrollPosition &&
!this.heading &&
!this.lazyLoading &&
!this.scrolling)
) {
this.resizeTime = moment() this.resizeTime = moment()
this.scrollPosition.restore() this.scrollPosition.restore()
} }
}) })
const scrollWrapper = el.getElementsByClassName( const scrollWrapper = el.getElementsByClassName('vue-recycle-scroller__item-wrapper')[0]
'vue-recycle-scroller__item-wrapper'
)[0]
this.observer.observe(scrollWrapper) this.observer.observe(scrollWrapper)
}, },
beforeUpdate() { beforeUpdate() {
if ( if (this.$store.state.TimelineSpace.SideMenu.unreadNotifications && this.heading) {
this.$store.state.TimelineSpace.SideMenu.unreadNotifications && this.$store.commit('TimelineSpace/SideMenu/changeUnreadNotifications', false)
this.heading
) {
this.$store.commit(
'TimelineSpace/SideMenu/changeUnreadNotifications',
false
)
} }
if (this.scrollPosition) { if (this.scrollPosition) {
this.scrollPosition.prepare() this.scrollPosition.prepare()
@ -185,20 +127,10 @@ export default {
this.observer.disconnect() this.observer.disconnect()
}, },
destroyed() { destroyed() {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Notifications/changeHeading', true)
'TimelineSpace/Contents/Notifications/changeHeading', this.$store.commit('TimelineSpace/Contents/Notifications/archiveNotifications')
true if (document.getElementById('scroller') !== undefined && document.getElementById('scroller') !== null) {
) document.getElementById('scroller').removeEventListener('scroll', this.onScroll)
this.$store.commit(
'TimelineSpace/Contents/Notifications/archiveNotifications'
)
if (
document.getElementById('scroller') !== undefined &&
document.getElementById('scroller') !== null
) {
document
.getElementById('scroller')
.removeEventListener('scroll', this.onScroll)
document.getElementById('scroller').scrollTop = 0 document.getElementById('scroller').scrollTop = 0
} }
}, },
@ -212,15 +144,9 @@ export default {
}, },
focusedId: function (newState, _oldState) { focusedId: function (newState, _oldState) {
if (newState >= 0 && this.heading) { if (newState >= 0 && this.heading) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Notifications/changeHeading', false)
'TimelineSpace/Contents/Notifications/changeHeading',
false
)
} else if (newState === null && !this.heading) { } else if (newState === null && !this.heading) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Notifications/changeHeading', true)
'TimelineSpace/Contents/Notifications/changeHeading',
true
)
this.$store.dispatch('TimelineSpace/Contents/Notifications/resetBadge') this.$store.dispatch('TimelineSpace/Contents/Notifications/resetBadge')
} }
}, },
@ -228,7 +154,7 @@ export default {
if (this.heading && newState.length > 0) { if (this.heading && newState.length > 0) {
this.$store.dispatch('TimelineSpace/Contents/Notifications/saveMarker') this.$store.dispatch('TimelineSpace/Contents/Notifications/saveMarker')
} }
}, }
}, },
methods: { methods: {
onScroll(event) { onScroll(event) {
@ -237,15 +163,11 @@ export default {
} }
this.scrollTime = moment() this.scrollTime = moment()
if (!this.scrolling) { if (!this.scrolling) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Notifications/changeScrolling', true)
'TimelineSpace/Contents/Notifications/changeScrolling',
true
)
} }
if ( if (
event.target.clientHeight + event.target.scrollTop >= event.target.clientHeight + event.target.scrollTop >= document.getElementById('scroller').scrollHeight - 10 &&
document.getElementById('scroller').scrollHeight - 10 &&
!this.lazyloading !this.lazyloading
) { ) {
this.$store this.$store
@ -253,41 +175,29 @@ export default {
'TimelineSpace/Contents/Notifications/lazyFetchNotifications', 'TimelineSpace/Contents/Notifications/lazyFetchNotifications',
this.handledNotifications[this.handledNotifications.length - 1] this.handledNotifications[this.handledNotifications.length - 1]
) )
.then((statuses) => { .then(statuses => {
if (statuses === null) { if (statuses === null) {
return return
} }
if (statuses.length > 0) { if (statuses.length > 0) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Notifications/changeScrolling', true)
'TimelineSpace/Contents/Notifications/changeScrolling',
true
)
setTimeout(() => { setTimeout(() => {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Notifications/changeScrolling', false)
'TimelineSpace/Contents/Notifications/changeScrolling',
false
)
}, 500) }, 500)
} }
}) })
.catch(() => { .catch(() => {
this.$message({ this.$message({
message: this.$t('message.notification_fetch_error'), message: this.$t('message.notification_fetch_error'),
type: 'error', type: 'error'
}) })
}) })
} }
if (event.target.scrollTop > 10 && this.heading) { if (event.target.scrollTop > 10 && this.heading) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Notifications/changeHeading', false)
'TimelineSpace/Contents/Notifications/changeHeading',
false
)
} else if (event.target.scrollTop <= 10 && !this.heading) { } else if (event.target.scrollTop <= 10 && !this.heading) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Notifications/changeHeading', true)
'TimelineSpace/Contents/Notifications/changeHeading',
true
)
this.$store.dispatch('TimelineSpace/Contents/Notifications/resetBadge') this.$store.dispatch('TimelineSpace/Contents/Notifications/resetBadge')
this.$store.dispatch('TimelineSpace/Contents/Notifications/saveMarker') this.$store.dispatch('TimelineSpace/Contents/Notifications/saveMarker')
} }
@ -296,25 +206,17 @@ export default {
const now = moment() const now = moment()
if (now.diff(this.scrollTime) >= 150) { if (now.diff(this.scrollTime) >= 150) {
this.scrollTime = null this.scrollTime = null
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Notifications/changeScrolling', false)
'TimelineSpace/Contents/Notifications/changeScrolling',
false
)
} }
}, 150) }, 150)
}, },
fetchNotificationsSince(since_id) { fetchNotificationsSince(since_id) {
this.loadingMore = true this.loadingMore = true
this.$store this.$store.dispatch('TimelineSpace/Contents/Notifications/fetchNotificationsSince', since_id).finally(() => {
.dispatch( setTimeout(() => {
'TimelineSpace/Contents/Notifications/fetchNotificationsSince', this.loadingMore = false
since_id }, 500)
) })
.finally(() => {
setTimeout(() => {
this.loadingMore = false
}, 500)
})
}, },
async reload() { async reload() {
this.$store.commit('TimelineSpace/changeLoading', true) this.$store.commit('TimelineSpace/changeLoading', true)
@ -326,19 +228,14 @@ export default {
} }
}, },
updateToot(message) { updateToot(message) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Notifications/updateToot', message)
'TimelineSpace/Contents/Notifications/updateToot',
message
)
}, },
upper() { upper() {
this.$refs.scroller.scrollToItem(0) this.$refs.scroller.scrollToItem(0)
this.focusedId = null this.focusedId = null
}, },
focusNext() { focusNext() {
const currentIndex = this.handledNotifications.findIndex( const currentIndex = this.handledNotifications.findIndex(notification => this.focusedId === notification.id)
(notification) => this.focusedId === notification.id
)
if (currentIndex === -1) { if (currentIndex === -1) {
this.focusedId = this.handledNotifications[0].id this.focusedId = this.handledNotifications[0].id
} else if (currentIndex < this.handledNotifications.length) { } else if (currentIndex < this.handledNotifications.length) {
@ -346,9 +243,7 @@ export default {
} }
}, },
focusPrev() { focusPrev() {
const currentIndex = this.handledNotifications.findIndex( const currentIndex = this.handledNotifications.findIndex(notification => this.focusedId === notification.id)
(notification) => this.focusedId === notification.id
)
if (currentIndex === 0) { if (currentIndex === 0) {
this.focusedId = null this.focusedId = null
} else if (currentIndex > 0) { } else if (currentIndex > 0) {
@ -367,8 +262,8 @@ export default {
this.focusedId = this.handledNotifications[0].id this.focusedId = this.handledNotifications[0].id
break break
} }
}, }
}, }
} }
</script> </script>

View File

@ -1,28 +1,9 @@
<template> <template>
<div <div id="public" v-shortkey="shortcutEnabled ? { next: ['j'] } : {}" @shortkey="handleKey">
id="public" <div v-shortkey="{ linux: ['ctrl', 'r'], mac: ['meta', 'r'] }" @shortkey="reload()"></div>
v-shortkey="shortcutEnabled ? { next: ['j'] } : {}" <DynamicScroller :items="timeline" :min-item-size="86" id="scroller" class="scroller" ref="scroller">
@shortkey="handleKey"
>
<div
v-shortkey="{ linux: ['ctrl', 'r'], mac: ['meta', 'r'] }"
@shortkey="reload()"
></div>
<DynamicScroller
:items="timeline"
:min-item-size="86"
id="scroller"
class="scroller"
ref="scroller"
>
<template v-slot="{ item, index, active }"> <template v-slot="{ item, index, active }">
<DynamicScrollerItem <DynamicScrollerItem :item="item" :active="active" :size-dependencies="[item.uri]" :data-index="index" :watchData="true">
:item="item"
:active="active"
:size-dependencies="[item.uri]"
:data-index="index"
:watchData="true"
>
<toot <toot
:message="item" :message="item"
:focused="item.uri + item.id === focusedId" :focused="item.uri + item.id === focusedId"
@ -40,18 +21,15 @@
</DynamicScrollerItem> </DynamicScrollerItem>
</template> </template>
</DynamicScroller> </DynamicScroller>
<div <div :class="openSideBar ? 'upper-with-side-bar' : 'upper'" v-show="!heading">
:class="openSideBar ? 'upper-with-side-bar' : 'upper'" <el-button type="primary" @click="upper" circle>
v-show="!heading" <font-awesome-icon icon="arrow-up" />
>
<el-button type="primary" :icon="ElIconArrowUp" @click="upper" circle>
</el-button> </el-button>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import { ArrowUp as ElIconArrowUp } from '@element-plus/icons'
import { mapState, mapGetters } from 'vuex' import { mapState, mapGetters } from 'vuex'
import moment from 'moment' import moment from 'moment'
import Toot from '~/src/renderer/components/organisms/Toot' import Toot from '~/src/renderer/components/organisms/Toot'
@ -66,8 +44,7 @@ export default {
scrollPosition: null, scrollPosition: null,
observer: null, observer: null,
scrollTime: null, scrollTime: null,
resizeTime: null, resizeTime: null
ElIconArrowUp,
} }
}, },
name: 'public', name: 'public',
@ -75,17 +52,16 @@ export default {
mixins: [reloadable], mixins: [reloadable],
computed: { computed: {
...mapState('TimelineSpace/Contents/Public', { ...mapState('TimelineSpace/Contents/Public', {
timeline: (state) => state.timeline, timeline: state => state.timeline,
lazyLoading: (state) => state.lazyLoading, lazyLoading: state => state.lazyLoading,
heading: (state) => state.heading, heading: state => state.heading,
scrolling: (state) => state.scrolling, scrolling: state => state.scrolling
}), }),
...mapState({ ...mapState({
openSideBar: (state) => state.TimelineSpace.Contents.SideBar.openSideBar, openSideBar: state => state.TimelineSpace.Contents.SideBar.openSideBar,
backgroundColor: (state) => state.App.theme.background_color, backgroundColor: state => state.App.theme.background_color,
startReload: (state) => state.TimelineSpace.HeaderMenu.reload, startReload: state => state.TimelineSpace.HeaderMenu.reload,
unreadNotification: (state) => unreadNotification: state => state.TimelineSpace.timelineSetting.unreadNotification
state.TimelineSpace.timelineSetting.unreadNotification,
}), }),
...mapGetters('TimelineSpace/Contents/Public', ['filters']), ...mapGetters('TimelineSpace/Contents/Public', ['filters']),
...mapGetters('TimelineSpace/Modals', ['modalOpened']), ...mapGetters('TimelineSpace/Modals', ['modalOpened']),
@ -97,23 +73,16 @@ export default {
return true return true
} }
// Sometimes toots are deleted, so perhaps focused toot don't exist. // Sometimes toots are deleted, so perhaps focused toot don't exist.
const currentIndex = this.timeline.findIndex( const currentIndex = this.timeline.findIndex(toot => this.focusedId === toot.uri + toot.id)
(toot) => this.focusedId === toot.uri + toot.id
)
return currentIndex === -1 return currentIndex === -1
}, }
}, },
async mounted() { async mounted() {
this.$store.commit( this.$store.commit('TimelineSpace/SideMenu/changeUnreadPublicTimeline', false)
'TimelineSpace/SideMenu/changeUnreadPublicTimeline', document.getElementById('scroller').addEventListener('scroll', this.onScroll)
false
)
document
.getElementById('scroller')
.addEventListener('scroll', this.onScroll)
if (!this.unreadNotification.public) { if (!this.unreadNotification.public) {
this.$store.commit('TimelineSpace/Contents/changeLoading', true) this.$store.commit('TimelineSpace/Contents/changeLoading', true)
await this.initialize().finally((_) => { await this.initialize().finally(_ => {
this.$store.commit('TimelineSpace/Contents/changeLoading', false) this.$store.commit('TimelineSpace/Contents/changeLoading', false)
}) })
} }
@ -131,31 +100,18 @@ export default {
this.scrollPosition.prepare() this.scrollPosition.prepare()
this.observer = new ResizeObserver(() => { this.observer = new ResizeObserver(() => {
if ( if (this.scrollPosition && !this.heading && !this.lazyLoading && !this.scrolling) {
this.scrollPosition &&
!this.heading &&
!this.lazyLoading &&
!this.scrolling
) {
this.resizeTime = moment() this.resizeTime = moment()
this.scrollPosition.restore() this.scrollPosition.restore()
} }
}) })
const scrollWrapper = el.getElementsByClassName( const scrollWrapper = el.getElementsByClassName('vue-recycle-scroller__item-wrapper')[0]
'vue-recycle-scroller__item-wrapper'
)[0]
this.observer.observe(scrollWrapper) this.observer.observe(scrollWrapper)
}, },
beforeUpdate() { beforeUpdate() {
if ( if (this.$store.state.TimelineSpace.SideMenu.unreadPublicTimeline && this.heading) {
this.$store.state.TimelineSpace.SideMenu.unreadPublicTimeline && this.$store.commit('TimelineSpace/SideMenu/changeUnreadPublicTimeline', false)
this.heading
) {
this.$store.commit(
'TimelineSpace/SideMenu/changeUnreadPublicTimeline',
false
)
} }
if (this.scrollPosition) { if (this.scrollPosition) {
this.scrollPosition.prepare() this.scrollPosition.prepare()
@ -175,13 +131,8 @@ export default {
if (!this.unreadNotification.public) { if (!this.unreadNotification.public) {
this.$store.commit('TimelineSpace/Contents/Public/clearTimeline') this.$store.commit('TimelineSpace/Contents/Public/clearTimeline')
} }
if ( if (document.getElementById('scroller') !== undefined && document.getElementById('scroller') !== null) {
document.getElementById('scroller') !== undefined && document.getElementById('scroller').removeEventListener('scroll', this.onScroll)
document.getElementById('scroller') !== null
) {
document
.getElementById('scroller')
.removeEventListener('scroll', this.onScroll)
document.getElementById('scroller').scrollTop = 0 document.getElementById('scroller').scrollTop = 0
} }
}, },
@ -199,18 +150,16 @@ export default {
} else if (newState === null && !this.heading) { } else if (newState === null && !this.heading) {
this.$store.commit('TimelineSpace/Contents/Public/changeHeading', true) this.$store.commit('TimelineSpace/Contents/Public/changeHeading', true)
} }
}, }
}, },
methods: { methods: {
async initialize() { async initialize() {
await this.$store await this.$store.dispatch('TimelineSpace/Contents/Public/fetchPublicTimeline').catch(_ => {
.dispatch('TimelineSpace/Contents/Public/fetchPublicTimeline') this.$message({
.catch((_) => { message: this.$t('message.timeline_fetch_error'),
this.$message({ type: 'error'
message: this.$t('message.timeline_fetch_error'),
type: 'error',
})
}) })
})
await this.$store.dispatch('TimelineSpace/bindPublicStreaming') await this.$store.dispatch('TimelineSpace/bindPublicStreaming')
this.$store.dispatch('TimelineSpace/startPublicStreaming') this.$store.dispatch('TimelineSpace/startPublicStreaming')
}, },
@ -227,43 +176,30 @@ export default {
this.scrollTime = moment() this.scrollTime = moment()
if (!this.scrolling) { if (!this.scrolling) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Public/changeScrolling', true)
'TimelineSpace/Contents/Public/changeScrolling',
true
)
} }
if ( if (
event.target.clientHeight + event.target.scrollTop >= event.target.clientHeight + event.target.scrollTop >= document.getElementById('scroller').scrollHeight - 10 &&
document.getElementById('scroller').scrollHeight - 10 &&
!this.lazyloading !this.lazyloading
) { ) {
this.$store this.$store
.dispatch( .dispatch('TimelineSpace/Contents/Public/lazyFetchTimeline', this.timeline[this.timeline.length - 1])
'TimelineSpace/Contents/Public/lazyFetchTimeline', .then(statuses => {
this.timeline[this.timeline.length - 1]
)
.then((statuses) => {
if (statuses === null) { if (statuses === null) {
return return
} }
if (statuses.length > 0) { if (statuses.length > 0) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Public/changeScrolling', true)
'TimelineSpace/Contents/Public/changeScrolling',
true
)
setTimeout(() => { setTimeout(() => {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Public/changeScrolling', false)
'TimelineSpace/Contents/Public/changeScrolling',
false
)
}, 500) }, 500)
} }
}) })
.catch(() => { .catch(() => {
this.$message({ this.$message({
message: this.$t('message.timeline_fetch_error'), message: this.$t('message.timeline_fetch_error'),
type: 'error', type: 'error'
}) })
}) })
} }
@ -278,10 +214,7 @@ export default {
const now = moment() const now = moment()
if (now.diff(this.scrollTime) >= 150) { if (now.diff(this.scrollTime) >= 150) {
this.scrollTime = null this.scrollTime = null
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Public/changeScrolling', false)
'TimelineSpace/Contents/Public/changeScrolling',
false
)
} }
}, 150) }, 150)
}, },
@ -298,27 +231,19 @@ export default {
this.focusedId = null this.focusedId = null
}, },
focusNext() { focusNext() {
const currentIndex = this.timeline.findIndex( const currentIndex = this.timeline.findIndex(toot => this.focusedId === toot.uri + toot.id)
(toot) => this.focusedId === toot.uri + toot.id
)
if (currentIndex === -1) { if (currentIndex === -1) {
this.focusedId = this.timeline[0].uri + this.timeline[0].id this.focusedId = this.timeline[0].uri + this.timeline[0].id
} else if (currentIndex < this.timeline.length) { } else if (currentIndex < this.timeline.length) {
this.focusedId = this.focusedId = this.timeline[currentIndex + 1].uri + this.timeline[currentIndex + 1].id
this.timeline[currentIndex + 1].uri +
this.timeline[currentIndex + 1].id
} }
}, },
focusPrev() { focusPrev() {
const currentIndex = this.timeline.findIndex( const currentIndex = this.timeline.findIndex(toot => this.focusedId === toot.uri + toot.id)
(toot) => this.focusedId === toot.uri + toot.id
)
if (currentIndex === 0) { if (currentIndex === 0) {
this.focusedId = null this.focusedId = null
} else if (currentIndex > 0) { } else if (currentIndex > 0) {
this.focusedId = this.focusedId = this.timeline[currentIndex - 1].uri + this.timeline[currentIndex - 1].id
this.timeline[currentIndex - 1].uri +
this.timeline[currentIndex - 1].id
} }
}, },
focusToot(message) { focusToot(message) {
@ -337,13 +262,10 @@ export default {
sizeChanged() { sizeChanged() {
this.$store.commit('TimelineSpace/Contents/Public/changeScrolling', true) this.$store.commit('TimelineSpace/Contents/Public/changeScrolling', true)
setTimeout(() => { setTimeout(() => {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/Public/changeScrolling', false)
'TimelineSpace/Contents/Public/changeScrolling',
false
)
}, 500) }, 500)
}, }
}, }
} }
</script> </script>

View File

@ -1,20 +1,12 @@
<template> <template>
<div <div class="side-bar" v-if="openSideBar" v-shortkey="shortcutEnabled ? { close: ['esc'] } : {}" @shortkey="handleKey">
class="side-bar"
v-if="openSideBar"
v-shortkey="shortcutEnabled ? { close: ['esc'] } : {}"
@shortkey="handleKey"
>
<div class="header"> <div class="header">
<el-icon><el-icon-loading /></el-icon> <font-awesome-icon icon="spinner" />
<el-icon><el-icon-refresh /></el-icon> <font-awesome-icon icon="rotate" />
<el-icon><el-icon-close /></el-icon> <font-awesome-icon icon="xmark" />
</div> </div>
<div id="sidebar_scrollable"> <div id="sidebar_scrollable">
<account-profile <account-profile v-if="component === 1" v-on:change-loading="changeLoading"></account-profile>
v-if="component === 1"
v-on:change-loading="changeLoading"
></account-profile>
<toot-detail v-else-if="component === 2"></toot-detail> <toot-detail v-else-if="component === 2"></toot-detail>
<div <div
class="loading" class="loading"
@ -29,11 +21,6 @@
</template> </template>
<script> <script>
import {
Loading as ElIconLoading,
Refresh as ElIconRefresh,
Close as ElIconClose,
} from '@element-plus/icons'
import { mapState } from 'vuex' import { mapState } from 'vuex'
import TootDetail from './SideBar/TootDetail' import TootDetail from './SideBar/TootDetail'
import AccountProfile from './SideBar/AccountProfile' import AccountProfile from './SideBar/AccountProfile'
@ -41,32 +28,29 @@ import AccountProfile from './SideBar/AccountProfile'
export default { export default {
components: { components: {
TootDetail, TootDetail,
AccountProfile, AccountProfile
ElIconLoading,
ElIconRefresh,
ElIconClose,
}, },
name: 'side-bar', name: 'side-bar',
props: { props: {
overlaid: { overlaid: {
type: Boolean, type: Boolean,
default: false, default: false
}, }
}, },
data() { data() {
return { return {
loading: false, loading: false
} }
}, },
computed: { computed: {
...mapState({ ...mapState({
openSideBar: (state) => state.TimelineSpace.Contents.SideBar.openSideBar, openSideBar: state => state.TimelineSpace.Contents.SideBar.openSideBar,
component: (state) => state.TimelineSpace.Contents.SideBar.component, component: state => state.TimelineSpace.Contents.SideBar.component,
backgroundColor: (state) => state.App.theme.background_color, backgroundColor: state => state.App.theme.background_color
}), }),
shortcutEnabled: function () { shortcutEnabled: function () {
return !this.overlaid return !this.overlaid
}, }
}, },
beforeDestroy() { beforeDestroy() {
this.close() this.close()
@ -87,8 +71,8 @@ export default {
this.close() this.close()
break break
} }
}, }
}, }
} }
</script> </script>

View File

@ -3,17 +3,19 @@
<div id="image" v-show="modalOpen" @click="close" :aria-hidden="!modalOpen" aria-modal="true" role="dialog"> <div id="image" v-show="modalOpen" @click="close" :aria-hidden="!modalOpen" aria-modal="true" role="dialog">
<div class="image-wrapper" v-shortkey="modalOpen ? { close: ['esc'] } : {}" @shortkey="closeHandle"> <div class="image-wrapper" v-shortkey="modalOpen ? { close: ['esc'] } : {}" @shortkey="closeHandle">
<div class="image-header"> <div class="image-header">
<el-button type="text" :icon="ElIconClose" @click="close" class="close-button"></el-button> <el-button type="text" @click="close" class="close-button">
<font-awesome-icon icon="xmark" />
</el-button>
</div> </div>
<div class="image-content" role="presentation"> <div class="image-content" role="presentation">
<span class="button-area" <span class="button-area"
><el-button type="text" v-show="showLeft" v-shortkey="['arrowleft']" @shortkey="decrementIndex()" ><el-button type="text" v-show="showLeft" v-shortkey="['arrowleft']" @shortkey="decrementIndex()">
><el-icon><el-icon-arrow-left /></el-icon></el-button <font-awesome-icon icon="arrow-left" /> </el-button
></span> ></span>
<Media :src="imageURL" :type="imageType"></Media> <Media :src="imageURL" :type="imageType"></Media>
<span class="button-area" <span class="button-area"
><el-button type="text" v-show="showRight" v-shortkey="['arrowright']" @shortkey="incrementIndex()" ><el-button type="text" v-show="showRight" v-shortkey="['arrowright']" @shortkey="incrementIndex()">
><el-icon><el-icon-arrow-right /></el-icon></el-button <font-awesome-icon icon="arrow-right" /> </el-button
></span> ></span>
</div> </div>
</div> </div>
@ -22,20 +24,12 @@
</template> </template>
<script> <script>
import { ArrowLeft as ElIconArrowLeft, ArrowRight as ElIconArrowRight, Close as ElIconClose } from '@element-plus/icons'
import Media from './Media' import Media from './Media'
import { mapState } from 'vuex' import { mapState } from 'vuex'
export default { export default {
data() {
return {
ElIconClose
}
},
components: { components: {
Media, Media
ElIconArrowLeft,
ElIconArrowRight
}, },
name: 'image-viewer', name: 'image-viewer',
computed: { computed: {

View File

@ -9,13 +9,13 @@
up: ['arrowup'], up: ['arrowup'],
down: ['arrowdown'], down: ['arrowdown'],
enter: ['enter'], enter: ['enter'],
esc: ['esc'], esc: ['esc']
} }
: { : {
linux: ['ctrl', 'enter'], linux: ['ctrl', 'enter'],
mac: ['meta', 'enter'], mac: ['meta', 'enter'],
left: ['arrowleft'], left: ['arrowleft'],
right: ['arrowright'], right: ['arrowright']
} }
" "
@shortkey="handleKey" @shortkey="handleKey"
@ -29,13 +29,7 @@
autofocus autofocus
> >
</textarea> </textarea>
<el-popover <el-popover placement="bottom-start" width="300" trigger="manual" :model-value="openSuggest" popper-class="suggest-popper">
placement="bottom-start"
width="300"
trigger="manual"
:model-value="openSuggest"
popper-class="suggest-popper"
>
<ul class="suggest-list"> <ul class="suggest-list">
<li <li
v-for="(item, index) in filteredSuggestion" v-for="(item, index) in filteredSuggestion"
@ -60,62 +54,58 @@
<font-awesome-icon :icon="['far', 'face-smile']" size="lg" /> <font-awesome-icon :icon="['far', 'face-smile']" size="lg" />
</el-button> </el-button>
<div v-if="openEmojiPicker" class="emoji-picker"> <div v-if="openEmojiPicker" class="emoji-picker">
<picker <picker set="emojione" :autoFocus="true" :custom="pickerEmojis" @select="selectEmoji" />
set="emojione"
:autoFocus="true"
:custom="pickerEmojis"
@select="selectEmoji"
/>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import 'emoji-mart-vue-fast/css/emoji-mart.css'
import { mapState, mapGetters } from 'vuex' import { mapState, mapGetters } from 'vuex'
import { Picker } from 'emoji-mart-vue' import { Picker } from 'emoji-mart-vue-fast/src'
import ClickOutside from 'vue-click-outside' import ClickOutside from 'vue-click-outside'
import suggestText from '@/utils/suggestText' import suggestText from '@/utils/suggestText'
export default { export default {
name: 'status', name: 'status',
directives: { directives: {
ClickOutside, ClickOutside
}, },
components: { components: {
Picker, Picker
}, },
props: { props: {
value: { value: {
type: String, type: String
}, },
opened: { opened: {
type: Boolean, type: Boolean,
default: false, default: false
}, },
fixCursorPos: { fixCursorPos: {
type: Boolean, type: Boolean,
default: false, default: false
}, },
height: { height: {
type: Number, type: Number,
default: 120, default: 120
}, }
}, },
data() { data() {
return { return {
highlightedIndex: 0, highlightedIndex: 0,
openEmojiPicker: false, openEmojiPicker: false
} }
}, },
computed: { computed: {
...mapState('TimelineSpace/Modals/NewToot/Status', { ...mapState('TimelineSpace/Modals/NewToot/Status', {
filteredAccounts: (state) => state.filteredAccounts, filteredAccounts: state => state.filteredAccounts,
filteredHashtags: (state) => state.filteredHashtags, filteredHashtags: state => state.filteredHashtags,
openSuggest: (state) => state.openSuggest, openSuggest: state => state.openSuggest,
startIndex: (state) => state.startIndex, startIndex: state => state.startIndex,
matchWord: (state) => state.matchWord, matchWord: state => state.matchWord,
filteredSuggestion: (state) => state.filteredSuggestion, filteredSuggestion: state => state.filteredSuggestion
}), }),
...mapGetters('TimelineSpace/Modals/NewToot/Status', ['pickerEmojis']), ...mapGetters('TimelineSpace/Modals/NewToot/Status', ['pickerEmojis']),
status: { status: {
@ -124,8 +114,8 @@ export default {
}, },
set: function (value) { set: function (value) {
this.$emit('input', value) this.$emit('input', value)
}, }
}, }
}, },
mounted() { mounted() {
// When change account, the new toot modal is recreated. // When change account, the new toot modal is recreated.
@ -148,7 +138,7 @@ export default {
this.closeSuggest() this.closeSuggest()
this.hideEmojiPicker() this.hideEmojiPicker()
} }
}, }
}, },
methods: { methods: {
async startSuggest(e) { async startSuggest(e) {
@ -184,10 +174,7 @@ export default {
}, },
async suggestAccount(start, word) { async suggestAccount(start, word) {
try { try {
await this.$store.dispatch( await this.$store.dispatch('TimelineSpace/Modals/NewToot/Status/suggestAccount', { word: word, start: start })
'TimelineSpace/Modals/NewToot/Status/suggestAccount',
{ word: word, start: start }
)
this.$emit('suggestOpened', true) this.$emit('suggestOpened', true)
return true return true
} catch (err) { } catch (err) {
@ -197,10 +184,7 @@ export default {
}, },
async suggestHashtag(start, word) { async suggestHashtag(start, word) {
try { try {
await this.$store.dispatch( await this.$store.dispatch('TimelineSpace/Modals/NewToot/Status/suggestHashtag', { word: word, start: start })
'TimelineSpace/Modals/NewToot/Status/suggestHashtag',
{ word: word, start: start }
)
this.$emit('suggestOpened', true) this.$emit('suggestOpened', true)
return true return true
} catch (err) { } catch (err) {
@ -210,10 +194,7 @@ export default {
}, },
suggestEmoji(start, word) { suggestEmoji(start, word) {
try { try {
this.$store.dispatch( this.$store.dispatch('TimelineSpace/Modals/NewToot/Status/suggestEmoji', { word: word, start: start })
'TimelineSpace/Modals/NewToot/Status/suggestEmoji',
{ word: word, start: start }
)
this.$emit('suggestOpened', true) this.$emit('suggestOpened', true)
return true return true
} catch (err) { } catch (err) {
@ -239,14 +220,10 @@ export default {
}, },
insertItem(item) { insertItem(item) {
if (item.code) { if (item.code) {
const str = `${this.status.slice(0, this.startIndex - 1)}${ const str = `${this.status.slice(0, this.startIndex - 1)}${item.code} ${this.status.slice(this.startIndex + this.matchWord.length)}`
item.code
} ${this.status.slice(this.startIndex + this.matchWord.length)}`
this.status = str this.status = str
} else { } else {
const str = `${this.status.slice(0, this.startIndex - 1)}${ const str = `${this.status.slice(0, this.startIndex - 1)}${item.name} ${this.status.slice(this.startIndex + this.matchWord.length)}`
item.name
} ${this.status.slice(this.startIndex + this.matchWord.length)}`
this.status = str this.status = str
} }
this.closeSuggest() this.closeSuggest()
@ -300,18 +277,14 @@ export default {
selectEmoji(emoji) { selectEmoji(emoji) {
const current = this.$refs.status.selectionStart const current = this.$refs.status.selectionStart
if (emoji.native) { if (emoji.native) {
this.status = `${this.status.slice(0, current)}${ this.status = `${this.status.slice(0, current)}${emoji.native} ${this.status.slice(current)}`
emoji.native
} ${this.status.slice(current)}`
} else { } else {
// Custom emoji don't have natvie code // Custom emoji don't have natvie code
this.status = `${this.status.slice(0, current)}${ this.status = `${this.status.slice(0, current)}${emoji.name} ${this.status.slice(current)}`
emoji.name
} ${this.status.slice(current)}`
} }
this.hideEmojiPicker() this.hideEmojiPicker()
}, }
}, }
} }
</script> </script>

View File

@ -12,7 +12,7 @@
</div> </div>
<el-dropdown trigger="click" @command="handleProfile" :title="$t('side_menu.profile')"> <el-dropdown trigger="click" @command="handleProfile" :title="$t('side_menu.profile')">
<span class="el-dropdown-link"> <span class="el-dropdown-link">
<el-icon class="el-icon--right"><el-icon-arrow-down /></el-icon> <font-awesome-icon icon="arrow-up" class="el-icon--right" />
</span> </span>
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
<el-dropdown-item command="show">{{ $t('side_menu.show_profile') }}</el-dropdown-item> <el-dropdown-item command="show">{{ $t('side_menu.show_profile') }}</el-dropdown-item>
@ -239,13 +239,9 @@
</template> </template>
<script> <script>
import { ArrowDown as ElIconArrowDown } from '@element-plus/icons'
import { mapState } from 'vuex' import { mapState } from 'vuex'
export default { export default {
components: {
ElIconArrowDown
},
name: 'side-menu', name: 'side-menu',
computed: { computed: {
...mapState('TimelineSpace/SideMenu', { ...mapState('TimelineSpace/SideMenu', {

View File

@ -2,7 +2,7 @@
<div class="link" @click="openLink(url)"> <div class="link" @click="openLink(url)">
<el-image :src="icon" class="icon" fit="cover" lazy> <el-image :src="icon" class="icon" fit="cover" lazy>
<div class="image-slot" slot="error"> <div class="image-slot" slot="error">
<el-icon><el-icon-link /></el-icon> <font-awesome-icon icon="link" />
</div> </div>
</el-image> </el-image>
<div class="contents"> <div class="contents">
@ -13,37 +13,33 @@
</template> </template>
<script> <script>
import { Link as ElIconLink } from '@element-plus/icons'
export default { export default {
components: {
ElIconLink,
},
name: 'link-preview', name: 'link-preview',
props: { props: {
icon: { icon: {
type: String, type: String,
default: '', default: ''
}, },
title: { title: {
type: String, type: String,
default: '', default: ''
}, },
description: { description: {
type: String, type: String,
default: '', default: ''
}, },
url: { url: {
type: String, type: String,
default: null, default: null
}, }
}, },
methods: { methods: {
openLink(link) { openLink(link) {
if (link) { if (link) {
return window.shell.openExternal(link) return window.shell.openExternal(link)
} }
}, }
}, }
} }
</script> </script>

View File

@ -15,7 +15,7 @@
open: ['o'], open: ['o'],
profile: ['p'], profile: ['p'],
image: ['i'], image: ['i'],
cw: ['x'], cw: ['x']
} }
: {} : {}
" "
@ -28,15 +28,8 @@
<div v-show="filtered" class="filtered">Filtered</div> <div v-show="filtered" class="filtered">Filtered</div>
<div v-show="!filtered" class="toot"> <div v-show="!filtered" class="toot">
<div class="reblogger" v-show="message.reblog && !message.quote"> <div class="reblogger" v-show="message.reblog && !message.quote">
<span <span class="reblogger-icon" @click="openUser(message.account)" role="presentation">
class="reblogger-icon" <FailoverImg :src="message.account.avatar" :alt="`Avatar of ${message.account.username}`" />
@click="openUser(message.account)"
role="presentation"
>
<FailoverImg
:src="message.account.avatar"
:alt="`Avatar of ${message.account.username}`"
/>
</span> </span>
<font-awesome-icon icon="retweet" /> <font-awesome-icon icon="retweet" />
<span <span
@ -58,17 +51,11 @@
<div class="detail" v-on:dblclick="openDetail(message)"> <div class="detail" v-on:dblclick="openDetail(message)">
<div class="toot-header"> <div class="toot-header">
<div class="user" @click="openUser(originalMessage.account)"> <div class="user" @click="openUser(originalMessage.account)">
<span class="display-name" <span class="display-name"><bdi v-html="username(originalMessage.account)"></bdi></span>
><bdi v-html="username(originalMessage.account)"></bdi
></span>
<span class="acct">{{ accountName(originalMessage.account) }}</span> <span class="acct">{{ accountName(originalMessage.account) }}</span>
</div> </div>
<div class="timestamp"> <div class="timestamp">
<time <time :datetime="originalMessage.created_at" :title="readableTimestamp" @click="openDetail(message)">
:datetime="originalMessage.created_at"
:title="readableTimestamp"
@click="openDetail(message)"
>
{{ timestamp }} {{ timestamp }}
</time> </time>
</div> </div>
@ -76,28 +63,11 @@
</div> </div>
<div class="content-wrapper"> <div class="content-wrapper">
<div class="spoiler" v-show="spoilered"> <div class="spoiler" v-show="spoilered">
<span <span v-html="emojiText(originalMessage.spoiler_text, originalMessage.emojis)"></span>
v-html=" <el-button v-if="!isShowContent" plain type="primary" size="medium" class="spoil-button" @click="toggleSpoiler">
emojiText(originalMessage.spoiler_text, originalMessage.emojis)
"
></span>
<el-button
v-if="!isShowContent"
plain
type="primary"
size="medium"
class="spoil-button"
@click="toggleSpoiler"
>
{{ $t('cards.toot.show_more') }} {{ $t('cards.toot.show_more') }}
</el-button> </el-button>
<el-button <el-button v-else type="primary" size="medium" class="spoil-button" @click="toggleSpoiler">
v-else
type="primary"
size="medium"
class="spoil-button"
@click="toggleSpoiler"
>
{{ $t('cards.toot.hide') }} {{ $t('cards.toot.hide') }}
</el-button> </el-button>
</div> </div>
@ -107,21 +77,10 @@
v-html="emojiText(originalMessage.content, originalMessage.emojis)" v-html="emojiText(originalMessage.content, originalMessage.emojis)"
@click.capture.prevent="tootClick" @click.capture.prevent="tootClick"
></div> ></div>
<Poll <Poll v-show="isShowContent" v-if="poll" :poll="poll" @vote="vote" @refresh="refresh"></Poll>
v-show="isShowContent"
v-if="poll"
:poll="poll"
@vote="vote"
@refresh="refresh"
></Poll>
</div> </div>
<div class="attachments"> <div class="attachments">
<el-button <el-button v-show="sensitive && !isShowAttachments" class="show-sensitive" type="info" @click="toggleCW()">
v-show="sensitive && !isShowAttachments"
class="show-sensitive"
type="info"
@click="toggleCW()"
>
{{ $t('cards.toot.sensitive') }} {{ $t('cards.toot.sensitive') }}
</el-button> </el-button>
<div v-show="isShowAttachments"> <div v-show="isShowAttachments">
@ -134,39 +93,16 @@
> >
<font-awesome-icon icon="eye" class="hide" /> <font-awesome-icon icon="eye" class="hide" />
</el-button> </el-button>
<div <div class="media" v-bind:key="media.preview_url" v-for="media in mediaAttachments">
class="media"
v-bind:key="media.preview_url"
v-for="media in mediaAttachments"
>
<FailoverImg <FailoverImg
:src=" :src="media.preview_url ? media.preview_url : originalMessage.account.avatar"
media.preview_url
? media.preview_url
: originalMessage.account.avatar
"
@click="openImage(media.url, mediaAttachments)" @click="openImage(media.url, mediaAttachments)"
:title="media.description" :title="media.description"
:readExif="true" :readExif="true"
/> />
<el-tag <el-tag class="media-label" size="mini" v-if="media.type === 'gifv'">GIF</el-tag>
class="media-label" <el-tag class="media-label" size="mini" v-else-if="media.type === 'video'">VIDEO</el-tag>
size="mini" <el-tag class="media-label" size="mini" v-else-if="media.type === 'audio'">AUDIO</el-tag>
v-if="media.type === 'gifv'"
>GIF</el-tag
>
<el-tag
class="media-label"
size="mini"
v-else-if="media.type === 'video'"
>VIDEO</el-tag
>
<el-tag
class="media-label"
size="mini"
v-else-if="media.type === 'audio'"
>AUDIO</el-tag
>
</div> </div>
</div> </div>
<div class="clearfix"></div> <div class="clearfix"></div>
@ -188,33 +124,17 @@
/> />
<div class="emoji-reactions"> <div class="emoji-reactions">
<template v-for="reaction in originalMessage.emoji_reactions"> <template v-for="reaction in originalMessage.emoji_reactions">
<el-button <el-button v-if="reaction.me" type="success" size="medium" class="reaction" @click="removeReaction(reaction.name)"
v-if="reaction.me"
type="success"
size="medium"
class="reaction"
@click="removeReaction(reaction.name)"
>{{ reaction.name }} {{ reaction.count }}</el-button >{{ reaction.name }} {{ reaction.count }}</el-button
> >
<el-button <el-button v-else type="text" size="medium" class="reaction" @click="addReaction(reaction.name)"
v-else
type="text"
size="medium"
class="reaction"
@click="addReaction(reaction.name)"
>{{ reaction.name }} {{ reaction.count }}</el-button >{{ reaction.name }} {{ reaction.count }}</el-button
> >
</template> </template>
</div> </div>
<div class="toot-footer"> <div class="toot-footer">
<div class="tool-box"> <div class="tool-box">
<el-button <el-button type="text" @click="openReply()" class="reply" :title="$t('cards.toot.reply')" :aria-label="$t('cards.toot.reply')">
type="text"
@click="openReply()"
class="reply"
:title="$t('cards.toot.reply')"
:aria-label="$t('cards.toot.reply')"
>
<font-awesome-icon icon="reply" size="sm" /> <font-awesome-icon icon="reply" size="sm" />
</el-button> </el-button>
<el-button v-show="locked" type="text" class="locked"> <el-button v-show="locked" type="text" class="locked">
@ -238,11 +158,7 @@
<el-button <el-button
type="text" type="text"
@click="changeFavourite(originalMessage)" @click="changeFavourite(originalMessage)"
:class=" :class="originalMessage.favourited ? 'favourited animated bounceIn' : 'favourite'"
originalMessage.favourited
? 'favourited animated bounceIn'
: 'favourite'
"
:title="$t('cards.toot.fav')" :title="$t('cards.toot.fav')"
:aria-label="$t('cards.toot.fav')" :aria-label="$t('cards.toot.fav')"
> >
@ -261,12 +177,7 @@
> >
<font-awesome-icon icon="bookmark" size="sm" /> <font-awesome-icon icon="bookmark" size="sm" />
</el-button> </el-button>
<el-button <el-button type="text" class="quote-btn" v-if="quoteSupported" @click="openQuote()">
type="text"
class="quote-btn"
v-if="quoteSupported"
@click="openQuote()"
>
<font-awesome-icon icon="quote-right" size="sm" /> <font-awesome-icon icon="quote-right" size="sm" />
</el-button> </el-button>
<template v-if="sns !== 'mastodon'"> <template v-if="sns !== 'mastodon'">
@ -295,13 +206,7 @@
</el-button> </el-button>
</el-popover> </el-popover>
</template> </template>
<el-button <el-button class="pinned" type="text" :title="$t('cards.toot.pinned')" :aria-label="$t('cards.toot.pinned')" v-show="pinned">
class="pinned"
type="text"
:title="$t('cards.toot.pinned')"
:aria-label="$t('cards.toot.pinned')"
v-show="pinned"
>
<font-awesome-icon icon="thumbtack" size="sm" /> <font-awesome-icon icon="thumbtack" size="sm" />
</el-button> </el-button>
<el-popover <el-popover
@ -314,11 +219,7 @@
@hide="hideMenu" @hide="hideMenu"
> >
<ul class="menu-list" v-if="openToolMenu"> <ul class="menu-list" v-if="openToolMenu">
<li <li role="button" @click="openDetail(message)" v-show="!detailed">
role="button"
@click="openDetail(message)"
v-show="!detailed"
>
{{ $t('cards.toot.view_toot_detail') }} {{ $t('cards.toot.view_toot_detail') }}
</li> </li>
<li role="button" @click="openBrowser(originalMessage)"> <li role="button" @click="openBrowser(originalMessage)">
@ -336,20 +237,11 @@
<li role="button" @click="reportUser()" v-if="!isMyMessage"> <li role="button" @click="reportUser()" v-if="!isMyMessage">
{{ $t('cards.toot.report') }} {{ $t('cards.toot.report') }}
</li> </li>
<li <li role="button" class="separate" @click="deleteToot(message)" v-if="isMyMessage">
role="button"
class="separate"
@click="deleteToot(message)"
v-if="isMyMessage"
>
{{ $t('cards.toot.delete') }} {{ $t('cards.toot.delete') }}
</li> </li>
</ul> </ul>
<el-button <el-button slot="reference" type="text" :title="$t('cards.toot.detail')">
slot="reference"
type="text"
:title="$t('cards.toot.detail')"
>
<font-awesome-icon icon="ellipsis" size="sm" /> <font-awesome-icon icon="ellipsis" size="sm" />
</el-button> </el-button>
</el-popover> </el-popover>
@ -366,9 +258,10 @@
</template> </template>
<script> <script>
import 'emoji-mart-vue-fast/css/emoji-mart.css'
import moment from 'moment' import moment from 'moment'
import { mapState } from 'vuex' import { mapState } from 'vuex'
import { Picker } from 'emoji-mart-vue' import { Picker } from 'emoji-mart-vue-fast/src'
import ClickOutside from 'vue-click-outside' import ClickOutside from 'vue-click-outside'
import { findAccount, findLink, findTag } from '~/src/renderer/utils/tootParser' import { findAccount, findLink, findTag } from '~/src/renderer/utils/tootParser'
import DisplayStyle from '~/src/constants/displayStyle' import DisplayStyle from '~/src/constants/displayStyle'
@ -385,14 +278,14 @@ import Filtered from '@/utils/filter'
export default { export default {
name: 'toot', name: 'toot',
directives: { directives: {
ClickOutside, ClickOutside
}, },
components: { components: {
FailoverImg, FailoverImg,
Poll, Poll,
Picker, Picker,
LinkPreview, LinkPreview,
Quote, Quote
}, },
data() { data() {
return { return {
@ -401,47 +294,47 @@ export default {
hideAllAttachments: this.$store.state.App.hideAllAttachments, hideAllAttachments: this.$store.state.App.hideAllAttachments,
now: Date.now(), now: Date.now(),
openEmojiPicker: false, openEmojiPicker: false,
openToolMenu: false, openToolMenu: false
} }
}, },
props: { props: {
message: { message: {
type: Object, type: Object,
default: {}, default: {}
}, },
filters: { filters: {
type: Array, type: Array,
default: [], default: []
}, },
focused: { focused: {
type: Boolean, type: Boolean,
default: false, default: false
}, },
overlaid: { overlaid: {
type: Boolean, type: Boolean,
default: false, default: false
}, },
pinned: { pinned: {
type: Boolean, type: Boolean,
default: false, default: false
}, },
detailed: { detailed: {
type: Boolean, type: Boolean,
default: false, default: false
}, }
}, },
computed: { computed: {
...mapState('App', { ...mapState('App', {
displayNameStyle: (state) => state.displayNameStyle, displayNameStyle: state => state.displayNameStyle,
timeFormat: (state) => state.timeFormat, timeFormat: state => state.timeFormat,
language: (state) => state.language, language: state => state.language
}), }),
...mapState('TimelineSpace', { ...mapState('TimelineSpace', {
sns: (state) => state.sns, sns: state => state.sns,
account: (state) => state.account, account: state => state.account
}), }),
...mapState('TimelineSpace/SideMenu', { ...mapState('TimelineSpace/SideMenu', {
bookmarkSupported: (state) => state.enabledTimelines.bookmark, bookmarkSupported: state => state.enabledTimelines.bookmark
}), }),
shortcutEnabled: function () { shortcutEnabled: function () {
return this.focused && !this.overlaid && !this.openEmojiPicker return this.focused && !this.overlaid && !this.openEmojiPicker
@ -476,10 +369,7 @@ export default {
return null return null
}, },
isMyMessage: function () { isMyMessage: function () {
return ( return this.$store.state.TimelineSpace.account.accountId === this.originalMessage.account.id
this.$store.state.TimelineSpace.account.accountId ===
this.originalMessage.account.id
)
}, },
application: function () { application: function () {
const msg = this.originalMessage const msg = this.originalMessage
@ -498,10 +388,7 @@ export default {
return this.originalMessage.poll return this.originalMessage.poll
}, },
sensitive: function () { sensitive: function () {
return ( return (this.hideAllAttachments || this.originalMessage.sensitive) && this.mediaAttachments.length > 0
(this.hideAllAttachments || this.originalMessage.sensitive) &&
this.mediaAttachments.length > 0
)
}, },
isShowAttachments: function () { isShowAttachments: function () {
return !this.sensitive || this.showAttachments return !this.sensitive || this.showAttachments
@ -517,7 +404,7 @@ export default {
}, },
quoteSupported: function () { quoteSupported: function () {
return QuoteSupported(this.sns, this.account.domain) return QuoteSupported(this.sns, this.account.domain)
}, }
}, },
mounted() { mounted() {
if (this.focused) { if (this.focused) {
@ -541,7 +428,7 @@ export default {
this.$refs.status.blur() this.$refs.status.blur()
}) })
} }
}, }
}, },
methods: { methods: {
username(account) { username(account) {
@ -589,34 +476,20 @@ export default {
} }
const parsedAccount = findAccount(e.target, 'toot') const parsedAccount = findAccount(e.target, 'toot')
if (parsedAccount !== null) { if (parsedAccount !== null) {
this.$store.commit( this.$store.commit('TimelineSpace/Contents/SideBar/changeOpenSideBar', true)
'TimelineSpace/Contents/SideBar/changeOpenSideBar',
true
)
this.$store this.$store
.dispatch( .dispatch('TimelineSpace/Contents/SideBar/AccountProfile/searchAccount', {
'TimelineSpace/Contents/SideBar/AccountProfile/searchAccount', parsedAccount: parsedAccount,
{ status: this.originalMessage
parsedAccount: parsedAccount,
status: this.originalMessage,
}
)
.then((account) => {
this.$store.dispatch(
'TimelineSpace/Contents/SideBar/openAccountComponent'
)
this.$store.dispatch(
'TimelineSpace/Contents/SideBar/AccountProfile/changeAccount',
account
)
}) })
.catch((err) => { .then(account => {
this.$store.dispatch('TimelineSpace/Contents/SideBar/openAccountComponent')
this.$store.dispatch('TimelineSpace/Contents/SideBar/AccountProfile/changeAccount', account)
})
.catch(err => {
console.error(err) console.error(err)
this.openLink(e) this.openLink(e)
this.$store.commit( this.$store.commit('TimelineSpace/Contents/SideBar/changeOpenSideBar', false)
'TimelineSpace/Contents/SideBar/changeOpenSideBar',
false
)
}) })
return parsedAccount.acct return parsedAccount.acct
} }
@ -629,21 +502,12 @@ export default {
} }
}, },
openReply() { openReply() {
this.$store.dispatch( this.$store.dispatch('TimelineSpace/Modals/NewToot/openReply', this.originalMessage)
'TimelineSpace/Modals/NewToot/openReply',
this.originalMessage
)
}, },
openDetail(message) { openDetail(message) {
this.$store.dispatch('TimelineSpace/Contents/SideBar/openTootComponent') this.$store.dispatch('TimelineSpace/Contents/SideBar/openTootComponent')
this.$store.dispatch( this.$store.dispatch('TimelineSpace/Contents/SideBar/TootDetail/changeToot', message)
'TimelineSpace/Contents/SideBar/TootDetail/changeToot', this.$store.commit('TimelineSpace/Contents/SideBar/changeOpenSideBar', true)
message
)
this.$store.commit(
'TimelineSpace/Contents/SideBar/changeOpenSideBar',
true
)
this.$refs.status_menu_popper.doClose() this.$refs.status_menu_popper.doClose()
}, },
openBrowser(message) { openBrowser(message) {
@ -655,17 +519,11 @@ export default {
this.$refs.status_menu_popper.doClose() this.$refs.status_menu_popper.doClose()
}, },
reportUser() { reportUser() {
this.$store.dispatch( this.$store.dispatch('TimelineSpace/Modals/Report/openReport', this.originalMessage)
'TimelineSpace/Modals/Report/openReport',
this.originalMessage
)
this.$refs.status_menu_popper.doClose() this.$refs.status_menu_popper.doClose()
}, },
confirmMute() { confirmMute() {
this.$store.dispatch( this.$store.dispatch('TimelineSpace/Modals/MuteConfirm/changeAccount', this.originalMessage.account)
'TimelineSpace/Modals/MuteConfirm/changeAccount',
this.originalMessage.account
)
this.$store.dispatch('TimelineSpace/Modals/MuteConfirm/changeModal', true) this.$store.dispatch('TimelineSpace/Modals/MuteConfirm/changeModal', true)
this.$refs.status_menu_popper.doClose() this.$refs.status_menu_popper.doClose()
}, },
@ -677,27 +535,27 @@ export default {
if (message.reblogged) { if (message.reblogged) {
this.$store this.$store
.dispatch('organisms/Toot/unreblog', message) .dispatch('organisms/Toot/unreblog', message)
.then((data) => { .then(data => {
this.$emit('update', data) this.$emit('update', data)
}) })
.catch((err) => { .catch(err => {
console.error(err) console.error(err)
this.$message({ this.$message({
message: this.$t('message.unreblog_error'), message: this.$t('message.unreblog_error'),
type: 'error', type: 'error'
}) })
}) })
} else { } else {
this.$store this.$store
.dispatch('organisms/Toot/reblog', message) .dispatch('organisms/Toot/reblog', message)
.then((data) => { .then(data => {
this.$emit('update', data) this.$emit('update', data)
}) })
.catch((err) => { .catch(err => {
console.error(err) console.error(err)
this.$message({ this.$message({
message: this.$t('message.reblog_error'), message: this.$t('message.reblog_error'),
type: 'error', type: 'error'
}) })
}) })
} }
@ -706,27 +564,27 @@ export default {
if (message.favourited) { if (message.favourited) {
this.$store this.$store
.dispatch('organisms/Toot/removeFavourite', message) .dispatch('organisms/Toot/removeFavourite', message)
.then((data) => { .then(data => {
this.$emit('update', data) this.$emit('update', data)
}) })
.catch((err) => { .catch(err => {
console.error(err) console.error(err)
this.$message({ this.$message({
message: this.$t('message.unfavourite_error'), message: this.$t('message.unfavourite_error'),
type: 'error', type: 'error'
}) })
}) })
} else { } else {
this.$store this.$store
.dispatch('organisms/Toot/addFavourite', message) .dispatch('organisms/Toot/addFavourite', message)
.then((data) => { .then(data => {
this.$emit('update', data) this.$emit('update', data)
}) })
.catch((err) => { .catch(err => {
console.error(err) console.error(err)
this.$message({ this.$message({
message: this.$t('message.favourite_error'), message: this.$t('message.favourite_error'),
type: 'error', type: 'error'
}) })
}) })
} }
@ -735,65 +593,57 @@ export default {
if (message.bookmarked) { if (message.bookmarked) {
this.$store this.$store
.dispatch('organisms/Toot/removeBookmark', message) .dispatch('organisms/Toot/removeBookmark', message)
.then((data) => { .then(data => {
this.$emit('update', data) this.$emit('update', data)
}) })
.catch((err) => { .catch(err => {
console.error(err) console.error(err)
this.$message({ this.$message({
message: this.$t('message.unbookmark_error'), message: this.$t('message.unbookmark_error'),
type: 'error', type: 'error'
}) })
}) })
} else { } else {
this.$store this.$store
.dispatch('organisms/Toot/addBookmark', message) .dispatch('organisms/Toot/addBookmark', message)
.then((data) => { .then(data => {
this.$emit('update', data) this.$emit('update', data)
}) })
.catch((err) => { .catch(err => {
console.error(err) console.error(err)
this.$message({ this.$message({
message: this.$t('message.bookmark_error'), message: this.$t('message.bookmark_error'),
type: 'error', type: 'error'
}) })
}) })
} }
}, },
openImage(url, rawMediaList) { openImage(url, rawMediaList) {
const mediaList = rawMediaList.map((media) => { const mediaList = rawMediaList.map(media => {
return media.url return media.url
}) })
const currentIndex = mediaList.indexOf(url) const currentIndex = mediaList.indexOf(url)
this.$store.dispatch('TimelineSpace/Modals/ImageViewer/openModal', { this.$store.dispatch('TimelineSpace/Modals/ImageViewer/openModal', {
currentIndex: currentIndex, currentIndex: currentIndex,
mediaList: rawMediaList, mediaList: rawMediaList
}) })
}, },
openUser(account) { openUser(account) {
console.log(account) console.log(account)
this.$store.dispatch( this.$store.dispatch('TimelineSpace/Contents/SideBar/openAccountComponent')
'TimelineSpace/Contents/SideBar/openAccountComponent' this.$store.dispatch('TimelineSpace/Contents/SideBar/AccountProfile/changeAccount', account)
) this.$store.commit('TimelineSpace/Contents/SideBar/changeOpenSideBar', true)
this.$store.dispatch(
'TimelineSpace/Contents/SideBar/AccountProfile/changeAccount',
account
)
this.$store.commit(
'TimelineSpace/Contents/SideBar/changeOpenSideBar',
true
)
}, },
deleteToot(message) { deleteToot(message) {
this.$store this.$store
.dispatch('organisms/Toot/deleteToot', message) .dispatch('organisms/Toot/deleteToot', message)
.then((message) => { .then(message => {
this.$emit('delete', message) this.$emit('delete', message)
}) })
.catch(() => { .catch(() => {
this.$message({ this.$message({
message: this.$t('message.delete_error'), message: this.$t('message.delete_error'),
type: 'error', type: 'error'
}) })
}) })
}, },
@ -846,24 +696,24 @@ export default {
async vote(choices) { async vote(choices) {
const res = await this.$store.dispatch('organisms/Toot/vote', { const res = await this.$store.dispatch('organisms/Toot/vote', {
id: this.poll.id, id: this.poll.id,
choices: choices, choices: choices
}) })
const status = Object.assign({}, this.originalMessage, { const status = Object.assign({}, this.originalMessage, {
poll: res, poll: res
}) })
this.$emit('update', status) this.$emit('update', status)
}, },
async refresh(id) { async refresh(id) {
const res = await this.$store.dispatch('organisms/Toot/refresh', id) const res = await this.$store.dispatch('organisms/Toot/refresh', id)
const status = Object.assign({}, this.originalMessage, { const status = Object.assign({}, this.originalMessage, {
poll: res, poll: res
}) })
this.$emit('update', status) this.$emit('update', status)
}, },
async selectEmoji(emoji) { async selectEmoji(emoji) {
const status = await this.$store.dispatch('organisms/Toot/sendReaction', { const status = await this.$store.dispatch('organisms/Toot/sendReaction', {
status_id: this.originalMessage.id, status_id: this.originalMessage.id,
native: emoji.native, native: emoji.native
}) })
this.$emit('update', status) this.$emit('update', status)
this.$refs.status_emoji_picker.doClose() this.$refs.status_emoji_picker.doClose()
@ -871,25 +721,19 @@ export default {
async addReaction(native) { async addReaction(native) {
const status = await this.$store.dispatch('organisms/Toot/sendReaction', { const status = await this.$store.dispatch('organisms/Toot/sendReaction', {
status_id: this.originalMessage.id, status_id: this.originalMessage.id,
native: native, native: native
}) })
this.$emit('update', status) this.$emit('update', status)
}, },
async removeReaction(native) { async removeReaction(native) {
const status = await this.$store.dispatch( const status = await this.$store.dispatch('organisms/Toot/deleteReaction', {
'organisms/Toot/deleteReaction', status_id: this.originalMessage.id,
{ native: native
status_id: this.originalMessage.id, })
native: native,
}
)
this.$emit('update', status) this.$emit('update', status)
}, },
openQuote() { openQuote() {
this.$store.dispatch( this.$store.dispatch('TimelineSpace/Modals/NewToot/openQuote', this.originalMessage)
'TimelineSpace/Modals/NewToot/openQuote',
this.originalMessage
)
}, },
openPicker() { openPicker() {
this.openEmojiPicker = true this.openEmojiPicker = true
@ -910,8 +754,8 @@ export default {
toggleCW() { toggleCW() {
this.showAttachments = !this.showAttachments this.showAttachments = !this.showAttachments
this.$emit('sizeChanged', true) this.$emit('sizeChanged', true)
}, }
}, }
} }
</script> </script>

View File

@ -47,7 +47,14 @@ import {
faChevronLeft, faChevronLeft,
faEllipsisVertical, faEllipsisVertical,
faCircleXmark, faCircleXmark,
faMagnifyingGlass faMagnifyingGlass,
faCircleUser,
faArrowUp,
faArrowDown,
faArrowLeft,
faArrowRight,
faSpinner,
faLink
} from '@fortawesome/free-solid-svg-icons' } from '@fortawesome/free-solid-svg-icons'
import { import {
faFaceSmile as farFaceSmile, faFaceSmile as farFaceSmile,
@ -120,7 +127,14 @@ library.add(
farTrashCan, farTrashCan,
farBell, farBell,
faChevronLeft, faChevronLeft,
faEllipsisVertical faEllipsisVertical,
faCircleUser,
faArrowUp,
faArrowDown,
faArrowLeft,
faArrowRight,
faSpinner,
faLink
) )
const app = createApp(App) const app = createApp(App)

View File

@ -1,4 +1,4 @@
import { createRouter } from 'vue-router' import { createRouter, createWebHistory } from 'vue-router'
import Login from '@/components/Login.vue' import Login from '@/components/Login.vue'
import Authorize from '@/components/Authorize.vue' import Authorize from '@/components/Authorize.vue'
@ -215,7 +215,8 @@ const routes = [
] ]
const router = createRouter({ const router = createRouter({
routes history: createWebHistory(),
routes: routes
}) })
export default router export default router