index.tsx raw
1 import { useSecondaryPage } from '@/PageManager'
2 import { Button } from '@/components/ui/button'
3 import { Drawer, DrawerContent, DrawerOverlay } from '@/components/ui/drawer'
4 import {
5 DropdownMenu,
6 DropdownMenuContent,
7 DropdownMenuItem,
8 DropdownMenuTrigger
9 } from '@/components/ui/dropdown-menu'
10 import { toExternalContent } from '@/lib/link'
11 import { truncateUrl } from '@/lib/url'
12 import { cn } from '@/lib/utils'
13 import { useScreenSize } from '@/providers/ScreenSizeProvider'
14 import { ExternalLink as ExternalLinkIcon, MessageSquare } from 'lucide-react'
15 import { useMemo, useState } from 'react'
16 import { useTranslation } from 'react-i18next'
17
18 export default function ExternalLink({
19 url,
20 className,
21 justOpenLink
22 }: {
23 url: string
24 className?: string
25 justOpenLink?: boolean
26 }) {
27 const { t } = useTranslation()
28 const { isSmallScreen } = useScreenSize()
29 const { push } = useSecondaryPage()
30 const [isDrawerOpen, setIsDrawerOpen] = useState(false)
31 const displayUrl = useMemo(() => truncateUrl(url), [url])
32
33 const handleOpenLink = (e: React.MouseEvent) => {
34 e.stopPropagation()
35 if (isSmallScreen) {
36 setIsDrawerOpen(false)
37 }
38 window.open(url, '_blank', 'noreferrer')
39 }
40
41 const handleViewDiscussions = (e: React.MouseEvent) => {
42 e.stopPropagation()
43 if (isSmallScreen) {
44 setIsDrawerOpen(false)
45 setTimeout(() => push(toExternalContent(url)), 100) // wait for drawer to close
46 return
47 }
48 push(toExternalContent(url))
49 }
50
51 if (justOpenLink) {
52 return (
53 <a
54 href={url}
55 target="_blank"
56 rel="noreferrer"
57 className={cn('cursor-pointer text-primary hover:underline', className)}
58 onClick={(e) => e.stopPropagation()}
59 >
60 {displayUrl}
61 </a>
62 )
63 }
64
65 const trigger = (
66 <span
67 className={cn('cursor-pointer text-primary hover:underline', className)}
68 onClick={(e) => {
69 e.stopPropagation()
70 if (isSmallScreen) {
71 setIsDrawerOpen(true)
72 }
73 }}
74 title={url}
75 >
76 {displayUrl}
77 </span>
78 )
79
80 if (isSmallScreen) {
81 return (
82 <>
83 {trigger}
84 <Drawer open={isDrawerOpen} onOpenChange={setIsDrawerOpen}>
85 <DrawerOverlay
86 onClick={(e) => {
87 e.stopPropagation()
88 setIsDrawerOpen(false)
89 }}
90 />
91 <DrawerContent hideOverlay>
92 <div className="py-2">
93 <Button
94 onClick={handleOpenLink}
95 className="w-full p-6 justify-start text-lg gap-4 [&_svg]:size-5"
96 variant="ghost"
97 >
98 <ExternalLinkIcon />
99 {t('Open link')}
100 </Button>
101 <Button
102 onClick={handleViewDiscussions}
103 className="w-full p-6 justify-start text-lg gap-4 [&_svg]:size-5"
104 variant="ghost"
105 >
106 <MessageSquare />
107 {t('View Nostr discussions')}
108 </Button>
109 </div>
110 </DrawerContent>
111 </Drawer>
112 </>
113 )
114 }
115
116 return (
117 <DropdownMenu>
118 <DropdownMenuTrigger>
119 <span className={cn('cursor-pointer text-primary hover:underline', className)} title={url}>
120 {displayUrl}
121 </span>
122 </DropdownMenuTrigger>
123 <DropdownMenuContent align="start" onClick={(e) => e.stopPropagation()}>
124 <DropdownMenuItem onClick={handleOpenLink}>
125 <ExternalLinkIcon />
126 {t('Open link')}
127 </DropdownMenuItem>
128 <DropdownMenuItem onClick={handleViewDiscussions}>
129 <MessageSquare />
130 {t('View Nostr discussions')}
131 </DropdownMenuItem>
132 </DropdownMenuContent>
133 </DropdownMenu>
134 )
135 }
136