Files
btrc-hub/frontend/src/components/PostEmbed.tsx
T
2026-05-10 11:16:49 +09:00

105 lines
2.5 KiB
TypeScript

import { useState } from 'react'
import YoutubeEmbed from 'react-youtube'
import NicoViewer from '@/components/NicoViewer'
import TwitterEmbed from '@/components/TwitterEmbed'
import { useDialogue } from '@/components/dialogues/DialogueProvider'
import type { FC, RefObject } from 'react'
import type { NiconicoMetadata, NiconicoVideoInfo, NiconicoViewerHandle, Post } from '@/types'
type Props = {
ref?: RefObject<NiconicoViewerHandle | null>
post: Post
onLoadComplete?: (info: NiconicoVideoInfo) => void
onMetadataChange?: (meta: NiconicoMetadata) => void }
export default (({ ref, post, onLoadComplete, onMetadataChange }: Props) => {
const dialogue = useDialogue ()
const url = new URL (post.url)
switch (url.hostname.split ('.').slice (-2).join ('.'))
{
case 'nicovideo.jp':
{
const mVideoId = url.pathname.match (/(?<=\/watch\/)[a-zA-Z0-9]+?(?=\/|$)/)
if (!(mVideoId))
break
const [videoId] = mVideoId
return (
<NicoViewer
ref={ref}
id={videoId}
width={640}
height={360}
onLoadComplete={onLoadComplete}
onMetadataChange={onMetadataChange}/>)
}
case 'twitter.com':
case 'x.com':
{
const mUserId = url.pathname.match (/(?<=\/)[^\/]+?(?=\/|$|\?)/)
const mStatusId = url.pathname.match (/(?<=\/status\/)\d+?(?=\/|$|\?)/)
if (!(mUserId) || !(mStatusId))
break
const [userId] = mUserId
const [statusId] = mStatusId
return <TwitterEmbed userId={userId} statusId={statusId}/>
}
case 'youtube.com':
{
const videoId = url.searchParams.get ('v')
if (!(videoId))
break
return (
<YoutubeEmbed videoId={videoId} opts={{ playerVars: {
playsinline: 1,
autoplay: 1,
mute: 0,
loop: 1,
width: '640',
height: '360' } }}/>)
}
}
const [framed, setFramed] = useState (false)
return (
<>
{framed
? (
<iframe
src={post.url}
title={post.title || post.url}
width={640}
height={360}/>)
: (
<div>
<a href="#" onClick={async e => {
e.preventDefault ()
setFramed (await dialogue.confirm ({
title: '未確認の外部ページを表示します。',
description: (
<div>
<p></p>
<p>?</p>
</div>),
confirmText: '表示' }))
}}>
</a>
</div>)}
</>)
}) satisfies FC<Props>