From 80992ce4a3b1a7f13ef7a0130efb61ad7ebc8b8a Mon Sep 17 00:00:00 2001 From: Naman Goel Date: Sat, 4 Jan 2025 00:06:00 +0300 Subject: [PATCH] docs: Better mobile design for the playground. Initial implementation complete --- apps/docs/components/LoadingSpinner.js | 46 +++ apps/docs/components/Playground.js | 348 +++++++++++++----- .../docs/components/playground-utils/files.js | 7 +- apps/docs/src/pages/playground.js | 61 +++ 4 files changed, 365 insertions(+), 97 deletions(-) create mode 100644 apps/docs/components/LoadingSpinner.js diff --git a/apps/docs/components/LoadingSpinner.js b/apps/docs/components/LoadingSpinner.js new file mode 100644 index 00000000..264b6262 --- /dev/null +++ b/apps/docs/components/LoadingSpinner.js @@ -0,0 +1,46 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * + */ + +import * as React from 'react'; +import * as stylex from '@stylexjs/stylex'; + +const spin = stylex.keyframes({ + '0%': { transform: 'rotate(0deg)' }, + '100%': { transform: 'rotate(360deg)' }, +}); + +const styles = stylex.create({ + spinner: { + width: 40, + height: 40, + borderWidth: 4, + borderStyle: 'solid', + borderColor: 'var(--ifm-color-emphasis-200)', + borderTopColor: 'var(--ifm-color-primary)', + borderRadius: '50%', + animationName: spin, + animationDuration: '1s', + animationIterationCount: 'infinite', + animationTimingFunction: 'linear', + }, + container: { + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + minHeight: 200, + }, +}); + +export default function LoadingSpinner() { + return ( +
+
+
+ ); +} diff --git a/apps/docs/components/Playground.js b/apps/docs/components/Playground.js index b6ffd58f..7d7b75f9 100644 --- a/apps/docs/components/Playground.js +++ b/apps/docs/components/Playground.js @@ -20,6 +20,7 @@ import { UnControlled as CodeMirror } from 'react-codemirror2'; import 'codemirror/mode/javascript/javascript'; import { files } from './playground-utils/files'; import useDebounced from './hooks/useDebounced'; +import LoadingSpinner from './LoadingSpinner'; // Add FontAwesome icons to the library library.add(faBars, faRotateRight); @@ -55,17 +56,17 @@ async function wcSpawn(instance, ...args) { * @returns {Promise} - Promise that resolves with the configured WebContainer instance. */ async function makeWebcontainer() { - console.log('Booting WebContainer...'); + // console.log('Booting WebContainer...'); const instance = await WebContainer.boot(); - console.log('Boot successful!'); + // console.log('Boot successful!'); - console.log('Mounting files...'); + // console.log('Mounting files...'); await instance.mount(files); - console.log('Mounted files!'); + // console.log('Mounted files!'); - console.log('Installing dependencies...'); + // console.log('Installing dependencies...'); await wcSpawn(instance, 'npm', ['install']); - console.log('Installed dependencies!'); + // console.log('Installed dependencies!'); return instance; } @@ -83,36 +84,7 @@ export default function Playground() { const [error, setError] = useState(null); const urlRef = useRef(null); - /** - * Function to build the WebContainer and start the development server. - */ - const build = async () => { - const containerInstance = instance.current; - if (!containerInstance) { - console.log('error due to failed instance'); - setError( - 'WebContainer failed to load. Please try reloading or use a different browser.', - ); - return; - } - - console.log('Trying to run `npm run dev`...'); - const process = await containerInstance.spawn('npm', ['run', 'dev']); - console.log('Spawned `npm run dev`...'); - process.output.pipeTo( - new WritableStream({ - write(data) { - console.log(data); - }, - }), - ); - console.log('Waiting for server-ready event...'); - containerInstance.on('server-ready', (port, url) => { - console.log('server-ready', port, url); - setUrl(url); - urlRef.current = url; - }); - }; + const [activePanel, setActivePanel] = useState('code'); /** * Function to update files in the WebContainer. @@ -159,20 +131,41 @@ export default function Playground() { // useEffect to initialize the WebContainer and build it useEffect(() => { let loadingTimeout; - makeWebcontainer().then((i) => { - instance.current = i; - build().then(() => { - loadingTimeout = setTimeout(() => { - if (!urlRef.current) { - console.log('error due to timeout...'); - setError( - 'WebContainer failed to load. Please try reloading or use a different browser.', - ); - } - loadingTimeout = null; - }, 10000); + + /** + * Function to build the WebContainer and start the development server. + */ + async function build() { + const containerInstance = await makeWebcontainer(); + + if (!containerInstance) { + console.log('error due to failed instance'); + setError( + 'WebContainer failed to load. Please try reloading or use a different browser.', + ); + return; + } + instance.current = containerInstance; + + // console.log('Trying to run `npm run dev`...'); + const process = await containerInstance.spawn('npm', ['run', 'dev']); + // console.log('Spawned `npm run dev`...'); + process.output.pipeTo( + new WritableStream({ + write(data) { + console.log(data); + }, + }), + ); + // console.log('Waiting for server-ready event...'); + containerInstance.on('server-ready', (port, url) => { + console.log('server-ready', port, url); + setUrl(url); + urlRef.current = url; }); - }); + } + + build(); // Cleanup function to unmount the WebContainer and clear timeouts return () => { @@ -186,26 +179,76 @@ export default function Playground() { // Render the Playground component return (
-
- {/* */} - -
+
+
+
+ + Experimental playground - Try a{' '} + + full example app + + +
+
+ + + + )} + +
+
+ +
+
+
{() => ( <> handleCodeChange(newCode)} options={{ mode: 'javascript', @@ -215,14 +258,32 @@ export default function Playground() { value={code} /> {error ? ( -
+
{error}
) : url ? ( -