Browse Source

[Beta] Add console to sandboxes (#4672)

* added code for sandpack console

* add log

* added console for older bundle

* Revert "[beta] Sandpack - new bundler (#4458)"

This reverts commit 3ab1245314.

* adds proper console and removes new bundle

* modify styles

* remove unwanted code

* nit

* fix types (#4677)

* update console

* little nits

* remove unwanted code changes

* update bundler URL

* use `message.firstLoad` for clearing console

* use `refresh` event to clear logs as well (used when going away and coming back to sandpack)

* remove padding for code blocks inside console

* small UI revamps

* change p to div since the sandpack comes inside the p, add try catch and a try catch for the catch again

* tweaks

* Fixes

* Reset unrelated changes

* tweaks

* fix

* fixes

* oops

* Fix

* fix

Co-authored-by: Danilo Woznica <danilowoz@gmail.com>
Co-authored-by: Dan Abramov <dan.abramov@gmail.com>
main
Strek 3 years ago
committed by GitHub
parent
commit
6d965422a4
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 154
      beta/src/components/MDX/Sandpack/Console.tsx
  2. 2
      beta/src/components/MDX/Sandpack/Preview.tsx
  3. 7
      beta/src/styles/sandpack.css

154
beta/src/components/MDX/Sandpack/Console.tsx

@ -0,0 +1,154 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*/
import cn from 'classnames';
import * as React from 'react';
import {IconChevron} from 'components/Icon/IconChevron';
import {SandpackCodeViewer, useSandpack} from '@codesandbox/sandpack-react';
import type {SandpackMessageConsoleMethods} from '@codesandbox/sandpack-client';
const getType = (
message: SandpackMessageConsoleMethods
): 'info' | 'warning' | 'error' => {
if (message === 'log' || message === 'info') {
return 'info';
}
if (message === 'warn') {
return 'warning';
}
return 'error';
};
type ConsoleData = Array<{
data: Array<string | Record<string, string>>;
id: string;
method: SandpackMessageConsoleMethods;
}>;
const MAX_MESSAGE_COUNT = 100;
export const SandpackConsole = () => {
const {listen} = useSandpack();
const [logs, setLogs] = React.useState<ConsoleData>([]);
const wrapperRef = React.useRef<HTMLDivElement>(null);
React.useEffect(() => {
const unsubscribe = listen((message) => {
if (
(message.type === 'start' && message.firstLoad) ||
message.type === 'refresh'
) {
setLogs([]);
}
if (message.type === 'console' && message.codesandbox) {
setLogs((prev) => {
const messages = [...prev, ...message.log];
messages.slice(Math.max(0, messages.length - MAX_MESSAGE_COUNT));
return messages.filter(({method}) => method === 'log');
});
}
});
return unsubscribe;
}, [listen]);
const [isExpanded, setIsExpanded] = React.useState(false);
React.useEffect(() => {
if (wrapperRef.current) {
wrapperRef.current.scrollTop = wrapperRef.current.scrollHeight;
}
}, [logs]);
if (logs.length === 0) {
return null;
}
return (
<div className="absolute dark:border-gray-700 bg-white dark:bg-gray-95 border-t bottom-0 w-full dark:text-white">
<div className="flex justify-between">
<button
className="flex items-center p-1"
onClick={() => setIsExpanded(!isExpanded)}>
<IconChevron displayDirection={isExpanded ? 'down' : 'right'} />
<span className="pl-1 text-sm">Console ({logs.length})</span>
</button>
<button
className="p-1"
onClick={() => {
setLogs([]);
setIsExpanded(false);
}}>
<svg
viewBox="0 0 24 24"
width="18"
height="18"
stroke="currentColor"
strokeWidth="2"
fill="none"
strokeLinecap="round"
strokeLinejoin="round">
<circle cx="12" cy="12" r="10"></circle>
<line x1="4.93" y1="4.93" x2="19.07" y2="19.07"></line>
</svg>
</button>
</div>
{isExpanded && (
<div className="w-full h-full border-y bg-white dark:border-gray-700 dark:bg-gray-95 min-h-[28px] console">
<div className="max-h-52 h-auto overflow-auto" ref={wrapperRef}>
{logs.map(({data, id, method}) => {
return (
<div
key={id}
className={cn(
'last:border-none border-b dark:border-gray-700 text-md p-1 pl-2 leading-6 font-mono',
`console-${getType(method)}`
)}>
<span className={cn('console-message')}>
{data.map((msg, index) => {
if (typeof msg === 'string') {
return <span key={`${msg}-${index}`}>{msg}</span>;
}
let children;
if (msg != null && typeof msg['@t'] === 'string') {
// CodeSandbox wraps custom types
children = msg['@t'];
} else {
try {
children = JSON.stringify(msg, null, 2);
} catch (error) {
try {
children = Object.prototype.toString.call(msg);
} catch (err) {
children = '[' + typeof msg + ']';
}
}
}
return (
<span
className={cn('console-span')}
key={`${msg}-${index}`}>
<SandpackCodeViewer
initMode="user-visible"
// fileType="js"
code={children}
/>
</span>
);
})}
</span>
</div>
);
})}
</div>
</div>
)}
</div>
);
};

2
beta/src/components/MDX/Sandpack/Preview.tsx

@ -7,6 +7,7 @@ import * as React from 'react';
import {useSandpack, LoadingOverlay} from '@codesandbox/sandpack-react';
import cn from 'classnames';
import {Error} from './Error';
import {SandpackConsole} from './Console';
import type {LintDiagnostic} from './useSandpackLint';
const generateRandomId = (): string =>
@ -209,6 +210,7 @@ export function Preview({
loading={!isReady && iframeComputedHeight === null}
/>
</div>
<SandpackConsole />
</div>
);
}

7
beta/src/styles/sandpack.css

@ -154,6 +154,13 @@ html.dark .sp-code-editor .cm-diagnostic {
overflow: auto !important;
padding: 18px 0 !important;
}
.console .sp-cm,
.console .sp-cm .cm-scroller,
.console .sp-cm .cm-line {
padding: 0px !important;
}
.sp-cm .cm-gutters {
background-color: var(--sp-colors-bg-default);
z-index: 1;

Loading…
Cancel
Save