index.tsx99 lines · main
1import { useParams } from 'common'
2import { PropsWithChildren } from 'react'
3import { cn } from 'ui'
4
5import { useAvailableIntegrations } from '../../Landing/useAvailableIntegrations'
6import { FilesViewer } from './FilesViewer'
7import { MarkdownContent } from './MarkdownContent'
8import { InlineLinkClassName } from '@/components/ui/InlineLink'
9
10const getSiteUrlLabel = (url: string | undefined | null) => {
11 if (!url) return undefined
12
13 try {
14 return new URL(url).origin
15 } catch (error) {
16 return undefined
17 }
18}
19
20const isGithubHost = (url: string | undefined | null) => {
21 if (!url) return false
22 try {
23 const hostname = new URL(url).hostname.toLowerCase()
24 return hostname === 'github.com' || hostname.endsWith('.github.com')
25 } catch (error) {
26 return false
27 }
28}
29
30/**
31 * [Joshen] This will serve as the overview tab for remotely fetched integrations
32 */
33export const IntegrationOverviewTabV2 = ({ children }: PropsWithChildren) => {
34 const { id } = useParams()
35
36 const { data: allIntegrations } = useAvailableIntegrations()
37 const integration = allIntegrations.find((i) => i.id === id)
38
39 if (!integration) {
40 return <div>Unsupported integration type</div>
41 }
42
43 const { type, content, docsUrl, siteUrl, files = [] } = integration
44
45 const docsUrlLabel = docsUrl?.includes('supabase.com/docs')
46 ? 'Briven Docs'
47 : isGithubHost(docsUrl)
48 ? 'GitHub Docs'
49 : 'Documentation'
50 const siteUrlLabel = getSiteUrlLabel(siteUrl)
51
52 return (
53 <div className="grid grid-cols-3 gap-x-8 px-10 py-8">
54 <div className="col-span-2 flex flex-col gap-y-8">
55 {files.length > 0 && <FilesViewer files={files} />}
56 <MarkdownContent integrationId={id} content={content} />
57 {children}
58 </div>
59
60 <div className="text-sm col-span-1 flex flex-col gap-y-8">
61 <div className="flex flex-col gap-y-4">
62 <p>Details</p>
63
64 <div className="flex flex-col gap-y-1">
65 <p className="font-mono uppercase text-foreground-light">Type</p>
66 <p className="capitalize">{type === 'oauth' ? 'OAuth' : type.replaceAll('_', ' ')}</p>
67 </div>
68
69 <div className="flex flex-col gap-y-1">
70 <p className="font-mono uppercase text-foreground-light">Built by</p>
71 <p className={cn(!integration.author.name && 'text-foreground-lighter')}>
72 {integration.author.name || 'Unknown Author'}
73 </p>
74 </div>
75
76 {docsUrl && (
77 <div className="flex flex-col gap-y-1">
78 <p className="font-mono uppercase text-foreground-light">Docs</p>
79 <a target="_blank" rel="noreferrer" href={docsUrl} className={InlineLinkClassName}>
80 {docsUrlLabel}
81 </a>
82 </div>
83 )}
84
85 {siteUrl && (
86 <div className="flex flex-col gap-y-1">
87 <p className="font-mono uppercase text-foreground-light">Website</p>
88 <a target="_blank" rel="noreferrer" href={siteUrl} className={InlineLinkClassName}>
89 {siteUrlLabel}
90 </a>
91 </div>
92 )}
93 </div>
94
95 {/* Subsequent other actions here */}
96 </div>
97 </div>
98 )
99}