Skip to content

Commit

Permalink
support resizing console
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremyphilemon committed Dec 12, 2024
1 parent 5090fa4 commit 8a1e933
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 182 deletions.
27 changes: 19 additions & 8 deletions components/block-actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,14 @@ import { Tooltip, TooltipContent, TooltipTrigger } from './ui/tooltip';
import { useCopyToClipboard } from 'usehooks-ts';
import { toast } from 'sonner';
import { ConsoleOutput, UIBlock } from './block';
import { Dispatch, memo, SetStateAction, useCallback, useState } from 'react';
import {
Dispatch,
memo,
SetStateAction,
startTransition,
useCallback,
useState,
} from 'react';

interface BlockActionsProps {
block: UIBlock;
Expand Down Expand Up @@ -73,19 +80,21 @@ export function RunCodeButton({
}

try {
await currentPyodideInstance.runPythonAsync(`
setTimeout(async () => {
await currentPyodideInstance.runPythonAsync(`
import sys
import io
sys.stdout = io.StringIO()
`);

await currentPyodideInstance.runPythonAsync(codeContent);
await currentPyodideInstance.runPythonAsync(codeContent);

const output: string = await currentPyodideInstance.runPythonAsync(
`sys.stdout.getvalue()`,
);
const output: string = await currentPyodideInstance.runPythonAsync(
`sys.stdout.getvalue()`,
);

updateConsoleOutput(runId, output, 'completed');
updateConsoleOutput(runId, output, 'completed');
}, 1000);
} catch (error: any) {
updateConsoleOutput(runId, error.message, 'failed');
}
Expand All @@ -97,7 +106,9 @@ export function RunCodeButton({
variant="outline"
className="py-1.5 px-2 h-fit dark:hover:bg-zinc-700"
onClick={() => {
loadAndRunPython();
startTransition(() => {
loadAndRunPython();
});
}}
disabled={block.status === 'streaming'}
>
Expand Down
132 changes: 90 additions & 42 deletions components/console.tsx
Original file line number Diff line number Diff line change
@@ -1,56 +1,104 @@
import { motion } from 'framer-motion';
import { TerminalIcon, CrossIcon, LoaderIcon } from './icons';
import { Button } from './ui/button';
import { Dispatch, SetStateAction } from 'react';
import {
Dispatch,
SetStateAction,
useCallback,
useEffect,
useState,
} from 'react';
import { ConsoleOutput } from './block';
import { cn } from '@/lib/utils';

interface ConsoleProps {
consoleOutputs: Array<ConsoleOutput>;
setConsoleOutputs: Dispatch<SetStateAction<Array<ConsoleOutput>>>;
}

export function Console({ consoleOutputs, setConsoleOutputs }: ConsoleProps) {
return (
consoleOutputs.length > 0 && (
<motion.div
className="absolute flex flex-col bottom-0 bg-zinc-900 h-56 w-full border-t z-50 overflow-y-scroll border-zinc-700"
initial={{ y: 224 }}
animate={{ y: 0 }}
exit={{ y: 224 }}
transition={{ type: 'spring', stiffness: 140, damping: 20 }}
>
<div className="flex flex-row justify-between items-center w-full h-fit border-b border-zinc-700 p-2 sticky top-0 z-50 bg-zinc-800">
<div className="text-sm pl-2 text-zinc-50 flex flex-row gap-4 items-center">
<TerminalIcon />
Console
</div>
<Button
variant="ghost"
className="h-fit px-2 text-zinc-50 hover:bg-zinc-700 hover:text-zinc-50"
onClick={() => {
setConsoleOutputs([]);
}}
>
<CrossIcon />
</Button>
</div>
const [height, setHeight] = useState<number>(224);
const [isResizing, setIsResizing] = useState(false);

const minHeight = 100;
const maxHeight = 800;

const startResizing = useCallback(() => {
setIsResizing(true);
}, []);

{consoleOutputs.map((consoleOutput, index) => (
<div
key={consoleOutput.id}
className="p-4 flex flex-row gap-2 text-sm border-b border-zinc-700 bg-zinc-900 font-mono"
>
<div className="text-emerald-500">[{index + 1}]</div>
{consoleOutput.status === 'in_progress' ? (
<div className="animate-spin">
<LoaderIcon />
</div>
) : (
<div className="text-zinc-50">{consoleOutput.content}</div>
)}
</div>
))}
</motion.div>
)
const stopResizing = useCallback(() => {
setIsResizing(false);
}, []);

const resize = useCallback(
(e: MouseEvent) => {
if (isResizing) {
const newHeight = window.innerHeight - e.clientY;
if (newHeight >= minHeight && newHeight <= maxHeight) {
setHeight(newHeight);
}
}
},
[isResizing],
);

useEffect(() => {
window.addEventListener('mousemove', resize);
window.addEventListener('mouseup', stopResizing);
return () => {
window.removeEventListener('mousemove', resize);
window.removeEventListener('mouseup', stopResizing);
};
}, [resize, stopResizing]);

return consoleOutputs.length > 0 ? (
<motion.div
initial={{ y: height }}
animate={{ y: 0 }}
exit={{ y: height }}
transition={{ type: 'spring', stiffness: 140, damping: 20 }}
className={cn(
'absolute flex flex-col bottom-0 bg-zinc-900 w-full border-t z-50 overflow-y-scroll border-zinc-700',
{
'select-none': isResizing,
},
)}
style={{ height }}
>
<div
className="w-full h-2 bg-zinc-800 cursor-ns-resize"
onMouseDown={startResizing}
/>

<div className="flex flex-row justify-between items-center w-full h-fit border-b border-zinc-700 p-2 pt-0 sticky top-0 z-50 bg-zinc-800">
<div className="text-sm pl-2 text-zinc-50 flex flex-row gap-4 items-center">
<TerminalIcon />
Console
</div>
<Button
variant="ghost"
className="h-fit px-2 text-zinc-50 hover:bg-zinc-700 hover:text-zinc-50"
onClick={() => setConsoleOutputs([])}
>
<CrossIcon />
</Button>
</div>
{consoleOutputs.map((consoleOutput, index) => (
<div
key={consoleOutput.id}
className="p-4 flex flex-row gap-2 text-sm border-b border-zinc-700 bg-zinc-900 font-mono"
>
<div className="text-emerald-500">[{index + 1}]</div>
{consoleOutput.status === 'in_progress' ? (
<div className="animate-spin size-fit self-center">
<LoaderIcon />
</div>
) : (
<div className="text-zinc-50">{consoleOutput.content}</div>
)}
</div>
))}
</motion.div>
) : null;
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
"react": "19.0.0-rc-45804af1-20241021",
"react-dom": "19.0.0-rc-45804af1-20241021",
"react-markdown": "^9.0.1",
"react-resizable-panels": "^2.1.7",
"remark-gfm": "^4.0.0",
"server-only": "^0.0.1",
"sonner": "^1.5.0",
Expand Down
Loading

0 comments on commit 8a1e933

Please sign in to comment.