diff --git a/gui/src/app/FileEditor/StanFileEditor.tsx b/gui/src/app/FileEditor/StanFileEditor.tsx index 922f1824..1ed6df8a 100644 --- a/gui/src/app/FileEditor/StanFileEditor.tsx +++ b/gui/src/app/FileEditor/StanFileEditor.tsx @@ -234,7 +234,7 @@ const StanFileEditor: FunctionComponent = ({ readOnly={!isCompiling ? readOnly : true} toolbarItems={toolbarItems} codeMarkers={stancErrorsToCodeMarkers(stancErrors)} - hintTextOnEmpty="Begin editing or select an example from the left panel" + contentOnEmpty="Begin editing or select an example from the left panel" /> {window} diff --git a/gui/src/app/FileEditor/TextEditor.tsx b/gui/src/app/FileEditor/TextEditor.tsx index 5398d188..2eb3a34d 100644 --- a/gui/src/app/FileEditor/TextEditor.tsx +++ b/gui/src/app/FileEditor/TextEditor.tsx @@ -27,7 +27,7 @@ type Props = { toolbarItems?: ToolbarItem[]; label: string; codeMarkers?: CodeMarker[]; - hintTextOnEmpty?: string; + contentOnEmpty?: string | HTMLSpanElement; }; export type ToolbarItem = @@ -55,7 +55,7 @@ const TextEditor: FunctionComponent = ({ language, label, codeMarkers, - hintTextOnEmpty, + contentOnEmpty, }) => { const handleChange = useCallback( (value: string | undefined) => { @@ -104,16 +104,16 @@ const TextEditor: FunctionComponent = ({ useEffect(() => { if (!editorInstance) return; - if (!hintTextOnEmpty) return; + if (!contentOnEmpty) return; if (text || editedText) { return; } - const contentWidget = createHintTextContentWidget(hintTextOnEmpty); + const contentWidget = createHintTextContentWidget(contentOnEmpty); editorInstance.addContentWidget(contentWidget); return () => { editorInstance.removeContentWidget(contentWidget); }; - }, [text, editorInstance, editedText, hintTextOnEmpty]); + }, [text, editorInstance, editedText, contentOnEmpty]); ///////////////////////////////////////////////// @@ -242,14 +242,18 @@ const NotSelectable: FunctionComponent = ({ children }) => { return
{children}
; }; -const createHintTextContentWidget = (hintText: string) => { +const createHintTextContentWidget = (content: string | HTMLSpanElement) => { return { getDomNode: () => { const node = document.createElement("div"); node.style.width = "max-content"; - node.style.pointerEvents = "none"; node.className = "EditorHintText"; - node.textContent = hintText; + const spanElement = + typeof content === "string" ? document.createElement("span") : content; + if (typeof content === "string") { + spanElement.textContent = content; + } + node.appendChild(spanElement); return node; }, getId: () => "hintText", diff --git a/gui/src/app/pages/HomePage/DataGenerationWindow/DataPyFileEditor.tsx b/gui/src/app/pages/HomePage/DataGenerationWindow/DataPyFileEditor.tsx index a6e6c274..eed5aa0f 100644 --- a/gui/src/app/pages/HomePage/DataGenerationWindow/DataPyFileEditor.tsx +++ b/gui/src/app/pages/HomePage/DataGenerationWindow/DataPyFileEditor.tsx @@ -87,6 +87,21 @@ const DataPyFileEditor: FunctionComponent = ({ [fileContent, editedFileContent, handleRun, status, handleHelp], ); + const contentOnEmpty = useMemo(() => { + const spanElement = document.createElement("span"); + const t1 = document.createTextNode( + "Define a dictionary called data to update the data.json. ", + ); + const a1 = document.createElement("a"); + a1.onclick = () => { + setEditedFileContent(dataPyTemplate); + }; + a1.textContent = "Click here to generate an example"; + spanElement.appendChild(t1); + spanElement.appendChild(a1); + return spanElement; + }, [setEditedFileContent]); + return ( = ({ onSetEditedText={setEditedFileContent} readOnly={readOnly} toolbarItems={toolbarItems} + contentOnEmpty={contentOnEmpty} /> ); }; +const dataPyTemplate = `data = { + "a": [1, 2, 3] +}`; + export default DataPyFileEditor; diff --git a/gui/src/app/pages/HomePage/DataGenerationWindow/DataRFileEditor.tsx b/gui/src/app/pages/HomePage/DataGenerationWindow/DataRFileEditor.tsx index b5c0f386..a8cb7841 100644 --- a/gui/src/app/pages/HomePage/DataGenerationWindow/DataRFileEditor.tsx +++ b/gui/src/app/pages/HomePage/DataGenerationWindow/DataRFileEditor.tsx @@ -121,6 +121,21 @@ if (typeof(data) != "list") { [fileContent, editedFileContent, handleRun, status, handleHelp], ); + const contentOnEmpty = useMemo(() => { + const spanElement = document.createElement("span"); + const t1 = document.createTextNode( + "Define a list called data to update the data.json. ", + ); + const a1 = document.createElement("a"); + a1.onclick = () => { + setEditedFileContent(dataRTemplate); + }; + a1.textContent = "Click here to generate an example"; + spanElement.appendChild(t1); + spanElement.appendChild(a1); + return spanElement; + }, [setEditedFileContent]); + return ( ); }; +const dataRTemplate = `data <- list( + a = c(1, 2, 3) +)`; + export default DataRFileEditor; diff --git a/gui/src/app/pyodide/AnalysisPyFileEditor.tsx b/gui/src/app/pyodide/AnalysisPyFileEditor.tsx index 59afef92..a572aae2 100644 --- a/gui/src/app/pyodide/AnalysisPyFileEditor.tsx +++ b/gui/src/app/pyodide/AnalysisPyFileEditor.tsx @@ -158,6 +158,21 @@ const AnalysisPyFileEditor: FunctionComponent = ({ return ret; }, [fileContent, editedFileContent, imagesRef, hasData, status, handleRun]); + const contentOnEmpty = useMemo(() => { + const spanElement = document.createElement("span"); + const t1 = document.createTextNode( + "Use the draws object to access the samples. ", + ); + const a1 = document.createElement("a"); + a1.onclick = () => { + setEditedFileContent(analysisPyTemplate); + }; + a1.textContent = "Click here to generate an example"; + spanElement.appendChild(t1); + spanElement.appendChild(a1); + return spanElement; + }, [setEditedFileContent]); + return ( = ({ onSetEditedText={setEditedFileContent} readOnly={readOnly} toolbarItems={toolbarItems} + contentOnEmpty={contentOnEmpty} /> ); }; +const analysisPyTemplate = `import matplotlib.pyplot as plt + +# Print the draws object +print(draws) + +# Print parameter names +print(draws.parameter_names) + +# plot the lp parameter +samples = draws.get("lp__") +print(samples.shape) +plt.hist(samples.ravel(), bins=30) +plt.title("lp__") +plt.show() +`; + type ConsoleOutType = "stdout" | "stderr"; export const writeConsoleOutToDiv = ( diff --git a/gui/src/localStyles.css b/gui/src/localStyles.css index bd47c831..1024392e 100644 --- a/gui/src/localStyles.css +++ b/gui/src/localStyles.css @@ -196,4 +196,11 @@ span.EditorTitle { .EditorHintText { font-style: italic; color: #aaa; -} \ No newline at end of file + pointer-events: none; +} + +.EditorHintText a { + color: gray; + text-decoration: underline; + pointer-events: all; +}