mirror of
https://github.com/h3poteto/whalebird-desktop
synced 2025-02-02 10:26:50 +01:00
Implement status detail drawer
This commit is contained in:
parent
a6a7e9da52
commit
974221d001
44
renderer/components/detail/Detail.tsx
Normal file
44
renderer/components/detail/Detail.tsx
Normal file
@ -0,0 +1,44 @@
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { FaChevronLeft, FaX } from 'react-icons/fa6'
|
||||
import Thread from './Thread'
|
||||
import { MegalodonInterface } from 'megalodon'
|
||||
|
||||
type Props = {
|
||||
client: MegalodonInterface
|
||||
}
|
||||
|
||||
export default function Detail(props: Props) {
|
||||
const [target, setTarget] = useState<'status' | null>(null)
|
||||
const router = useRouter()
|
||||
|
||||
useEffect(() => {
|
||||
if (router.query.status_id) {
|
||||
setTarget('status')
|
||||
} else {
|
||||
setTarget(null)
|
||||
}
|
||||
}, [router.query])
|
||||
|
||||
const back = () => {
|
||||
router.back()
|
||||
}
|
||||
|
||||
const close = () => {
|
||||
router.push({ query: { id: router.query.id, timeline: router.query.timeline } })
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{target && (
|
||||
<div className="w-96 h-full fixed top-0 right-0 bg-white shadow-md">
|
||||
<div className="bg-blue-900 text-gray-200 flex justify-between p-2 items-center" style={{ height: '50px' }}>
|
||||
<FaChevronLeft onClick={back} className="cursor-pointer text-lg" />
|
||||
<FaX onClick={close} className="cursor-pointer text-lg" />
|
||||
</div>
|
||||
{target === 'status' && <Thread client={props.client} status_id={router.query.status_id as string} />}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
38
renderer/components/detail/Thread.tsx
Normal file
38
renderer/components/detail/Thread.tsx
Normal file
@ -0,0 +1,38 @@
|
||||
import { Entity, MegalodonInterface } from 'megalodon'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Virtuoso } from 'react-virtuoso'
|
||||
import Status from '../timelines/status/Status'
|
||||
|
||||
type Props = {
|
||||
client: MegalodonInterface
|
||||
status_id: string
|
||||
}
|
||||
|
||||
export default function Thread(props: Props) {
|
||||
const [ancestors, setAncestors] = useState<Array<Entity.Status>>([])
|
||||
const [descendants, setDescendants] = useState<Array<Entity.Status>>([])
|
||||
const [status, setStatus] = useState<Entity.Status | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
if (props.status_id) {
|
||||
const f = async () => {
|
||||
const s = await props.client.getStatus(props.status_id)
|
||||
setStatus(s.data)
|
||||
const res = await props.client.getStatusContext(props.status_id)
|
||||
setAncestors(res.data.ancestors)
|
||||
setDescendants(res.data.descendants)
|
||||
}
|
||||
f()
|
||||
}
|
||||
}, [props.status_id])
|
||||
|
||||
return (
|
||||
<>
|
||||
<Virtuoso
|
||||
style={{ height: '100%' }}
|
||||
data={[...ancestors, status, ...descendants].filter(s => s !== null)}
|
||||
itemContent={(_, status) => <Status client={props.client} status={status} key={status.id} onRefresh={() => {}} />}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
@ -70,7 +70,7 @@ export default function Layout({ children }: LayoutProps) {
|
||||
<Sidebar.Items>
|
||||
<Sidebar.ItemGroup>
|
||||
{pages.map(page => (
|
||||
<Sidebar.Item key={page.id} active={`${page.path}/` === router.asPath} onClick={() => router.push(page.path)}>
|
||||
<Sidebar.Item key={page.id} active={router.asPath.includes(page.path)} onClick={() => router.push(page.path)}>
|
||||
{page.title}
|
||||
</Sidebar.Item>
|
||||
))}
|
||||
|
@ -5,6 +5,7 @@ import { useEffect, useState, useCallback, useRef } from 'react'
|
||||
import { Virtuoso } from 'react-virtuoso'
|
||||
import Status from './status/Status'
|
||||
import { FormattedMessage, useIntl } from 'react-intl'
|
||||
import Detail from '../detail/Detail'
|
||||
|
||||
const TIMELINE_STATUSES_COUNT = 30
|
||||
const TIMELINE_MAX_STATUSES = 2147483647
|
||||
@ -159,6 +160,7 @@ export default function Timeline(props: Props) {
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<Detail client={props.client} />
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import Card from './Card'
|
||||
import Poll from './Poll'
|
||||
import { FormattedMessage } from 'react-intl'
|
||||
import Actions from './Actions'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
type Props = {
|
||||
status: Entity.Status
|
||||
@ -17,12 +18,17 @@ type Props = {
|
||||
|
||||
export default function Status(props: Props) {
|
||||
const status = originalStatus(props.status)
|
||||
const router = useRouter()
|
||||
|
||||
const onRefresh = async () => {
|
||||
const res = await props.client.getStatus(status.id)
|
||||
props.onRefresh(res.data)
|
||||
}
|
||||
|
||||
const openStatus = () => {
|
||||
router.push({ query: { id: router.query.id, timeline: router.query.timeline, status_id: status.id } })
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="border-b mr-2 py-1">
|
||||
{rebloggedHeader(props.status)}
|
||||
@ -39,7 +45,7 @@ export default function Status(props: Props) {
|
||||
></span>
|
||||
<span className="text-gray-600 text-ellipsis break-all overflow-hidden">@{status.account.acct}</span>
|
||||
</div>
|
||||
<div className="text-gray-600 text-right">
|
||||
<div className="text-gray-600 text-right cursor-pointer" onClick={openStatus}>
|
||||
<time dateTime={status.created_at}>{dayjs(status.created_at).format('YYYY-MM-DD HH:mm:ss')}</time>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -16,6 +16,7 @@ export default function Page() {
|
||||
|
||||
useEffect(() => {
|
||||
if (router.query.id) {
|
||||
console.log(router)
|
||||
const f = async () => {
|
||||
const a = await db.accounts.get(parseInt(router.query.id as string))
|
||||
if (a) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user