Skip to content

Commit

Permalink
feat: better zero states around code (#541)
Browse files Browse the repository at this point in the history
  • Loading branch information
jimniels committed Jul 6, 2023
1 parent 3698dd4 commit dfe5531
Show file tree
Hide file tree
Showing 4 changed files with 412 additions and 249 deletions.
13 changes: 10 additions & 3 deletions src/ui/menus/CodeEditor/CodeEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { AI, Formula, Python } from '../../icons';
import { TooltipHint } from '../../components/TooltipHint';
import { KeyboardSymbols } from '../../../helpers/keyboardSymbols';
import { ResizeControl } from './ResizeControl';
import { CodeEditorPlaceholder } from './CodeEditorPlaceholder';
import mixpanel from 'mixpanel-browser';
import useAlertOnUnsavedChanges from '../../../hooks/useAlertOnUnsavedChanges';

Expand Down Expand Up @@ -386,6 +387,7 @@ export const CodeEditor = (props: CodeEditorProps) => {
{/* Editor Body */}
<div
style={{
position: 'relative',
minHeight: '100px',
flex: '2',
}}
Expand All @@ -395,9 +397,7 @@ export const CodeEditor = (props: CodeEditorProps) => {
width="100%"
language={editorMode === 'PYTHON' ? 'python' : editorMode === 'FORMULA' ? 'formula' : 'plaintext'}
value={editorContent}
onChange={(value) => {
setEditorContent(value);
}}
onChange={setEditorContent}
onMount={handleEditorDidMount}
options={{
minimap: { enabled: true },
Expand All @@ -412,6 +412,13 @@ export const CodeEditor = (props: CodeEditorProps) => {
wordWrap: 'on',
}}
/>
{selectedCell.type === 'PYTHON' && (
<CodeEditorPlaceholder
editorContent={editorContent}
setEditorContent={setEditorContent}
editorRef={editorRef}
/>
)}
</div>

<ResizeControl setState={setConsoleHeight} position="TOP" />
Expand Down
137 changes: 137 additions & 0 deletions src/ui/menus/CodeEditor/CodeEditorPlaceholder.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import { Fragment, RefObject, useEffect, useState } from 'react';
import useLocalStorage from '../../../hooks/useLocalStorage';
import { codeEditorBaseStyles, codeEditorCommentStyles } from './styles';
import monaco from 'monaco-editor';

export const snippets = [
{
label: 'fetch data',
// prettier-ignore
code:
`import json
from pyodide.http import pyfetch
# Fetch data
res = await pyfetch(
'https://jsonplaceholder.typicode.com/users',
method = 'GET',
headers = {
'Content-Type': 'application/json'
}
)
users = json.loads(await res.string())
# Table
out = []
# Headers
out.append(['Username', 'Email', 'Website'])
# Rows (from json)
for user in users:
out.append([user['username'], user['email'], user['website']])
# Last line returns to sheet
out`,
},
{
label: 'reference cells',
// prettier-ignore
code:
`# Reference a value from the sheet
myCell = cell(x, y)
# Or reference a range of cells (returns a Pandas DataFrame)
cells((x1, y1), (x2, y2))`,
},
{
label: 'return data to the sheet',
// prettier-ignore
code:
`out = []
for x in range(10):
out.append(x)
# Last line returns to the sheet
out
# [out] # Wrap in array to expand horizontally`,
},
];

export function CodeEditorPlaceholder({
editorContent,
editorRef,
setEditorContent,
}: {
editorContent: string | undefined;
editorRef: RefObject<monaco.editor.IStandaloneCodeEditor | null>;
setEditorContent: (str: string | undefined) => void;
}) {
const [showPlaceholder, setShowPlaceholder] = useLocalStorage<boolean>('showCodeEditorPlaceholder', true);
const [shouldRunEffect, setShouldRunEffect] = useState<boolean>(false);

// When the user chooses to autofill the editor with a predefined snippet,
// focus the editor and set the initial cursor position
useEffect(() => {
if (editorRef && editorRef.current && shouldRunEffect) {
editorRef.current.focus();
editorRef.current.setPosition({ lineNumber: 0, column: 0 });
setShouldRunEffect(false);
}
}, [editorRef, editorContent, shouldRunEffect]);

if (editorContent) {
return null;
}

if (!showPlaceholder) {
return null;
}

return (
<div
style={{
position: 'absolute',
left: '64px',
right: '14%',
top: 0,
pointerEvents: 'none',
// Kinda hacky, but we're copying the style of the code editor
...codeEditorBaseStyles,
...codeEditorCommentStyles,
}}
>
Start with a code snippet to{' '}
{snippets.map((snippet, i: number) => (
<Fragment key={i}>
<a
href={`#snippet-${i}`}
style={{ color: 'inherit', pointerEvents: 'auto' }}
onClick={(e) => {
e.preventDefault();
setEditorContent(snippet.code);
setShouldRunEffect(true);
}}
>
{snippet.label}
</a>
{i === snippets.length - 1 ? '.' : i < snippets.length - 2 ? ', ' : ', or '}
</Fragment>
))}
<br />
<br />
Start typing to dismiss or{' '}
<a
href="#dont-show-again"
style={{ color: 'inherit', pointerEvents: 'auto' }}
onClick={(e) => {
e.preventDefault();
setShowPlaceholder(false);
}}
>
don’t show this again
</a>
.
</div>
);
}
Loading

1 comment on commit dfe5531

@vercel
Copy link

@vercel vercel bot commented on dfe5531 Jul 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

quadratic – ./

quadratic-nu.vercel.app
quadratic-git-main-quadratic.vercel.app
quadratic-quadratic.vercel.app

Please sign in to comment.