From 5083d8e7f8100a0a570ddd01b746229f77ef321c Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Sun, 13 Jun 2021 17:08:37 +1000 Subject: [PATCH] Add external resource flow related to #360 --- .../components/EncodedUrl/ExternalScript.tsx | 131 ++++++++++++++++++ .../EncodedUrl/FullScriptEncoding.tsx | 4 +- app/web/src/components/EncodedUrl/helpers.ts | 20 ++- .../src/components/IdeHeader/IdeHeader.tsx | 6 +- 4 files changed, 150 insertions(+), 11 deletions(-) create mode 100644 app/web/src/components/EncodedUrl/ExternalScript.tsx diff --git a/app/web/src/components/EncodedUrl/ExternalScript.tsx b/app/web/src/components/EncodedUrl/ExternalScript.tsx new file mode 100644 index 0000000..510b4ce --- /dev/null +++ b/app/web/src/components/EncodedUrl/ExternalScript.tsx @@ -0,0 +1,131 @@ +import { useState } from 'react' +import { useIdeContext } from 'src/helpers/hooks/useIdeContext' +import OutBound from 'src/components/OutBound/OutBound' +import { prepareEncodedUrl, makeExternalUrl } from './helpers' +import { copyTextToClipboard } from 'src/helpers/clipboard' +import { useRender } from 'src/components/IdeWrapper/useRender' +import { toast } from '@redwoodjs/web/toast' + +const ideTypeNameMap = { + openScad: 'OpenSCAD', + cadQuery: 'CadQuery', +} + +const ExternalScript = () => { + const { state, thunkDispatch } = useIdeContext() + const handleRender = useRender() + const [rawUrl, setRawUrl] = useState('') + const [script, setScript] = useState('') + const [asyncState, setAsyncState] = + useState<'INIT' | 'SUCCESS' | 'ERROR' | 'LOADING'>('INIT') + + const cadName = ideTypeNameMap[state.ideType] + + const onPaste: React.ClipboardEventHandler = async ({ + clipboardData, + }) => { + const url = clipboardData.getData('Text') + processUserUrl(url) + } + const onChange: React.ChangeEventHandler = async ({ + target, + }) => setRawUrl(target.value) + const onKeyDown = async ({ key, target }) => + key === 'Enter' && processUserUrl(target.value) + + async function processUserUrl(url: string) { + setRawUrl(url) + try { + setAsyncState('LOADING') + const response = await fetch(prepareEncodedUrl(url)) + if (response.status === 404) throw new Error("couldn't find script") + const script2 = await response.text() + if (script2.startsWith('')) + throw new Error('got html document, not a script') + setScript(script2) + setAsyncState('SUCCESS') + } catch (e) { + setAsyncState('ERROR') + toast.error( + "We had trouble with you're URL, are you sure it was correct?" + ) + } + } + const onCopyRender: React.MouseEventHandler = () => { + copyTextToClipboard(makeExternalUrl(rawUrl)) + thunkDispatch({ type: 'updateCode', payload: script }) + setTimeout(handleRender) + } + return ( +
+

+ Paste an external url containing a {cadName} script to generate a new + CadHub url for this resource.{' '} + + Learn more + {' '} + about this feature. +

+ {['INIT', 'ERROR'].includes(asyncState) && ( + <> +

Paste url

+ + + )} + {asyncState === 'ERROR' && ( +

That didn't work, try again.

+ )} + {asyncState === 'LOADING' && ( +
+
+
+
+
+ )} + {asyncState === 'SUCCESS' && ( + <> + + +
+ + +
+ + )} +
+ ) +} + +export default ExternalScript diff --git a/app/web/src/components/EncodedUrl/FullScriptEncoding.tsx b/app/web/src/components/EncodedUrl/FullScriptEncoding.tsx index e4c7eda..32687b5 100644 --- a/app/web/src/components/EncodedUrl/FullScriptEncoding.tsx +++ b/app/web/src/components/EncodedUrl/FullScriptEncoding.tsx @@ -6,7 +6,7 @@ const FullScriptEncoding = () => { const { state } = useIdeContext() const encodedLink = makeEncodedLink(state.code) return ( - <> +

Encodes your CodeCad script into a URL so that you can share your work

@@ -21,7 +21,7 @@ const FullScriptEncoding = () => { > Copy URL - +
) } diff --git a/app/web/src/components/EncodedUrl/helpers.ts b/app/web/src/components/EncodedUrl/helpers.ts index e94fd4c..ff23f13 100644 --- a/app/web/src/components/EncodedUrl/helpers.ts +++ b/app/web/src/components/EncodedUrl/helpers.ts @@ -10,11 +10,6 @@ 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 @@ -22,7 +17,20 @@ export const githubSafe = (url: string): string => .replace('/blob/', '/') : url -const prepareEncodedUrl = flow(decodeURIComponent, githubSafe) +export const prepareEncodedUrl = flow(decodeURIComponent, githubSafe) + +const prepareDecodedUrl = flow(githubSafe, encodeURIComponent) + +export function makeEncodedLink(code: string): string { + const encodedScript = encode(code) + return `${location.origin}${location.pathname}#${scriptKeyV2}=${encodedScript}` +} + +export function makeExternalUrl(resourceUrl: string): string { + return `${location.origin}${ + location.pathname + }#${fetchText}=${prepareDecodedUrl(resourceUrl)}` +} export function useIdeInit(cadPackage: string) { const { thunkDispatch } = useIdeContext() diff --git a/app/web/src/components/IdeHeader/IdeHeader.tsx b/app/web/src/components/IdeHeader/IdeHeader.tsx index 68fee3c..5368d31 100644 --- a/app/web/src/components/IdeHeader/IdeHeader.tsx +++ b/app/web/src/components/IdeHeader/IdeHeader.tsx @@ -1,6 +1,7 @@ import { Popover } from '@headlessui/react' import { Tab, Tabs, TabList, TabPanel } from 'react-tabs' import FullScriptEncoding from 'src/components/EncodedUrl/FullScriptEncoding' +import ExternalScript from 'src/components/EncodedUrl/ExternalScript' const TopButton = ({ onClick, @@ -50,12 +51,11 @@ const IdeHeader = ({ handleRender }: { handleRender: () => void }) => { className="bg-gray-300 rounded-md shadow-md overflow-hidden text-gray-700" selectedTabClassName="bg-gray-200" > - + -

blah

- console.log(e)} /> +