Skip to content

Commit

Permalink
feat: embed codesandbox
Browse files Browse the repository at this point in the history
Signed-off-by: Innei <i@innei.in>
  • Loading branch information
Innei committed Jul 10, 2023
1 parent d1e7dbb commit e672da5
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 80 deletions.
19 changes: 19 additions & 0 deletions src/components/ui/markdown/customize.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,25 @@ https://github.com/vuejs/vitepress/commit/71eb11f72e60706a546b756dc3fd72d06e2ae4

https://github.com/vuejs/vitepress/commit/71eb11f72e60706a546b756dc3fd72d06e2ae4e2


```
https://codesandbox.io/s/framer-motion-layoutroot-prop-forked-p39g96
```

https://codesandbox.io/s/framer-motion-layoutroot-prop-forked-p39g96

```
https://github.com/toeverything/AFFiNE/blob/master/.github/workflows/nx.yml
```

https://github.com/toeverything/AFFiNE/blob/master/.github/workflows/nx.yml

```
https://github.com/toeverything/AFFiNE/blob/himself65/0710/remove-effect/apps/web/src/atoms/index.ts
```

https://github.com/toeverything/AFFiNE/blob/himself65/0710/remove-effect/apps/web/src/atoms/index.ts

## LinkCard

```
Expand Down
44 changes: 24 additions & 20 deletions src/components/ui/markdown/index.demo.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { useRef } from 'react'
import { ToastContainer } from 'react-toastify'
import { ThemeProvider } from 'next-themes'
import type { DocumentComponent } from 'storybook/typings'
Expand All @@ -8,28 +10,30 @@ import { Markdown } from './Markdown'

export const MarkdownCustomize: DocumentComponent = () => {
return (
<ThemeProvider>
<main className="relative m-auto mt-6 max-w-[800px] border border-accent/10">
<Markdown
extendsRules={{
codeBlock: {
react(node, output, state) {
return (
<pre>
<code>{node.content}</code>
</pre>
)
<QueryClientProvider client={useRef(new QueryClient()).current}>
<ThemeProvider>
<main className="relative m-auto mt-6 max-w-[800px] border border-accent/10">
<Markdown
extendsRules={{
codeBlock: {
react(node, output, state) {
return (
<pre>
<code>{node.content}</code>
</pre>
)
},
},
},
}}
value={customize}
className="prose"
as="article"
/>
</main>
}}
value={customize}
className="prose"
as="article"
/>
</main>

<ToastContainer />
</ThemeProvider>
<ToastContainer />
</ThemeProvider>
</QueryClientProvider>
)
}

Expand Down
86 changes: 26 additions & 60 deletions src/components/ui/markdown/renderers/LinkRenderer.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { useQuery } from '@tanstack/react-query'
import React, { memo, useMemo } from 'react'
import React, { useMemo } from 'react'
import dynamic from 'next/dynamic'

import { GitHubBrandIcon } from '~/components/icons/platform/GitHubBrandIcon'
import {
getTweetId,
isCodesandboxUrl,
isGistUrl,
isGithubCommitUrl,
isGithubFilePreviewUrl,
Expand All @@ -16,9 +16,8 @@ import {
parseGithubTypedUrl,
} from '~/lib/link-parser'

import { HighLighter } from '../../code-highlighter'
import { EmbedGithubFile } from '../../../widgets/shared/EmbedGithubFile'
import { LinkCard } from '../../link-card'
import { Loading } from '../../loading'
import { MLink } from './link'

const Tweet = dynamic(() => import('~/components/widgets/shared/Tweet'), {
Expand Down Expand Up @@ -96,15 +95,35 @@ export const LinkRenderer = ({ href }: { href: string }) => {
case isGithubFilePreviewUrl(url): {
const { owner, repo, afterTypeString } = parseGithubTypedUrl(url)
const splitString = afterTypeString.split('/')
const sha = splitString[0].length === 40 ? splitString[0] : undefined
const path = sha ? splitString.slice(1).join('/') : afterTypeString
const ref = splitString[0]
const path = ref ? splitString.slice(1).join('/') : afterTypeString
return (
<>
<MLink href={href}>{href}</MLink>
<EmbedGithubFile owner={owner} repo={repo} path={path} sha={sha} />
<EmbedGithubFile
owner={owner}
repo={repo}
path={path}
refType={ref}
/>
</>
)
}
case isCodesandboxUrl(url): {
// https://codesandbox.io/s/framer-motion-layoutroot-prop-forked-p39g96
// to
// https://codesandbox.io/embed/framer-motion-layoutroot-prop-forked-p39g96?fontsize=14&hidenavigation=1&theme=dark
return (
<FixedRatioContainer>
<iframe
className="absolute inset-0 h-full w-full rounded-md border-0"
src={`https://codesandbox.io/embed/${url.pathname.slice(
2,
)}?fontsize=14&hidenavigation=1&theme=dark${url.search}`}
/>
</FixedRatioContainer>
)
}
}
}
// fallback to default renderer
Expand Down Expand Up @@ -135,56 +154,3 @@ const FixedRatioContainer = ({
</div>
)
}

const EmbedGithubFile = memo(
({
owner,
path,
repo,
sha,
}: {
owner: string
repo: string
path: string
sha?: string
}) => {
const { data, isLoading, isError } = useQuery<string>({
queryKey: ['github-preview', owner, repo, path, sha],
queryFn: async () => {
return fetch(
`https://cdn.jsdelivr.net/gh/${owner}/${repo}${
sha ? `@${sha}` : ''
}/${path}`,
).then(async (res) => {
return res.text()
})
},
})

if (isLoading) {
return <Loading loadingText="Loading GitHub File Preview..." />
}

if (isError) {
return (
<pre className="flex h-[60px] flex-wrap center">
<code>Loading GitHub File Preview Failed:</code>
<br />
<code>
{owner}/{repo}/{path}
</code>
</pre>
)
}

if (!data) return null

return (
<div className="h-[50vh] overflow-auto">
<HighLighter content={data} lang="javascript" />
</div>
)
},
)

EmbedGithubFile.displayName = 'EmbedGithubFile'
111 changes: 111 additions & 0 deletions src/components/widgets/shared/EmbedGithubFile.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { useQuery } from '@tanstack/react-query'
import React, { memo } from 'react'

import { HighLighter } from '../../ui/code-highlighter'
import { Loading } from '../../ui/loading'

const ext2FileType = {
'.js': 'javascript',
'.ts': 'typescript',
'.jsx': 'javascript',
'.tsx': 'typescript',
'.md': 'markdown',
'.css': 'css',
'.scss': 'scss',
'.html': 'html',
'.json': 'json',
'.yml': 'yaml',
'.yaml': 'yaml',
'.toml': 'toml',
'.xml': 'xml',
'.sh': 'bash',
'.bash': 'bash',
'.zsh': 'bash',
'.fish': 'bash',
'.ps1': 'powershell',
'.bat': 'batch',
'.cmd': 'batch',
'.go': 'go',
'.py': 'python',
'.rb': 'ruby',
'.java': 'java',
'.c': 'c',
'.cpp': 'cpp',
'.cs': 'csharp',
'.rs': 'rust',
'.swift': 'swift',
'.kt': 'kotlin',
'.clj': 'clojure',
'.lua': 'lua',
'.sql': 'sql',
'.graphql': 'graphql',
'.groovy': 'groovy',
'.scala': 'scala',
'.pl': 'perl',
'.r': 'r',
'.dart': 'dart',
'.elm': 'elm',
'.erl': 'erlang',
'.ex': 'elixir',
'.h': 'c',
'.hpp': 'cpp',
'.hxx': 'cpp',
'.hh': 'cpp',
'.h++': 'cpp',
'.m': 'objectivec',
'.mm': 'objectivec',
'.vue': 'vue',
}
export const EmbedGithubFile = memo(
({
owner,
path,
repo,
refType,
}: {
owner: string
repo: string
path: string
refType?: string
}) => {
const ext = path.slice(path.lastIndexOf('.'))
const fileType = (ext2FileType as any)[ext] || 'text'
const { data, isLoading, isError } = useQuery<string>({
queryKey: ['github-preview', owner, repo, path, refType],
queryFn: async () => {
return fetch(
`https://cdn.jsdelivr.net/gh/${owner}/${repo}${
refType ? `@${refType}` : ''
}/${path}`,
).then(async (res) => {
return res.text()
})
},
})

if (isLoading) {
return <Loading loadingText="Loading GitHub File Preview..." />
}

if (isError) {
return (
<pre className="flex h-[60px] flex-wrap center">
<code>Loading GitHub File Preview Failed:</code>
<br />
<code>
{owner}/{repo}/{path}
</code>
</pre>
)
}

if (!data) return null

return (
<div className="h-[50vh] overflow-auto">
<HighLighter content={data} lang={fileType} />
</div>
)
},
)
EmbedGithubFile.displayName = 'EmbedGithubFile'
7 changes: 7 additions & 0 deletions src/lib/link-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ export const isTelegramUrl = (url: URL) => {
return url.hostname === 't.me'
}

export const isCodesandboxUrl = (url: URL) => {
// https://codesandbox.io/s/framer-motion-layoutroot-prop-forked-p39g96
return (
url.hostname === 'codesandbox.io' && url.pathname.split('/').length === 3
)
}

export const parseGithubRepoUrl = (url: URL) => {
const [_, owner, repo] = url.pathname.split('/')
return {
Expand Down

1 comment on commit e672da5

@vercel
Copy link

@vercel vercel bot commented on e672da5 Jul 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

shiro – ./

shiro-git-main-innei.vercel.app
shiro-innei.vercel.app
springtide.vercel.app
innei.in

Please sign in to comment.