mirror of
https://github.com/pyscript/pyscript.git
synced 2022-05-01 19:47:48 +03:00
add stores, move pyscript component in it's own file add method to add new scripts to page
This commit is contained in:
@@ -7,6 +7,18 @@
|
||||
function toggleMode() {
|
||||
editMode = ! editMode;
|
||||
}
|
||||
|
||||
function addScript(evt){
|
||||
// get the main element
|
||||
const mainEl = document.getElementById("dashboard");
|
||||
const p = document.createElement("py-script");
|
||||
mainEl.appendChild(p);
|
||||
}
|
||||
|
||||
function addInterpreter(evt){
|
||||
console.log("add interpreter");
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<nav class="bg-gray-800">
|
||||
@@ -20,13 +32,13 @@
|
||||
<div class="hidden md:block">
|
||||
<div class="ml-10 flex items-baseline space-x-4">
|
||||
<!-- Current: "bg-gray-900 text-white", Default: "text-gray-300 hover:bg-gray-700 hover:text-white" -->
|
||||
<a href="#" class="bg-gray-900 text-white px-3 py-2 rounded-md text-sm font-medium" aria-current="page">Dashboard</a>
|
||||
<a class="bg-gray-900 text-white px-3 py-2 rounded-md text-sm font-medium" aria-current="page">Dashboard</a>
|
||||
|
||||
<!-- <a href="#" class="text-gray-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">Team</a>
|
||||
<a class="text-gray-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium" on:click={addScript}>+ Script</a>
|
||||
|
||||
<a href="#" class="text-gray-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">Projects</a>
|
||||
<a class="text-gray-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium" on:click={addInterpreter}>+ Interpreter</a>
|
||||
|
||||
<a href="#" class="text-gray-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">Calendar</a>
|
||||
<!-- <a href="#" class="text-gray-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">Calendar</a>
|
||||
|
||||
<a href="#" class="text-gray-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium">Reports</a> -->
|
||||
</div>
|
||||
@@ -106,11 +118,11 @@
|
||||
<!-- Current: "bg-gray-900 text-white", Default: "text-gray-300 hover:bg-gray-700 hover:text-white" -->
|
||||
<a href="#" class="bg-gray-900 text-white block px-3 py-2 rounded-md text-base font-medium" aria-current="page">Dashboard</a>
|
||||
|
||||
<!-- <a href="#" class="text-gray-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium">Team</a>
|
||||
<a href="#" class="text-gray-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium">+ Script</a>
|
||||
|
||||
<a href="#" class="text-gray-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium">Projects</a>
|
||||
<a href="#" class="text-gray-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium">+ Interpreter</a>
|
||||
|
||||
<a href="#" class="text-gray-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium">Calendar</a>
|
||||
<!-- <a href="#" class="text-gray-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium">Calendar</a>
|
||||
|
||||
<a href="#" class="text-gray-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium">Reports</a> -->
|
||||
</div>
|
||||
|
||||
@@ -14,16 +14,19 @@
|
||||
</div>
|
||||
</header>
|
||||
<main>
|
||||
<div class="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8">
|
||||
<div class="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8">
|
||||
<!-- Replace with your content -->
|
||||
<div class="px-4 py-6 sm:px-0">
|
||||
<div class="border-4 border-dashed border-gray-200 rounded-lg h-96"></div>
|
||||
<div id="dashboard" class="border-4 border-dashed border-gray-200 rounded-lg h-96">
|
||||
<py-script>
|
||||
sum([1, 2, 3, 4, 5])
|
||||
</py-script>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<py-script>
|
||||
sum([1, 2, 3, 4, 5])
|
||||
</py-script>
|
||||
|
||||
|
||||
|
||||
<!-- /End replace -->
|
||||
</div>
|
||||
|
||||
138
pyscriptjs/src/components/pyscript.ts
Normal file
138
pyscriptjs/src/components/pyscript.ts
Normal file
@@ -0,0 +1,138 @@
|
||||
import {EditorState, EditorView , basicSetup} from "@codemirror/basic-setup"
|
||||
import { python } from "@codemirror/lang-python"
|
||||
import { keymap } from "@codemirror/view";
|
||||
import { defaultKeymap } from "@codemirror/commands";
|
||||
import { oneDarkTheme } from "@codemirror/theme-one-dark";
|
||||
|
||||
import { pyodideLoaded } from '../stores';
|
||||
import { addClasses } from '../utils';
|
||||
|
||||
// Premise used to connect to the first available pyodide interpreter
|
||||
let pyodideReadyPromise;
|
||||
|
||||
pyodideLoaded.subscribe(value => {
|
||||
pyodideReadyPromise = value;
|
||||
});
|
||||
|
||||
export class PyScript extends HTMLElement {
|
||||
shadow: ShadowRoot;
|
||||
wrapper: HTMLElement;
|
||||
editor: EditorView;
|
||||
editorNode: HTMLElement;
|
||||
code: string;
|
||||
cm: any;
|
||||
btnEdit: HTMLElement;
|
||||
btnRun: HTMLElement;
|
||||
editorOut: HTMLTextAreaElement;
|
||||
// editorState: EditorState;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
// attach shadow so we can preserve the element original innerHtml content
|
||||
this.shadow = this.attachShadow({ mode: 'open'});
|
||||
|
||||
this.wrapper = document.createElement('slot');
|
||||
|
||||
// add an extra div where we can attach the codemirror editor
|
||||
this.editorNode = document.createElement('div');
|
||||
|
||||
this.shadow.appendChild(this.wrapper);
|
||||
// this.shadow.appendChild(this.editorNode);
|
||||
// this.code = this.wrapper.innerHTML;
|
||||
console.log("Woooohooo");
|
||||
}
|
||||
connectedCallback() {
|
||||
|
||||
this.code = this.innerHTML;
|
||||
this.innerHTML = '';
|
||||
let startState = EditorState.create({
|
||||
doc: this.code,
|
||||
extensions: [
|
||||
keymap.of(defaultKeymap),
|
||||
oneDarkTheme,
|
||||
// python()
|
||||
]
|
||||
})
|
||||
|
||||
this.editor = new EditorView({
|
||||
state: startState,
|
||||
parent: this.editorNode
|
||||
})
|
||||
|
||||
let mainDiv = document.createElement('div');
|
||||
addClasses(mainDiv, ["flex", "flex-col"])
|
||||
|
||||
mainDiv.appendChild(this.editorNode);
|
||||
|
||||
// Butons DIV
|
||||
var eDiv = document.createElement('div');
|
||||
// addClasses(eDiv, ["flex", "flex-row-reverse", "justify-center", "rounded-lg", "text-lg", "mb-4"]);
|
||||
addClasses(eDiv, "flex flex-row-reverse space-x-reverse space-x-4 font-mono text-white text-sm font-bold leading-6 dev-buttons-group".split(" "))
|
||||
eDiv.setAttribute("role", "group");
|
||||
|
||||
// RUN BUTTON
|
||||
this.btnRun = document.createElement('button');
|
||||
this.btnRun.innerHTML = "run";
|
||||
let buttonClasses = ["mr-2", "block", "py-2", "px-8", "rounded-full"];
|
||||
addClasses(this.btnRun, buttonClasses);
|
||||
addClasses(this.btnRun, ["text-green-100", "bg-green-500"])
|
||||
|
||||
eDiv.appendChild(this.btnRun);
|
||||
|
||||
|
||||
this.btnEdit = document.createElement('button');
|
||||
this.btnEdit.innerHTML = "edit";
|
||||
addClasses(this.btnEdit, buttonClasses);
|
||||
addClasses(this.btnEdit, ["text-blue-100", "bg-blue-500"])
|
||||
eDiv.appendChild(this.btnEdit);
|
||||
|
||||
|
||||
this.editorOut = document.createElement('textarea');
|
||||
this.editorOut.classList.add("output");
|
||||
this.editorOut.disabled = true;
|
||||
this.editorOut.hidden = true;
|
||||
mainDiv.appendChild(eDiv);
|
||||
mainDiv.appendChild(this.editorOut);
|
||||
this.appendChild(mainDiv);
|
||||
|
||||
|
||||
this.btnRun.onclick = wrap(this);
|
||||
|
||||
function wrap(el: any){
|
||||
function addToOutput(s: string) {
|
||||
el.editorOut.value += ">>> " + s + "\n";
|
||||
}
|
||||
|
||||
async function evaluatePython() {
|
||||
console.log('evaluate');
|
||||
let pyodide = await pyodideReadyPromise;
|
||||
// debugger
|
||||
try {
|
||||
|
||||
// @ts-ignore
|
||||
let output = pyodide.runPython(el.editor.state.doc.toString());
|
||||
if (output !== undefined){
|
||||
addToOutput(output);
|
||||
el.editorOut.hidden = false;
|
||||
}
|
||||
|
||||
// debugger
|
||||
} catch (err) {
|
||||
addToOutput(err);
|
||||
}
|
||||
}
|
||||
return evaluatePython;
|
||||
}
|
||||
|
||||
|
||||
console.log('connected');
|
||||
}
|
||||
|
||||
render(){
|
||||
console.log('rendered');
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
15
pyscriptjs/src/interpreter.ts
Normal file
15
pyscriptjs/src/interpreter.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
// @ts-nocheck
|
||||
// @ts-ignore
|
||||
let pyodideReadyPromise;
|
||||
|
||||
|
||||
let loadInterpreter = async function(): any {
|
||||
/* @ts-ignore */
|
||||
let pyodide = await loadPyodide({
|
||||
indexURL: "https://cdn.jsdelivr.net/pyodide/v0.19.0/full/",
|
||||
});
|
||||
/* @ts-ignore */
|
||||
return pyodide;
|
||||
}
|
||||
|
||||
export {loadInterpreter, pyodideReadyPromise}
|
||||
@@ -5,140 +5,14 @@ import { python } from "@codemirror/lang-python"
|
||||
import { keymap } from "@codemirror/view";
|
||||
import { defaultKeymap } from "@codemirror/commands";
|
||||
import { oneDarkTheme } from "@codemirror/theme-one-dark";
|
||||
|
||||
import { PyScript } from "./components/pyscript";
|
||||
import { pyodideLoaded } from './stores';
|
||||
|
||||
function addClasses(element: HTMLElement, classes: Array<string>){
|
||||
for (let entry of classes) {
|
||||
element.classList.add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
let pyodideReadyPromise;
|
||||
|
||||
pyodideLoaded.subscribe(value => {
|
||||
pyodideReadyPromise = value;
|
||||
});
|
||||
|
||||
class PyScript extends HTMLElement {
|
||||
shadow: ShadowRoot;
|
||||
wrapper: HTMLElement;
|
||||
editor: EditorView;
|
||||
editorNode: HTMLElement;
|
||||
code: string;
|
||||
cm: any;
|
||||
btnEdit: HTMLElement;
|
||||
btnRun: HTMLElement;
|
||||
editorOut: HTMLTextAreaElement;
|
||||
// editorState: EditorState;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
// attach shadow so we can preserve the element original innerHtml content
|
||||
this.shadow = this.attachShadow({ mode: 'open'});
|
||||
|
||||
this.wrapper = document.createElement('slot');
|
||||
|
||||
// add an extra div where we can attach the codemirror editor
|
||||
this.editorNode = document.createElement('div');
|
||||
|
||||
this.shadow.appendChild(this.wrapper);
|
||||
// this.shadow.appendChild(this.editorNode);
|
||||
// this.code = this.wrapper.innerHTML;
|
||||
console.log("Woooohooo");
|
||||
}
|
||||
connectedCallback() {
|
||||
|
||||
this.code = this.innerHTML;
|
||||
this.innerHTML = '';
|
||||
let startState = EditorState.create({
|
||||
doc: this.code,
|
||||
extensions: [
|
||||
keymap.of(defaultKeymap),
|
||||
oneDarkTheme,
|
||||
// python()
|
||||
]
|
||||
})
|
||||
|
||||
this.editor = new EditorView({
|
||||
state: startState,
|
||||
parent: this.editorNode
|
||||
})
|
||||
|
||||
let mainDiv = document.createElement('div');
|
||||
addClasses(mainDiv, ["flex", "flex-col"])
|
||||
|
||||
mainDiv.appendChild(this.editorNode);
|
||||
|
||||
// Butons DIV
|
||||
var eDiv = document.createElement('div');
|
||||
// addClasses(eDiv, ["flex", "flex-row-reverse", "justify-center", "rounded-lg", "text-lg", "mb-4"]);
|
||||
addClasses(eDiv, "flex flex-row-reverse space-x-reverse space-x-4 font-mono text-white text-sm font-bold leading-6 dev-buttons-group".split(" "))
|
||||
eDiv.setAttribute("role", "group");
|
||||
|
||||
// RUN BUTTON
|
||||
this.btnRun = document.createElement('button');
|
||||
this.btnRun.innerHTML = "run";
|
||||
let buttonClasses = ["mr-2", "block", "py-2", "px-8", "rounded-full"];
|
||||
addClasses(this.btnRun, buttonClasses);
|
||||
addClasses(this.btnRun, ["text-green-100", "bg-green-500"])
|
||||
|
||||
eDiv.appendChild(this.btnRun);
|
||||
|
||||
|
||||
this.btnEdit = document.createElement('button');
|
||||
this.btnEdit.innerHTML = "edit";
|
||||
addClasses(this.btnEdit, buttonClasses);
|
||||
addClasses(this.btnEdit, ["text-blue-100", "bg-blue-500"])
|
||||
eDiv.appendChild(this.btnEdit);
|
||||
|
||||
|
||||
this.editorOut = document.createElement('textarea');
|
||||
this.editorOut.classList.add("output");
|
||||
this.editorOut.disabled = true;
|
||||
mainDiv.appendChild(eDiv);
|
||||
mainDiv.appendChild(this.editorOut);
|
||||
this.appendChild(mainDiv);
|
||||
|
||||
|
||||
this.btnRun.onclick = wrap(this);
|
||||
|
||||
function wrap(el: any){
|
||||
function addToOutput(s: string) {
|
||||
el.editorOut.value += ">>> " + s + "\n";
|
||||
}
|
||||
|
||||
async function evaluatePython() {
|
||||
console.log('evaluate');
|
||||
let pyodide = await pyodideReadyPromise;
|
||||
// debugger
|
||||
try {
|
||||
|
||||
// @ts-ignore
|
||||
let output = pyodide.runPython(el.editor.state.doc.toString());
|
||||
addToOutput(output);
|
||||
} catch (err) {
|
||||
addToOutput(err);
|
||||
}
|
||||
}
|
||||
return evaluatePython;
|
||||
}
|
||||
|
||||
|
||||
console.log('connected');
|
||||
}
|
||||
|
||||
render(){
|
||||
console.log('rendered');
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
let xPyScript = customElements.define('py-script', PyScript);
|
||||
|
||||
|
||||
|
||||
const app = new App({
|
||||
target: document.body,
|
||||
});
|
||||
|
||||
15
pyscriptjs/src/stores.ts
Normal file
15
pyscriptjs/src/stores.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { promisable } from 'svelte-promisable-stores';
|
||||
import { loadInterpreter } from "./interpreter";
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
|
||||
export const pyodideLoaded = writable({
|
||||
loaded: false,
|
||||
premise: null
|
||||
});
|
||||
|
||||
export const pyodideReadyPromise = promisable(
|
||||
loadInterpreter,
|
||||
// shouldRefreshPromise, // optional, but recommended
|
||||
);
|
||||
|
||||
6
pyscriptjs/src/utils.ts
Normal file
6
pyscriptjs/src/utils.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
export function addClasses(element: HTMLElement, classes: Array<string>){
|
||||
for (let entry of classes) {
|
||||
element.classList.add(entry);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user