Whalebird-desktop-client-ma.../renderer/components/detail/Profile.tsx

143 lines
5.5 KiB
TypeScript
Raw Normal View History

2023-12-02 03:50:42 +01:00
import emojify from '@/utils/emojify'
2023-12-02 05:30:01 +01:00
import { Avatar, Button, CustomFlowbiteTheme, Dropdown, Flowbite, Tabs } from 'flowbite-react'
2023-12-02 03:50:42 +01:00
import { Entity, MegalodonInterface } from 'megalodon'
2023-12-02 16:52:51 +01:00
import { MouseEventHandler, useEffect, useState } from 'react'
2023-12-02 03:50:42 +01:00
import { FaEllipsisVertical } from 'react-icons/fa6'
2023-12-02 05:30:01 +01:00
import { FormattedMessage, useIntl } from 'react-intl'
import Timeline from './profile/Timeline'
2023-12-02 05:53:43 +01:00
import Followings from './profile/Followings'
2023-12-02 07:06:47 +01:00
import Followers from './profile/Followers'
2023-12-02 16:52:51 +01:00
import { findLink } from '@/utils/statusParser'
import { Account } from '@/db'
2023-12-02 03:50:42 +01:00
type Props = {
client: MegalodonInterface
account: Account
2023-12-02 03:50:42 +01:00
user_id: string
2023-12-02 11:26:45 +01:00
openMedia: (media: Entity.Attachment) => void
2023-12-02 03:50:42 +01:00
}
2023-12-02 05:30:01 +01:00
const customTheme: CustomFlowbiteTheme = {
2023-12-21 16:49:13 +01:00
tabs: {
2023-12-02 05:30:01 +01:00
tablist: {
tabitem: {
base: 'flex items-center justify-center p-4 rounded-t-lg text-sm font-medium first:ml-0 disabled:cursor-not-allowed disabled:text-gray-400 disabled:dark:text-gray-500'
}
}
}
}
2023-12-02 03:50:42 +01:00
export default function Profile(props: Props) {
const [user, setUser] = useState<Entity.Account | null>(null)
const [relationship, setRelationship] = useState<Entity.Relationship | null>(null)
2023-12-02 05:30:01 +01:00
const { formatMessage } = useIntl()
2023-12-02 03:50:42 +01:00
useEffect(() => {
const f = async () => {
if (props.user_id) {
const res = await props.client.getAccount(props.user_id)
setUser(res.data)
const rel = await props.client.getRelationship(props.user_id)
setRelationship(rel.data)
}
}
f()
}, [props.user_id, props.client])
const follow = async (id: string) => {
const rel = await props.client.followAccount(id)
setRelationship(rel.data)
}
const unfollow = async (id: string) => {
const rel = await props.client.unfollowAccount(id)
setRelationship(rel.data)
}
const openOriginal = async (url: string) => {
global.ipc.invoke('open-browser', url)
}
2023-12-02 16:52:51 +01:00
const profileClicked: MouseEventHandler<HTMLDivElement> = async e => {
const url = findLink(e.target as HTMLElement, 'profile')
if (url) {
global.ipc.invoke('open-browser', url)
e.preventDefault()
e.stopPropagation()
}
}
2023-12-02 03:50:42 +01:00
return (
2023-12-02 07:13:28 +01:00
<div style={{ height: 'calc(100% - 50px)' }} className="overflow-y-auto timeline-scrollable">
2023-12-02 05:30:01 +01:00
<Flowbite theme={{ theme: customTheme }}>
{user && relationship && (
<>
<div className="header-image w-full bg-gray-100">
<img src={user.header} alt="header image" className="w-full object-cover h-40" />
</div>
<div className="p-5">
<div className="flex items-end justify-between" style={{ marginTop: '-50px' }}>
<Avatar img={user.avatar} size="lg" stacked />
<div className="flex gap-2">
{relationship.following ? (
<Button onClick={() => unfollow(user.id)}>
<FormattedMessage id="profile.unfollow" />
</Button>
) : (
<Button onClick={() => follow(user.id)}>
<FormattedMessage id="profile.follow" />
2023-12-02 03:50:42 +01:00
</Button>
)}
2023-12-02 05:30:01 +01:00
<Dropdown
label=""
renderTrigger={() => (
<Button color="gray">
<FaEllipsisVertical />
</Button>
)}
>
<Dropdown.Item onClick={() => openOriginal(user.url)}>
<FormattedMessage id="profile.open_original" />
</Dropdown.Item>
</Dropdown>
</div>
2023-12-02 03:50:42 +01:00
</div>
2023-12-02 05:30:01 +01:00
<div className="pt-4">
2023-12-02 05:53:43 +01:00
<div className="font-bold" dangerouslySetInnerHTML={{ __html: emojify(user.display_name, user.emojis) }} />
2023-12-02 05:30:01 +01:00
<div className="text-gray-500">@{user.acct}</div>
2023-12-02 16:52:51 +01:00
<div className="mt-4 raw-html profile" onClick={profileClicked}>
2023-12-02 05:30:01 +01:00
<span
dangerouslySetInnerHTML={{ __html: emojify(user.note, user.emojis) }}
className="overflow-hidden break-all text-gray-800"
/>
</div>
2023-12-02 16:52:51 +01:00
<div className="bg-gray-100 overflow-hidden break-all raw-html mt-2 profile" onClick={profileClicked}>
2023-12-02 05:30:01 +01:00
{user.fields.map((data, index) => (
<dl key={index} className="px-4 py-2 border-gray-200 border-b">
<dt className="text-gray-500">{data.name}</dt>
<dd className="text-gray-700" dangerouslySetInnerHTML={{ __html: emojify(data.value, user.emojis) }} />
</dl>
))}
</div>
2023-12-02 03:50:42 +01:00
</div>
</div>
2023-12-02 05:30:01 +01:00
<div>
2023-12-21 16:49:13 +01:00
<Tabs aria-label="Tabs with icons" style="underline">
2023-12-02 05:30:01 +01:00
<Tabs.Item active title={formatMessage({ id: 'profile.timeline' })}>
<Timeline client={props.client} account={props.account} user_id={props.user_id} openMedia={props.openMedia} />
2023-12-02 05:30:01 +01:00
</Tabs.Item>
2023-12-02 05:53:43 +01:00
<Tabs.Item title={formatMessage({ id: 'profile.followings' })}>
<Followings client={props.client} user_id={props.user_id} />
</Tabs.Item>
2023-12-02 05:30:01 +01:00
<Tabs.Item title={formatMessage({ id: 'profile.followers' })} className="focus:ring-0">
2023-12-02 07:06:47 +01:00
<Followers client={props.client} user_id={props.user_id} />
2023-12-02 05:30:01 +01:00
</Tabs.Item>
2023-12-21 16:49:13 +01:00
</Tabs>
2023-12-02 05:30:01 +01:00
</div>
</>
)}
</Flowbite>
2023-12-02 03:50:42 +01:00
</div>
)
}