-
-
Notifications
You must be signed in to change notification settings - Fork 507
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor: Clean up a bit post #1155 & #1150 #1157
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
import { useRoute } from 'preact-iso'; | ||
import { useLocation, useRoute } from 'preact-iso'; | ||
import { Repl } from './repl'; | ||
import { useExample } from './repl/examples'; | ||
import { fetchExample } from './repl/examples'; | ||
import { useContent, useResource } from '../../lib/use-resource'; | ||
import { useTitle, useDescription } from './utils'; | ||
import { useLanguage } from '../../lib/i18n'; | ||
|
@@ -15,7 +15,7 @@ export default function ReplPage() { | |
useTitle(meta.title); | ||
useDescription(meta.description); | ||
|
||
const [code, slug] = initialCode(query); | ||
const code = useResource(() => getInitialCode(query), [query]); | ||
|
||
return ( | ||
<div class={style.repl}> | ||
|
@@ -24,11 +24,8 @@ export default function ReplPage() { | |
height: 100% !important; | ||
overflow: hidden !important; | ||
} | ||
footer { | ||
display: none !important; | ||
} | ||
Comment on lines
-27
to
-29
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No footer on the REPL of course -- I had just copy/pasted this CSS, it's not relevant anymore. |
||
`}</style> | ||
<Repl code={code} slug={slug} /> | ||
<Repl code={code} /> | ||
</div> | ||
); | ||
} | ||
|
@@ -38,42 +35,31 @@ export default function ReplPage() { | |
* | ||
* ?code -> ?example -> localStorage -> simple counter example | ||
*/ | ||
function initialCode(query) { | ||
let code, slug; | ||
async function getInitialCode(query) { | ||
const { route } = useLocation(); | ||
Comment on lines
-41
to
+39
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Admittedly this block was a bit of a mess that I should have given a better look over. Fixes an issue with This still isn't great, |
||
let code; | ||
if (query.code) { | ||
try { | ||
code = useResource(() => querySafetyCheck(atob(query.code)), [query.code]); | ||
} catch (e) {} | ||
code = querySafetyCheck(atob(query.code)); | ||
} else if (query.example) { | ||
code = useExample([query.example]); | ||
if (code) { | ||
slug = query.example; | ||
history.replaceState( | ||
null, | ||
null, | ||
`/repl?example=${encodeURIComponent(slug)}` | ||
); | ||
code = await fetchExample(query.example); | ||
if (!code) { | ||
route('/repl', true); | ||
} | ||
else history.replaceState(null, null, '/repl'); | ||
} | ||
|
||
if (!code) { | ||
if (typeof window !== 'undefined' && localStorage.getItem('preact-www-repl-code')) { | ||
code = localStorage.getItem('preact-www-repl-code'); | ||
} else { | ||
slug = 'counter'; | ||
const slug = 'counter'; | ||
if (typeof window !== 'undefined') { | ||
history.replaceState( | ||
null, | ||
null, | ||
`/repl?example=${encodeURIComponent(slug)}` | ||
); | ||
route(`/repl?example=${encodeURIComponent(slug)}`, true); | ||
} | ||
code = useExample([slug]); | ||
code = await fetchExample(slug); | ||
} | ||
} | ||
|
||
return [code, slug]; | ||
return code; | ||
} | ||
|
||
async function querySafetyCheck(code) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
import { useState, useEffect } from 'preact/hooks'; | ||
import { useLocation, useRoute } from 'preact-iso'; | ||
import { Splitter } from '../../splitter'; | ||
import { EXAMPLES, getExample, loadExample } from './examples'; | ||
import { EXAMPLES, fetchExample } from './examples'; | ||
import { ErrorOverlay } from './error-overlay'; | ||
import { useStoredValue } from '../../../lib/localstorage'; | ||
import { useResource } from '../../../lib/use-resource'; | ||
|
@@ -13,55 +14,51 @@ import REPL_CSS from './examples.css?raw'; | |
* @param {string} props.code | ||
* @param {string} [props.slug] | ||
*/ | ||
export function Repl({ code, slug }) { | ||
export function Repl({ code }) { | ||
const { route } = useLocation(); | ||
const { query } = useRoute(); | ||
const [editorCode, setEditorCode] = useStoredValue('preact-www-repl-code', code); | ||
const [exampleSlug, setExampleSlug] = useState(slug || ''); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Most of the slug changes here are, again, due to me trying to run around |
||
const [error, setError] = useState(null); | ||
const [copied, setCopied] = useState(false); | ||
|
||
// TODO: CodeMirror v5 cannot load in Node, and loading only the runner | ||
// causes some bad jumping/pop-in. For the moment, this is the best option | ||
if (typeof window === 'undefined') return null; | ||
|
||
/** | ||
* @type {{ Runner: import('../repl/runner').default, CodeEditor: import('../../code-editor').default }} | ||
*/ | ||
const { Runner, CodeEditor } = useResource(() => Promise.all([ | ||
import('../../code-editor'), | ||
import('./runner') | ||
]).then(([CodeEditor, Runner]) => ({ CodeEditor: CodeEditor.default, Runner: Runner.default })), ['repl']); | ||
|
||
const applyExample = (e) => { | ||
const slug = e.target.value; | ||
loadExample(getExample(slug).url) | ||
fetchExample(slug) | ||
.then(code => { | ||
setEditorCode(code); | ||
setExampleSlug(slug); | ||
history.replaceState( | ||
null, | ||
null, | ||
`/repl?example=${encodeURIComponent(slug)}` | ||
); | ||
route(`/repl?example=${encodeURIComponent(slug)}`, true); | ||
}); | ||
}; | ||
|
||
useEffect(() => { | ||
const example = getExample(exampleSlug); | ||
(async function () { | ||
if (example) { | ||
const code = await loadExample(example.url); | ||
if (location.search && code !== editorCode) { | ||
setExampleSlug(''); | ||
history.replaceState(null, null, '/repl'); | ||
} | ||
} | ||
})(); | ||
}, [editorCode]); | ||
const onEditorInput = (code) => { | ||
setEditorCode(code); | ||
|
||
// Clears the (now outdated) example & code query params | ||
// when a user begins to modify the code | ||
if (location.search) { | ||
route('/repl', true); | ||
} | ||
}; | ||
|
||
const share = () => { | ||
if (!exampleSlug) { | ||
history.replaceState( | ||
null, | ||
null, | ||
`/repl?code=${encodeURIComponent(btoa(editorCode))}` | ||
); | ||
// No reason to share semi-sketchy btoa'd code if there's | ||
// a perfectly good example we can use instead | ||
if (!query.example) { | ||
// We use `history.replaceState` here as the code is only relevant on mount. | ||
// There's no need to notify the router of the change. | ||
history.replaceState(null, null, `/repl?code=${encodeURIComponent(btoa(editorCode))}`); | ||
} | ||
|
||
try { | ||
|
@@ -90,13 +87,13 @@ export function Repl({ code, slug }) { | |
<header class={style.toolbar}> | ||
<label> | ||
Examples:{' '} | ||
<select value={exampleSlug} onChange={applyExample}> | ||
<select value={query.example || ''} onChange={applyExample}> | ||
<option value="" disabled> | ||
Select Example... | ||
</option> | ||
{EXAMPLES.map(function item(ex) { | ||
const selected = | ||
ex.slug !== undefined && ex.slug === exampleSlug; | ||
ex.slug !== undefined && ex.slug === query.example; | ||
return ex.group ? ( | ||
<optgroup label={ex.group}>{ex.items.map(item)}</optgroup> | ||
) : ( | ||
|
@@ -137,7 +134,7 @@ export function Repl({ code, slug }) { | |
class={style.code} | ||
value={editorCode} | ||
error={error} | ||
onInput={setEditorCode} | ||
onInput={onEditorInput} | ||
/> | ||
</Splitter> | ||
</div> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -62,6 +62,9 @@ export function Tutorial({ html, meta }) { | |
// causes some bad jumping/pop-in. For the moment, this is the best option | ||
if (typeof window === 'undefined') return null; | ||
|
||
/** | ||
* @type {{ Runner: import('../repl/runner').default, CodeEditor: import('../../code-editor').default }} | ||
*/ | ||
const { Runner, CodeEditor } = useResource(() => Promise.all([ | ||
import('../../code-editor'), | ||
import('../repl/runner') | ||
|
@@ -73,7 +76,7 @@ export function Tutorial({ html, meta }) { | |
solutionCtx.setSolved(false); | ||
content.current.scrollTo(0, 0); | ||
} | ||
}, [html]); | ||
}, [meta.tutorial?.initial]); | ||
|
||
|
||
const useResult = fn => { | ||
|
@@ -140,42 +143,38 @@ export function Tutorial({ html, meta }) { | |
orientation="horizontal" | ||
force={!showCode ? '100%' : undefined} | ||
other={ | ||
// TODO: CodeMirror v5 cannot load in Node, and loading only the runner | ||
// causes some bad jumping/pop-in. For the moment, this is the best option | ||
typeof window === 'undefined' | ||
? null | ||
: <Splitter | ||
Comment on lines
-143
to
-147
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is already a Evidently I forgot to clean it up. |
||
orientation="vertical" | ||
other={ | ||
<> | ||
<div class={style.output}> | ||
{error && ( | ||
<ErrorOverlay | ||
name={error.name} | ||
message={error.message} | ||
stack={parseStackTrace(error)} | ||
/> | ||
)} | ||
<Runner | ||
ref={runner} | ||
onSuccess={onSuccess} | ||
onRealm={onRealm} | ||
onError={onError} | ||
code={editorCode} | ||
/> | ||
</div> | ||
{hasCode && ( | ||
<button | ||
class={style.toggleCode} | ||
title="Toggle Code" | ||
onClick={toggleCode} | ||
> | ||
<span>Toggle Code</span> | ||
</button> | ||
)} | ||
</> | ||
} | ||
> | ||
<Splitter | ||
orientation="vertical" | ||
other={ | ||
<> | ||
<div class={style.output}> | ||
{error && ( | ||
<ErrorOverlay | ||
name={error.name} | ||
message={error.message} | ||
stack={parseStackTrace(error)} | ||
/> | ||
)} | ||
<Runner | ||
ref={runner} | ||
onSuccess={onSuccess} | ||
onRealm={onRealm} | ||
onError={onError} | ||
code={editorCode} | ||
/> | ||
</div> | ||
{hasCode && ( | ||
<button | ||
class={style.toggleCode} | ||
title="Toggle Code" | ||
onClick={toggleCode} | ||
> | ||
<span>Toggle Code</span> | ||
</button> | ||
)} | ||
</> | ||
} | ||
> | ||
<div class={style.codeWindow}> | ||
<CodeEditor | ||
class={style.code} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is anyone against this getting silence? Granted, many of them are my fault, but we have dozens of warnings that I don't think are important to anyone these days?