@@ -4,8 +4,15 @@ import { type Theme } from 'react-shiki';
44import useSWR from 'swr' ;
55
66import { Label , P } from '~/common/styleguide' ;
7- import { CodeIcon , ImageFileIcon , TempFileIcon } from '~/components/Icons' ;
7+ import {
8+ CodeIcon ,
9+ FileIcon ,
10+ ImageFileIcon ,
11+ MarkdownPreviewIcon ,
12+ TempFileIcon ,
13+ } from '~/components/Icons' ;
814import CopyButton from '~/components/Package/CopyButton' ;
15+ import MarkdownRenderer from '~/components/Package/MarkdownContentBox/MarkdownRenderer' ;
916import ThreeDotsLoader from '~/components/Package/ThreeDotsLoader' ;
1017import Tooltip from '~/components/Tooltip' ;
1118import rndDark from '~/styles/shiki/rnd-dark.json' ;
@@ -27,6 +34,7 @@ type Props = {
2734 packageName : string ;
2835 isBrowserMaximized : boolean ;
2936 toggleMaximized : ( ) => void ;
37+ repoUrl : string ;
3038 filePath : string ;
3139 fileData ?: UnpkgMeta [ 'files' ] [ number ] ;
3240} ;
@@ -35,22 +43,27 @@ export default function CodeBrowserContent({
3543 packageName,
3644 isBrowserMaximized,
3745 toggleMaximized,
46+ repoUrl,
3847 filePath,
3948 fileData,
4049} : Props ) {
4150 const [ rawPreview , setRawPreview ] = useState ( false ) ;
51+ const [ markdownPreview , setMarkdownPreview ] = useState ( false ) ;
4252 const [ imageData , setImageData ] = useState <
4353 SyntheticEvent < HTMLImageElement > [ 'currentTarget' ] | null
4454 > ( null ) ;
4555
4656 useEffect ( ( ) => {
4757 setImageData ( null ) ;
58+ setRawPreview ( false ) ;
59+ setMarkdownPreview ( false ) ;
4860 } , [ filePath ] ) ;
4961
5062 const fileExtension = filePath . split ( '.' ) . at ( - 1 ) ?? 'text' ;
5163 const isTooBig = Boolean ( fileData ?. size && fileData . size > 1024 * 1024 * 4 ) ;
5264 const isPreviewDisabled = PREVIEW_DISABLED_FILES . includes ( fileExtension ) || isTooBig ;
5365 const isImageFile = IMAGE_FILES . includes ( fileExtension ) ;
66+ const isMarkdownFile = [ 'md' , 'mdx' ] . includes ( fileExtension ) ;
5467 const allowRawPreview = isImageFile && filePath . endsWith ( '.svg' ) ;
5568
5669 const { data, isLoading } = useSWR < string > (
@@ -116,6 +129,20 @@ export default function CodeBrowserContent({
116129 Show image preview
117130 </ Tooltip >
118131 ) }
132+ { isMarkdownFile && (
133+ < Tooltip
134+ trigger = {
135+ < Pressable onPress = { ( ) => setMarkdownPreview ( previewMode => ! previewMode ) } >
136+ { markdownPreview ? (
137+ < FileIcon style = { tw `size-5 text-palette-gray4 dark:text-pewter` } />
138+ ) : (
139+ < MarkdownPreviewIcon style = { tw `size-5 text-palette-gray4 dark:text-pewter` } />
140+ ) }
141+ </ Pressable >
142+ } >
143+ { markdownPreview ? 'Markdown code' : 'Markdown preview' }
144+ </ Tooltip >
145+ ) }
119146 < DownloadFileButton filePath = { filePath } packageName = { packageName } />
120147 < CopyButton
121148 data = { data }
@@ -129,26 +156,39 @@ export default function CodeBrowserContent({
129156 />
130157 </ View >
131158 </ CodeBrowserContentHeader >
132- < CodeBrowserContentHighlighter
133- code = { data }
134- lang = { filePath . split ( '.' ) . at ( - 1 ) ?? 'text' }
135- theme = { ( tw . prefixMatch ( 'dark' ) ? rndDark : rndLight ) as Theme }
136- />
137- < CodeBrowserContentFooter
138- leftSlot = {
139- < Label style = { tw `font-light text-secondary` } >
140- < span style = { tw `font-medium` } > { data . split ( '\n' ) . length } </ span > { ' ' }
141- { pluralize ( 'line' , data . split ( '\n' ) . length ) }
142- </ Label >
143- }
144- rightSlot = {
145- fileData && (
159+ { markdownPreview ? (
160+ < View
161+ id = "markdownContentWrapper"
162+ style = { [
163+ tw `bg-default px-6 pb-6 pt-4` ,
164+ { overflowY : 'auto' , maxHeight : 'calc(100% - 46px)' } ,
165+ ] } >
166+ < MarkdownRenderer data = { data } repoUrl = { repoUrl } linkableHeaders = { false } />
167+ </ View >
168+ ) : (
169+ < CodeBrowserContentHighlighter
170+ code = { data }
171+ lang = { filePath . split ( '.' ) . at ( - 1 ) ?? 'text' }
172+ theme = { ( tw . prefixMatch ( 'dark' ) ? rndDark : rndLight ) as Theme }
173+ />
174+ ) }
175+ { ! markdownPreview && (
176+ < CodeBrowserContentFooter
177+ leftSlot = {
146178 < Label style = { tw `font-light text-secondary` } >
147- < span style = { tw `font-medium` } > { formatBytes ( fileData . size ) } </ span >
179+ < span style = { tw `font-medium` } > { data . split ( '\n' ) . length } </ span > { ' ' }
180+ { pluralize ( 'line' , data . split ( '\n' ) . length ) }
148181 </ Label >
149- )
150- }
151- />
182+ }
183+ rightSlot = {
184+ fileData && (
185+ < Label style = { tw `font-light text-secondary` } >
186+ < span style = { tw `font-medium` } > { formatBytes ( fileData . size ) } </ span >
187+ </ Label >
188+ )
189+ }
190+ />
191+ ) }
152192 </ >
153193 ) ;
154194 }
0 commit comments