Implement reply
This commit is contained in:
parent
ea13f7170c
commit
dd032b6245
|
@ -7,6 +7,7 @@ import { useToast } from '@/utils/toast'
|
|||
|
||||
type Props = {
|
||||
client: MegalodonInterface
|
||||
in_reply_to?: Entity.Status
|
||||
}
|
||||
|
||||
export default function Compose(props: Props) {
|
||||
|
@ -27,6 +28,20 @@ export default function Compose(props: Props) {
|
|||
}
|
||||
}, [cw])
|
||||
|
||||
useEffect(() => {
|
||||
if (props.in_reply_to) {
|
||||
const f = async () => {
|
||||
const myself = await props.client.verifyAccountCredentials()
|
||||
const mentionAccounts = [props.in_reply_to.account.acct, ...props.in_reply_to.mentions.map(a => a.acct)]
|
||||
.filter((a, i, self) => self.indexOf(a) === i)
|
||||
.filter(a => a !== myself.data.username)
|
||||
setBody(`${mentionAccounts.map(m => `@${m}`).join(' ')} `)
|
||||
setVisibility(props.in_reply_to.visibility)
|
||||
}
|
||||
f()
|
||||
}
|
||||
}, [props.in_reply_to])
|
||||
|
||||
const post = async () => {
|
||||
if (body.length === 0) return
|
||||
let options = { visibility: visibility }
|
||||
|
|
|
@ -3,18 +3,21 @@ import { HTMLAttributes, useEffect, useState } from 'react'
|
|||
import { FaChevronLeft, FaX } from 'react-icons/fa6'
|
||||
import Thread from './Thread'
|
||||
import { MegalodonInterface } from 'megalodon'
|
||||
import Reply from './Reply'
|
||||
|
||||
type Props = {
|
||||
client: MegalodonInterface
|
||||
} & HTMLAttributes<HTMLElement>
|
||||
|
||||
export default function Detail(props: Props) {
|
||||
const [target, setTarget] = useState<'status' | null>(null)
|
||||
const [target, setTarget] = useState<'status' | 'reply' | null>(null)
|
||||
const router = useRouter()
|
||||
|
||||
useEffect(() => {
|
||||
if (router.query.status_id) {
|
||||
setTarget('status')
|
||||
} else if (router.query.reply_target_id) {
|
||||
setTarget('reply')
|
||||
} else {
|
||||
setTarget(null)
|
||||
}
|
||||
|
@ -37,6 +40,7 @@ export default function Detail(props: Props) {
|
|||
<FaX onClick={close} className="cursor-pointer text-lg" />
|
||||
</div>
|
||||
{target === 'status' && <Thread client={props.client} status_id={router.query.status_id as string} />}
|
||||
{target === 'reply' && <Reply client={props.client} status_id={router.query.reply_target_id as string} />}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
import { MegalodonInterface, Entity } from 'megalodon'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { Virtuoso } from 'react-virtuoso'
|
||||
import Status from '../timelines/status/Status'
|
||||
import Compose from '../compose/Compose'
|
||||
|
||||
type Props = {
|
||||
client: MegalodonInterface
|
||||
status_id: string
|
||||
}
|
||||
|
||||
export default function Reply(props: Props) {
|
||||
const [ancestors, setAncestors] = useState<Array<Entity.Status>>([])
|
||||
const [status, setStatus] = useState<Entity.Status | null>(null)
|
||||
const [composeHeight, setComposeHeight] = useState(120)
|
||||
|
||||
const composeRef = useRef<HTMLDivElement | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
const observer = new ResizeObserver(entries => {
|
||||
entries.forEach(el => {
|
||||
setComposeHeight(el.contentRect.height)
|
||||
})
|
||||
})
|
||||
if (composeRef.current) {
|
||||
observer.observe(composeRef.current)
|
||||
}
|
||||
return () => {
|
||||
observer.disconnect()
|
||||
}
|
||||
}, [])
|
||||
|
||||
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)
|
||||
}
|
||||
f()
|
||||
}
|
||||
}, [props.status_id])
|
||||
|
||||
return (
|
||||
<div className="overflow-x-hidden" style={{ height: 'calc(100% - 50px)' }}>
|
||||
<Virtuoso
|
||||
style={{ height: `calc(100% - ${composeHeight}px)` }}
|
||||
data={[...ancestors, status].filter(s => s !== null)}
|
||||
itemContent={(_, status) => <Status client={props.client} status={status} key={status.id} onRefresh={() => {}} />}
|
||||
/>
|
||||
<div ref={composeRef}>
|
||||
<Compose client={props.client} in_reply_to={status} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -148,7 +148,7 @@ export default function Timeline(props: Props) {
|
|||
}, [firstItemIndex, statuses, setStatuses, unreads])
|
||||
|
||||
const timelineClass = () => {
|
||||
if (router.query.status_id) {
|
||||
if (router.query.detail) {
|
||||
return 'timeline-with-drawer'
|
||||
}
|
||||
return 'timeline'
|
||||
|
@ -167,7 +167,7 @@ export default function Timeline(props: Props) {
|
|||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div className={`overflow-x-hidden`} style={{ height: 'calc(100% - 50px)' }}>
|
||||
<div className="overflow-x-hidden" style={{ height: 'calc(100% - 50px)' }}>
|
||||
<Virtuoso
|
||||
style={{ height: `calc(100% - ${composeHeight}px)` }}
|
||||
scrollerRef={ref => {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { Entity, MegalodonInterface } from 'megalodon'
|
||||
import { useRouter } from 'next/router'
|
||||
import { FaBookmark, FaEllipsis, FaReply, FaRetweet, FaStar } from 'react-icons/fa6'
|
||||
|
||||
type Props = {
|
||||
|
@ -8,6 +9,12 @@ type Props = {
|
|||
}
|
||||
|
||||
export default function Actions(props: Props) {
|
||||
const router = useRouter()
|
||||
|
||||
const reply = async () => {
|
||||
router.push({ query: { id: router.query.id, timeline: router.query.timeline, reply_target_id: props.status.id, detail: true } })
|
||||
}
|
||||
|
||||
const reblog = async () => {
|
||||
if (props.status.reblogged) {
|
||||
await props.client.unreblogStatus(props.status.id)
|
||||
|
@ -37,7 +44,7 @@ export default function Actions(props: Props) {
|
|||
|
||||
return (
|
||||
<div className="flex gap-6">
|
||||
<FaReply className={`w-4 text-gray-400 cursor-pointer hover:text-gray-600`} />
|
||||
<FaReply className={`w-4 text-gray-400 cursor-pointer hover:text-gray-600`} onClick={reply} />
|
||||
<FaRetweet className={`${retweetColor(props.status)} w-4 cursor-pointer hover:text-gray-600`} onClick={reblog} />
|
||||
<FaStar className={`${favouriteColor(props.status)} w-4 cursor-pointer hover:text-gray-600`} onClick={favourite} />
|
||||
<FaBookmark className={`${bookmarkColor(props.status)} w-4 cursor-pointer hover:text-gray-600`} onClick={bookmark} />
|
||||
|
|
|
@ -28,7 +28,7 @@ export default function Status(props: Props) {
|
|||
}
|
||||
|
||||
const openStatus = () => {
|
||||
router.push({ query: { id: router.query.id, timeline: router.query.timeline, status_id: status.id } })
|
||||
router.push({ query: { id: router.query.id, timeline: router.query.timeline, status_id: status.id, detail: true } })
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
Loading…
Reference in New Issue