IDE redesign, initial implementation #362
17
app/web/src/components/EncodedUrl/FullScriptEncoding.tsx
Normal file
17
app/web/src/components/EncodedUrl/FullScriptEncoding.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import { makeEncodedLink } from './helpers'
|
||||
import { copyTextToClipboard } from 'src/helpers/clipboard'
|
||||
import {useIdeContext} from 'src/helpers/hooks/useIdeContext'
|
||||
|
||||
const FullScriptEncoding = () => {
|
||||
|
Irev-Dev
commented
Review

|
||||
const {state} = useIdeContext()
|
||||
const encodedLink = makeEncodedLink(state.code)
|
||||
return (
|
||||
<>
|
||||
<p className="text-sm pb-4 border-b border-gray-700">Encodes your CodeCad script into a URL so that you can share your work</p>
|
||||
<input value={encodedLink.replace(/^.+:\/\//g, '')} readOnly className="p-1 mt-4 text-xs rounded-t border border-gray-700 w-full" />
|
||||
<button className="w-full bg-gray-700 py-1 rounded-b text-gray-300" onClick={() => copyTextToClipboard(encodedLink)} >Copy URL</button>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default FullScriptEncoding
|
||||
67
app/web/src/components/EncodedUrl/helpers.ts
Normal file
67
app/web/src/components/EncodedUrl/helpers.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import { useEffect } from 'react'
|
||||
import { flow } from 'lodash/fp'
|
||||
|
||||
import {useIdeContext} from 'src/helpers/hooks/useIdeContext'
|
||||
import { useRender } from 'src/components/IdeWrapper/useRender'
|
||||
import {encode, decode} from 'src/helpers/compress'
|
||||
import { isBrowser } from '@redwoodjs/prerender/browserUtils'
|
||||
|
||||
const scriptKey = 'encoded_script'
|
||||
const scriptKeyV2 = 'encoded_script_v2'
|
||||
const fetchText = 'fetch_text_v1'
|
||||
|
||||
export function makeEncodedLink(code: string): string {
|
||||
const encodedScript = encode(code)
|
||||
return `${location.origin}${location.pathname}#${scriptKeyV2}=${encodedScript}`
|
||||
}
|
||||
|
||||
export const githubSafe = (url: string): string =>
|
||||
url.includes('github.com')
|
||||
? url
|
||||
.replace('github.com', 'raw.githubusercontent.com')
|
||||
.replace('/blob/', '/')
|
||||
: url
|
||||
|
||||
const prepareEncodedUrl = flow(decodeURIComponent, githubSafe)
|
||||
|
||||
export function useIdeInit(cadPackage: string) {
|
||||
const {thunkDispatch} = useIdeContext()
|
||||
const handleRender = useRender()
|
||||
useEffect(() => {
|
||||
thunkDispatch({
|
||||
type: 'initIde',
|
||||
payload: { cadPackage },
|
||||
})
|
||||
// load code from hash if it's there
|
||||
|
All of the logic in this hook I had in the I've also now rename All of the logic in this hook I had in the `IdeToolbarNew` because that was the main wrapping component that had the context provider, so it made sense to have init useEffects there. However since most of the logic relates to checking if there is something encoded in the URL, I thought it made sense to bundle the logic here with the rest of the encoded url code, and bring it into `IdeToolbarNew` as a custom hook.
I've also now rename `IdeToolbarNew` to `IdeWrapper`
|
||||
const triggerRender = () =>
|
||||
setTimeout(() => {
|
||||
// definitely a little hacky, timeout with no delay is just to push it into the next event loop.
|
||||
handleRender()
|
||||
})
|
||||
let hash
|
||||
if (isBrowser) {
|
||||
hash = window.location.hash
|
||||
}
|
||||
const [key, encodedScript] = hash.slice(1).split('=')
|
||||
if (key === scriptKey) {
|
||||
const script = atob(encodedScript)
|
||||
thunkDispatch({ type: 'updateCode', payload: script })
|
||||
triggerRender()
|
||||
} else if (key === scriptKeyV2) {
|
||||
const script = decode(encodedScript)
|
||||
thunkDispatch({ type: 'updateCode', payload: script })
|
||||
triggerRender()
|
||||
} else if (key === fetchText) {
|
||||
const url = prepareEncodedUrl(encodedScript)
|
||||
fetch(url).then((response) =>
|
||||
response.text().then((script) => {
|
||||
thunkDispatch({ type: 'updateCode', payload: script })
|
||||
triggerRender()
|
||||
})
|
||||
)
|
||||
} else {
|
||||
triggerRender()
|
||||
}
|
||||
window.location.hash = ''
|
||||
}, [cadPackage])
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Popover } from '@headlessui/react'
|
||||
import { Tab, Tabs, TabList, TabPanel } from 'react-tabs';
|
||||
import { copyTextToClipboard } from 'src/helpers/clipboard'
|
||||
import { encode } from 'src/helpers/compress'
|
||||
import FullScriptEncoding from 'src/components/EncodedUrl/FullScriptEncoding'
|
||||
|
||||
const TopButton = ({
|
||||
onClick,
|
||||
@@ -34,7 +33,6 @@ const IdeHeader = ({handleRender}: {handleRender: () => void}) => {
|
||||
|
||||
<Popover className="relative outline-none w-full h-full">
|
||||
{({open}) => {
|
||||
const encodedLink = makeEncodedLink('bing bong')
|
||||
return (
|
||||
<>
|
||||
<Popover.Button className="h-full w-full outline-none">
|
||||
@@ -46,12 +44,11 @@ const IdeHeader = ({handleRender}: {handleRender: () => void}) => {
|
||||
selectedTabClassName="bg-gray-200"
|
||||
>
|
||||
<TabPanel className="p-4">
|
||||
<p className="text-sm pb-4 border-b border-gray-700">Encodes your CodeCad script into a URL so that you can share your work</p>
|
||||
<input value={encodedLink.replace(/^.+:\/\//g, '')} readOnly className="p-1 mt-4 text-xs rounded-t border border-gray-700 w-full" />
|
||||
<button className="w-full bg-gray-700 py-1 rounded-b text-gray-300" onClick={() => copyTextToClipboard(encodedLink)} >Copy URL</button>
|
||||
<FullScriptEncoding />
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<h2 className="h-32">Any content 2</h2>
|
||||
<p>blah</p>
|
||||
<input onPaste={(e) => console.log(e)} />
|
||||
</TabPanel>
|
||||
|
||||
<TabList className="flex whitespace-nowrap text-gray-700 border-t border-gray-700">
|
||||
@@ -71,10 +68,3 @@ const IdeHeader = ({handleRender}: {handleRender: () => void}) => {
|
||||
}
|
||||
|
||||
export default IdeHeader
|
||||
|
||||
const scriptKeyV2 = 'encoded_script_v2' // todo don't leave here
|
||||
|
||||
function makeEncodedLink(code: string): string {
|
||||
const encodedScript = encode(code)
|
||||
return `${location.href}#${scriptKeyV2}=${encodedScript}`
|
||||
}
|
||||
|
||||
@@ -1,68 +1,16 @@
|
||||
import { useContext, useEffect, useState } from 'react'
|
||||
import IdeContainer from 'src/components/IdeContainer'
|
||||
import { IdeContext } from 'src/pages/DevIdePage/DevIdePage'
|
||||
import { isBrowser } from '@redwoodjs/prerender/browserUtils'
|
||||
import { useState } from 'react'
|
||||
import IdeContainer from 'src/components/IdeContainer/IdeContainer'
|
||||
import { useRender } from './useRender'
|
||||
import { decode } from 'src/helpers/compress'
|
||||
import { flow } from 'lodash/fp'
|
||||
import OutBound from 'src/components/OutBound'
|
||||
import IdeSideBar from 'src/components/IdeSideBar'
|
||||
import IdeHeader from 'src/components/IdeHeader'
|
||||
import Svg from 'src/components/Svg'
|
||||
|
||||
export const githubSafe = (url) =>
|
||||
url.includes('github.com')
|
||||
? url
|
||||
.replace('github.com', 'raw.githubusercontent.com')
|
||||
.replace('/blob/', '/')
|
||||
: url
|
||||
|
||||
const prepareEncodedUrl = flow(decodeURIComponent, githubSafe)
|
||||
import OutBound from 'src/components/OutBound/OutBound'
|
||||
import IdeSideBar from 'src/components/IdeSideBar/IdeSideBar'
|
||||
import IdeHeader from 'src/components/IdeHeader/IdeHeader'
|
||||
import Svg from 'src/components/Svg/Svg'
|
||||
import { useIdeInit } from 'src/components/EncodedUrl/helpers'
|
||||
|
||||
const IdeToolbarNew = ({ cadPackage }) => {
|
||||
const { state, thunkDispatch } = useContext(IdeContext)
|
||||
const [shouldShowConstructionMessage, setShouldShowConstructionMessage] = useState(true)
|
||||
const handleRender = useRender()
|
||||
const scriptKey = 'encoded_script'
|
||||
const scriptKeyV2 = 'encoded_script_v2'
|
||||
const fetchText = 'fetch_text_v1'
|
||||
useEffect(() => {
|
||||
thunkDispatch({
|
||||
type: 'initIde',
|
||||
payload: { cadPackage },
|
||||
})
|
||||
// load code from hash if it's there
|
||||
const triggerRender = () =>
|
||||
setTimeout(() => {
|
||||
// definitely a little hacky, timeout with no delay is just to push it into the next event loop.
|
||||
handleRender()
|
||||
})
|
||||
let hash
|
||||
if (isBrowser) {
|
||||
hash = window.location.hash
|
||||
}
|
||||
const [key, encodedScript] = hash.slice(1).split('=')
|
||||
if (key === scriptKey) {
|
||||
const script = atob(encodedScript)
|
||||
thunkDispatch({ type: 'updateCode', payload: script })
|
||||
triggerRender()
|
||||
} else if (key === scriptKeyV2) {
|
||||
const script = decode(encodedScript)
|
||||
thunkDispatch({ type: 'updateCode', payload: script })
|
||||
triggerRender()
|
||||
} else if (key === fetchText) {
|
||||
const url = prepareEncodedUrl(encodedScript)
|
||||
fetch(url).then((response) =>
|
||||
response.text().then((script) => {
|
||||
thunkDispatch({ type: 'updateCode', payload: script })
|
||||
triggerRender()
|
||||
})
|
||||
)
|
||||
} else {
|
||||
triggerRender()
|
||||
}
|
||||
window.location.hash = ''
|
||||
}, [cadPackage])
|
||||
useIdeInit(cadPackage)
|
||||
|
||||
return (
|
||||
<div className="h-full flex">
|
||||
|
||||
6
app/web/src/helpers/hooks/useIdeContext.ts
Normal file
6
app/web/src/helpers/hooks/useIdeContext.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { IdeContext } from 'src/pages/DevIdePage/DevIdePage'
|
||||
import { useContext } from 'react'
|
||||
|
||||
export function useIdeContext() {
|
||||
return useContext(IdeContext)
|
||||
}
|
||||
Reference in New Issue
Block a user
