Skip to content

Commit

Permalink
Embedding Repl for previews using UIDL (#74)
Browse files Browse the repository at this point in the history
* Upgrading smooshpck to new package

* Testing embedable version for preview

* testing events

* Some style changes for the embed preview

* Updated yarn lock
  • Loading branch information
JayaKrishnaNamburu authored Mar 17, 2021
1 parent f06c2f8 commit 400077e
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 111 deletions.
40 changes: 31 additions & 9 deletions components/BrowserPreview/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,38 @@ import {
ClasserProvider,
SandpackFiles,
SandpackCodeViewer,
SandpackThemeProp,
useSandpack,
} from '@codesandbox/sandpack-react'
import { useEffect } from 'react'

const BrowserPreview: React.FC<{
displayFiles?: boolean
dependencies?: Record<string, string>
files?: SandpackFiles
}> = ({ dependencies = {}, files, displayFiles = false }) => {
interface BrowserPreviewProps {
options: {
displayFiles?: boolean
dependencies?: Record<string, string>
files?: SandpackFiles
theme?: SandpackThemeProp
}
}

const Preview: React.FC<BrowserPreviewProps> = ({ options }) => {
const { displayFiles = false, theme = 'monokai-pro' } = options || {}
const { sandpack } = useSandpack()

useEffect(() => {
sandpack.openInCSBRegisteredRef.current = true
}, [])

return (
<SandpackLayout theme={theme}>
{displayFiles && <SandpackCodeViewer />}
<SandpackPreview showNavigator={true} showOpenInCodeSandbox={false} />
</SandpackLayout>
)
}

const BrowserPreview: React.FC<BrowserPreviewProps> = ({ options }) => {
const { dependencies = {}, files, displayFiles } = options || {}
return (
<>
<SandpackProvider
Expand All @@ -28,10 +53,7 @@ const BrowserPreview: React.FC<{
'sp-stack': 'custom-stack',
}}
>
<SandpackLayout theme="monokai-pro">
{displayFiles && <SandpackCodeViewer />}
<SandpackPreview showNavigator={true} showOpenInCodeSandbox={false} />
</SandpackLayout>
<Preview options={options} />
</ClasserProvider>
</SandpackProvider>
<style jsx global>{`
Expand Down
14 changes: 8 additions & 6 deletions components/CodeScreen/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -483,12 +483,14 @@ class Code extends React.Component<CodeProps, CodeScreenState> {
</div>
<div className="editor">
<BrowserPreview
files={{ '/App.js': { code: this.state.preview.code } }}
dependencies={{
...this.state.preview.dependencies,
...{
'prop-types': 'latest',
'styled-components': 'latest',
options={{
files: { '/App.js': { code: this.state.preview.code } },
dependencies: {
...this.state.preview.dependencies,
...{
'prop-types': 'latest',
'styled-components': 'latest',
},
},
}}
/>
Expand Down
43 changes: 43 additions & 0 deletions pages/embed.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { useEffect, useState } from 'react'
import { SandpackFiles } from '@codesandbox/sandpack-react'
import { generate } from '../utils/helper'
import BrowserPreview from '../components/BrowserPreview'

const Embed = () => {
const [files, setFiles] = useState<SandpackFiles>({})

const listener = async (event: MessageEvent) => {
const { data } = event
if (data?.type === 'teleport-render' && data?.uidl) {
const filesGenerated = await generate(data.uidl)
if (!filesGenerated) {
return
}
setFiles(filesGenerated)
}
}

useEffect(() => {
if (!window) {
return
}

window.addEventListener('message', listener)
return () => window.removeEventListener('message', listener)
}, [])

return (
<div className="preview">
<BrowserPreview
options={{ files, displayFiles: false, theme: 'codesandbox-light' }}
/>
<style jsx>{`
.preview {
height: calc(100vh - 15px);
}
`}</style>
</div>
)
}

export default Embed
60 changes: 2 additions & 58 deletions pages/project.tsx
Original file line number Diff line number Diff line change
@@ -1,72 +1,16 @@
import React, { useEffect, useState } from 'react'
import { GeneratedFolder } from '@teleporthq/teleport-types'
import { AppPage } from '../components/AppPage'
import dynamic from 'next/dynamic'
import projectJSON from '../inputs/project.json'
import { TopBar } from '../components/TopBar'
import { createReactProjectGenerator } from '@teleporthq/teleport-project-generator-react'
import { SandpackFiles } from '@codesandbox/sandpack-react'
import throttle from 'lodash.throttle'

/* Till this get's fixed.
Reference --> https://github.com/teleporthq/teleport-code-generators/issues/540 */
const fixPackageJSONForReact = (json: string) => {
const packageJSON = JSON.parse(json)
packageJSON.dependencies = {
...packageJSON.dependencies,
...{
react: '^17.0.0',
'react-dom': '^17.0.0',
'react-scripts': '^4.0.0',
'react-router-dom': '5.1.2',
},
}
return packageJSON
}
import { generate } from '../utils/helper'

const CodeEditor = dynamic(import('../components/CodeEditor'), {
ssr: false,
})
const BrowserPreview = dynamic(import('../components/BrowserPreview'))
const generator = createReactProjectGenerator()

const generate = async (uidl: Record<string, unknown>) => {
try {
const { files: filesFromFolder, subFolders } = await generator.generateProject(uidl)
const packageJSON = filesFromFolder.find(
(file) => file.name === 'package' && file.fileType === 'json'
)
if (!packageJSON) {
return
}
const mappedFiles = {
['/package.json']: {
code: JSON.stringify(fixPackageJSONForReact(packageJSON.content), null, 2),
active: true,
},
...mapFiles(subFolders, ''),
}
return mappedFiles
} catch (e) {
throw new Error(e)
}
}

const mapFiles = (folders: GeneratedFolder[], currentPath: string) => {
return folders.reduce((acc: SandpackFiles, folder) => {
const { files: subFiles, subFolders } = folder
subFiles.map(
(file) =>
(acc[`${currentPath}/${folder.name}/${file.name}.${file.fileType}`] = {
code: file.content,
})
)
if (subFolders.length > 0) {
acc = { ...acc, ...mapFiles(subFolders, `/${folder.name}`) }
}
return acc
}, {})
}

const ProjectPreview = () => {
const [files, setFiles] = useState<SandpackFiles>({})
Expand Down Expand Up @@ -99,7 +43,7 @@ const ProjectPreview = () => {
/>
</div>
<div className="right">
<BrowserPreview files={files} displayFiles={true} />
<BrowserPreview options={{ files, displayFiles: true }} />
</div>
</div>
<style jsx>
Expand Down
58 changes: 58 additions & 0 deletions utils/helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { GeneratedFolder } from '@teleporthq/teleport-types'
import { createReactProjectGenerator } from '@teleporthq/teleport-project-generator-react'
import { SandpackFiles } from '@codesandbox/sandpack-react'

/* Till this get's fixed.
Reference --> https://github.com/teleporthq/teleport-code-generators/issues/540 */
export const fixPackageJSONForReact = (json: string) => {
const packageJSON = JSON.parse(json)
packageJSON.dependencies = {
...packageJSON.dependencies,
...{
react: '^17.0.0',
'react-dom': '^17.0.0',
'react-scripts': '^4.0.0',
'react-router-dom': '5.1.2',
},
}
return packageJSON
}

export const generate = async (uidl: Record<string, unknown>) => {
try {
const generator = createReactProjectGenerator()
const { files: filesFromFolder, subFolders } = await generator.generateProject(uidl)
const packageJSON = filesFromFolder.find(
(file) => file.name === 'package' && file.fileType === 'json'
)
if (!packageJSON) {
return
}
const mappedFiles = {
['/package.json']: {
code: JSON.stringify(fixPackageJSONForReact(packageJSON.content), null, 2),
active: true,
},
...mapFiles(subFolders, ''),
}
return mappedFiles
} catch (e) {
throw new Error(e)
}
}

export const mapFiles = (folders: GeneratedFolder[], currentPath: string) => {
return folders.reduce((acc: SandpackFiles, folder) => {
const { files: subFiles, subFolders } = folder
subFiles.map(
(file) =>
(acc[`${currentPath}/${folder.name}/${file.name}.${file.fileType}`] = {
code: file.content,
})
)
if (subFolders.length > 0) {
acc = { ...acc, ...mapFiles(subFolders, `/${folder.name}`) }
}
return acc
}, {})
}
Loading

1 comment on commit 400077e

@vercel
Copy link

@vercel vercel bot commented on 400077e Mar 17, 2021

Choose a reason for hiding this comment

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

Please sign in to comment.