refs #4653 Display hashtag timeline in detail
This commit is contained in:
parent
aa8f0922fb
commit
a2c61be256
@ -5,6 +5,7 @@ import Thread from './Thread'
|
||||
import { Entity, MegalodonInterface } from 'megalodon'
|
||||
import Reply from './Reply'
|
||||
import Profile from './Profile'
|
||||
import Tag from './Tag'
|
||||
import { Account } from '@/db'
|
||||
|
||||
type Props = {
|
||||
@ -14,7 +15,7 @@ type Props = {
|
||||
} & HTMLAttributes<HTMLElement>
|
||||
|
||||
export default function Detail(props: Props) {
|
||||
const [target, setTarget] = useState<'status' | 'reply' | 'profile' | null>(null)
|
||||
const [target, setTarget] = useState<'status' | 'reply' | 'profile' | 'tag' | null>(null)
|
||||
const router = useRouter()
|
||||
|
||||
useEffect(() => {
|
||||
@ -24,6 +25,8 @@ export default function Detail(props: Props) {
|
||||
setTarget('reply')
|
||||
} else if (router.query.user_id) {
|
||||
setTarget('profile')
|
||||
} else if (router.query.tag) {
|
||||
setTarget('tag')
|
||||
} else {
|
||||
setTarget(null)
|
||||
}
|
||||
@ -42,8 +45,13 @@ export default function Detail(props: Props) {
|
||||
{target && (
|
||||
<div className={`bg-white ${props.className}`} style={props.style}>
|
||||
<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 className="flex gap-4 items-center">
|
||||
<FaChevronLeft onClick={back} className="cursor-pointer text-lg" />
|
||||
{target === 'tag' && `#${router.query.tag}`}
|
||||
</div>
|
||||
<div>
|
||||
<FaX onClick={close} className="cursor-pointer text-lg" />
|
||||
</div>
|
||||
</div>
|
||||
{target === 'status' && (
|
||||
<Thread
|
||||
@ -64,6 +72,9 @@ export default function Detail(props: Props) {
|
||||
{target === 'profile' && (
|
||||
<Profile client={props.client} account={props.account} user_id={router.query.user_id as string} openMedia={props.openMedia} />
|
||||
)}
|
||||
{target === 'tag' && (
|
||||
<Tag client={props.client} account={props.account} tag={router.query.tag as string} openMedia={props.openMedia} />
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
@ -49,6 +49,7 @@ export default function Reply(props: Props) {
|
||||
<div className="overflow-x-hidden" style={{ height: 'calc(100% - 50px)' }}>
|
||||
<Virtuoso
|
||||
style={{ height: `calc(100% - ${composeHeight}px)` }}
|
||||
className="timeline-scrollable"
|
||||
data={[...ancestors, status].filter(s => s !== null)}
|
||||
itemContent={(_, status) => (
|
||||
<Status
|
||||
|
46
renderer/components/detail/Tag.tsx
Normal file
46
renderer/components/detail/Tag.tsx
Normal file
@ -0,0 +1,46 @@
|
||||
import { Account } from '@/db'
|
||||
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
|
||||
account: Account
|
||||
tag: string
|
||||
openMedia: (media: Entity.Attachment) => void
|
||||
}
|
||||
|
||||
export default function Tag(props: Props) {
|
||||
const [statuses, setStatuses] = useState<Array<Entity.Status>>([])
|
||||
|
||||
useEffect(() => {
|
||||
if (props.client && props.tag) {
|
||||
const f = async () => {
|
||||
const res = await props.client.getTagTimeline(props.tag)
|
||||
setStatuses(res.data)
|
||||
}
|
||||
f()
|
||||
}
|
||||
}, [props.client, props.tag])
|
||||
|
||||
return (
|
||||
<div className="overflow-x-hidden" style={{ height: 'calc(100% - 50px)' }}>
|
||||
<Virtuoso
|
||||
style={{ height: '100%' }}
|
||||
data={statuses}
|
||||
className="timeline-scrollable"
|
||||
itemContent={(_, status) => (
|
||||
<Status
|
||||
client={props.client}
|
||||
account={props.account}
|
||||
status={status}
|
||||
key={status.id}
|
||||
onRefresh={() => {}}
|
||||
openMedia={props.openMedia}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
@ -33,6 +33,7 @@ export default function Thread(props: Props) {
|
||||
<>
|
||||
<Virtuoso
|
||||
style={{ height: 'calc(100% - 50px)' }}
|
||||
className="timeline-scrollable"
|
||||
data={[...ancestors, status, ...descendants].filter(s => s !== null)}
|
||||
itemContent={(_, status) => (
|
||||
<Status
|
||||
|
@ -3,7 +3,7 @@ import { CustomFlowbiteTheme, Flowbite, Sidebar } from 'flowbite-react'
|
||||
import generator, { Entity } from 'megalodon'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { FaBell, FaGlobe, FaHashtag, FaHouse, FaUsers } from 'react-icons/fa6'
|
||||
import { FaBell, FaGlobe, FaHouse, FaList, FaUsers } from 'react-icons/fa6'
|
||||
import { useIntl } from 'react-intl'
|
||||
|
||||
type LayoutProps = {
|
||||
@ -107,7 +107,7 @@ export default function Layout({ children }: LayoutProps) {
|
||||
key={list.id}
|
||||
active={router.asPath.includes(`list_${list.id}`)}
|
||||
onClick={() => router.push({ pathname: `/accounts/${router.query.id}/list_${list.id}` })}
|
||||
icon={FaHashtag}
|
||||
icon={FaList}
|
||||
className="sidebar-menu-item"
|
||||
>
|
||||
<span className="sidebar-menu">{list.title}</span>
|
||||
|
@ -10,7 +10,7 @@ import { FormattedMessage } from 'react-intl'
|
||||
import Actions from './Actions'
|
||||
import { useRouter } from 'next/router'
|
||||
import { MouseEventHandler, useState } from 'react'
|
||||
import { findAccount, findLink, ParsedAccount, accountMatch } from '@/utils/statusParser'
|
||||
import { findAccount, findLink, ParsedAccount, accountMatch, findTag } from '@/utils/statusParser'
|
||||
import { Account } from '@/db'
|
||||
|
||||
type Props = {
|
||||
@ -54,7 +54,13 @@ export default function Status(props: Props) {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: find tag
|
||||
const parsedTag = findTag(e.target as HTMLElement, 'status-body')
|
||||
if (parsedTag) {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
router.push({ query: { id: router.query.id, timeline: router.query.timeline, tag: parsedTag, detail: true } })
|
||||
return
|
||||
}
|
||||
|
||||
const url = findLink(e.target as HTMLElement, 'status-body')
|
||||
if (url) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user