ぼざクリタグ広場 https://hub.nizika.monster
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

68 lines
1.7 KiB

  1. import { useState } from 'react'
  2. import YoutubeEmbed from 'react-youtube'
  3. import NicoViewer from '@/components/NicoViewer'
  4. import TwitterEmbed from '@/components/TwitterEmbed'
  5. import type { FC } from 'react'
  6. import type { Post } from '@/types'
  7. type Props = { post: Post }
  8. export default (({ post }: Props) => {
  9. const url = new URL (post.url)
  10. switch (url.hostname.split ('.').slice (-2).join ('.'))
  11. {
  12. case 'nicovideo.jp':
  13. {
  14. const [videoId] = url.pathname.match (/(?<=\/watch\/)[a-zA-Z0-9]+?(?=\/|$)/)!
  15. return <NicoViewer id={videoId} width={640} height={360}/>
  16. }
  17. case 'twitter.com':
  18. case 'x.com':
  19. const [userId] = url.pathname.match (/(?<=\/)[^\/]+?(?=\/|$|\?)/)!
  20. const [statusId] = url.pathname.match (/(?<=\/status\/)\d+?(?=\/|$|\?)/)!
  21. return <TwitterEmbed userId={userId} statusId={statusId}/>
  22. case 'youtube.com':
  23. {
  24. const videoId = url.searchParams.get ('v')!
  25. return (
  26. <YoutubeEmbed videoId={videoId} opts={{ playerVars: {
  27. playsinline: 1,
  28. autoplay: 1,
  29. mute: 0,
  30. loop: 1,
  31. width: '640',
  32. height: '360' } }}/>)
  33. }
  34. }
  35. const [framed, setFramed] = useState (false)
  36. return (
  37. <>
  38. {framed
  39. ? (
  40. <iframe
  41. src={post.url}
  42. title={post.title || post.url}
  43. width={640}
  44. height={360}/>)
  45. : (
  46. <div>
  47. <a href="#" onClick={e => {
  48. e.preventDefault ()
  49. setFramed (confirm ('未確認の外部ページを表示します。\n'
  50. + '悪意のあるスクリプトが実行される可能性があります。\n'
  51. + '表示しますか?'))
  52. return
  53. }}>
  54. 外部ページを表示
  55. </a>
  56. </div>)}
  57. </>)
  58. }) satisfies FC<Props>