Re-implement status detail

This commit is contained in:
AkiraFukushima 2023-01-22 22:07:47 +09:00
parent 88575a0a47
commit c9d43714e9
No known key found for this signature in database
GPG Key ID: B6E51BAC4DE1A957
4 changed files with 230 additions and 11 deletions

View File

@ -14,7 +14,9 @@
</div>
</el-main>
</el-container>
<div class="detail">detail</div>
<el-aside class="detail" v-if="detail">
<Detail />
</el-aside>
<modals></modals>
<receive-drop v-show="droppableVisible"></receive-drop>
</template>
@ -29,7 +31,7 @@ import HeaderMenu from './TimelineSpace/HeaderMenu.vue'
import Contents from './TimelineSpace/Contents.vue'
import Compose from './TimelineSpace/Compose.vue'
import Modals from './TimelineSpace/Modals.vue'
import SideBar from './TimelineSpace/Contents/SideBar.vue'
import Detail from './TimelineSpace/Detail.vue'
import Mousetrap from 'mousetrap'
import ReceiveDrop from './TimelineSpace/ReceiveDrop.vue'
import { AccountLoadError } from '@/errors/load'
@ -45,7 +47,7 @@ import { ACTION_TYPES as NEW_TOOT_ACTION } from '@/store/TimelineSpace/Modals/Ne
export default defineComponent({
name: 'timeline-space',
components: { SideMenu, HeaderMenu, Modals, Contents, ReceiveDrop, Compose, SideBar },
components: { SideMenu, HeaderMenu, Modals, Contents, ReceiveDrop, Compose, Detail },
setup() {
const space = 'TimelineSpace'
const store = useStore()
@ -57,9 +59,7 @@ export default defineComponent({
const contentsRef = ref<HTMLElement | null>(null)
const loading = computed(() => store.state.TimelineSpace.loading)
const collapse = computed(() => store.state.TimelineSpace.SideMenu.collapse)
// const modalOpened = computed(() => store.getters[`TimelineSpace/Modals/modalOpened`])
// const shortcutEnabled = computed(() => !modalOpened.value)
const detail = computed(() => route.query.detail?.toString() === 'true')
onMounted(async () => {
store.dispatch(`TimelineSpace/Contents/SideBar/${SIDEBAR_ACTION.CLOSE}`)
@ -167,10 +167,10 @@ export default defineComponent({
return {
loading,
collapse,
droppableVisible,
composeResized,
contentsRef
contentsRef,
detail
}
}
})
@ -183,6 +183,7 @@ export default defineComponent({
.header {
padding: 0;
height: auto;
border-bottom: 1px solid var(--theme-border-color);
}

View File

@ -0,0 +1,89 @@
<template>
<el-container>
<el-header class="header-wrapper">
<div class="header">
<div>
<el-button class="header-action" link @click="back">
<font-awesome-icon icon="chevron-left" />
Back
</el-button>
</div>
<div>
<el-button class="header-action" link @click="close">
<font-awesome-icon icon="xmark" />
</el-button>
</div>
</div>
</el-header>
<el-main class="main">
<Status v-if="target() === 'status'" />
</el-main>
</el-container>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import Status from './Detail/Status.vue'
export default defineComponent({
name: 'Detail',
components: { Status },
setup() {
const route = useRoute()
const router = useRouter()
const close = () => {
router.push({
query: {}
})
}
const back = () => {
router.back()
}
const target = () => {
if (route.query.status_id?.toString()) {
return 'status'
} else if (route.query.account_id?.toString()) {
return 'account'
}
return null
}
return {
close,
back,
target
}
}
})
</script>
<style lang="scss" scoped>
.header-wrapper {
height: auto;
border-bottom: 1px solid var(--theme-border-color);
}
.header {
display: flex;
justify-content: space-between;
padding: 10px 0;
line-height: 32px;
.header-action {
color: var(--theme-secondary-color);
&:hover {
color: #409eff;
}
}
}
.main {
margin: 0;
padding: 0;
}
</style>

View File

@ -0,0 +1,131 @@
<template>
<div class="status-detail">
<div class="ancestors" v-for="mes in ancestors" :key="mes.id">
<Toot
v-if="account.account && account.server"
:message="mes"
:overlaid="modalOpened"
:account="account.account"
:server="account.server"
@update="updateStatus"
/>
</div>
<div class="original-status">
<Toot
v-if="status !== null && account.account && account.server"
:message="status"
:overlaid="modalOpened"
:account="account.account"
:server="account.server"
@update="updateStatus"
/>
</div>
<div class="descendants" v-for="mes in descendants" :key="mes.id">
<Toot
v-if="account.account && account.server"
:message="mes"
:overlaid="modalOpened"
:account="account.account"
:server="account.server"
@update="updateStatus"
/>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, ref, onMounted, computed, reactive, watch } from 'vue'
import { useRoute } from 'vue-router'
import generator, { MegalodonInterface, Entity } from 'megalodon'
import Toot from '@/components/organisms/Toot.vue'
import { useStore } from '@/store'
import { MyWindow } from '~/src/types/global'
import { LocalAccount } from '~/src/types/localAccount'
import { LocalServer } from '~/src/types/localServer'
export default defineComponent({
name: 'Status',
components: { Toot },
setup() {
const win = (window as any) as MyWindow
const store = useStore()
const route = useRoute()
const client = ref<MegalodonInterface | null>(null)
const id = computed(() => parseInt(route.params.id as string))
const statusId = computed(() => route.query.status_id?.toString())
const userAgent = computed(() => store.state.App.userAgent)
const status = ref<Entity.Status | null>(null)
const ancestors = ref<Array<Entity.Status>>([])
const descendants = ref<Array<Entity.Status>>([])
const account = reactive<{ account: LocalAccount | null; server: LocalServer | null }>({
account: null,
server: null
})
const modalOpened = computed(() => store.getters[`TimelineSpace/Modals/modalOpened`])
onMounted(async () => {
const [a, s]: [LocalAccount, LocalServer] = await win.ipcRenderer.invoke('get-local-account', id.value)
account.account = a
account.server = s
const c = generator(s.sns, s.baseURL, a.accessToken, userAgent.value)
client.value = c
if (statusId.value) {
const s = await c.getStatus(statusId.value)
status.value = s.data
const res = await c.getStatusContext(statusId.value)
ancestors.value = res.data.ancestors
descendants.value = res.data.descendants
}
})
watch(statusId, async current => {
if (client.value && current) {
const s = await client.value.getStatus(current)
status.value = s.data
const res = await client.value.getStatusContext(current)
ancestors.value = res.data.ancestors
descendants.value = res.data.descendants
}
})
const update = (target: Entity.Status, s: Entity.Status) => {
if (target.id === s.id) {
return s
} else if (target.reblog !== null && target.reblog.id == s.id) {
return Object.assign(target, { reblog: s })
} else {
return target
}
}
const updateStatus = (s: Entity.Status) => {
if (status.value) {
status.value = update(status.value, s)
}
ancestors.value = ancestors.value.map(anc => update(anc, s))
descendants.value = descendants.value.map(des => update(des, s))
}
return {
account,
status,
ancestors,
descendants,
updateStatus,
modalOpened
}
}
})
</script>
<style lang="scss">
.status-detail {
.original-status {
.status {
background-color: var(--theme-selected-background-color);
outline: 0;
}
}
}
</style>

View File

@ -483,9 +483,7 @@ export default defineComponent({
})
}
const openDetail = (message: Entity.Status) => {
store.dispatch(`TimelineSpace/Contents/SideBar/${SIDEBAR_ACTION.OPEN_TOOT_COMPONENT}`)
store.dispatch(`TimelineSpace/Contents/SideBar/TootDetail/${DETAIL_ACTION.CHANGE_TOOT}`, message)
store.commit(`TimelineSpace/Contents/SideBar/${SIDEBAR_MUTATION.CHANGE_OPEN_SIDEBAR}`, true)
router.push({ query: { detail: 'true', status_id: message.id } })
}
const openBrowser = (message: Entity.Status) => {
;(window as any).shell.openExternal(message.url)