Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build static SCI playground page in GitHub pages #31

Merged
merged 1 commit into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions .github/workflows/deloy-site.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Build and Deploy
on:
push:
branches:
- main
permissions:
contents: read
pages: write
id-token: write
jobs:
build-and-deploy:
concurrency: ci-${{ github.ref }} # Recommended if you intend to make multiple deployments in quick succession.
runs-on: ubuntu-latest
steps:

- name: Checkout 🛎️
uses: actions/checkout@v3

- name: Prepare java
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-version: '11'

- name: Install clojure tools
uses: DeLaGuardo/[email protected]
with:
# Install just one or all simultaneously
# The value must indicate a particular version of the tool, or use 'latest'
# to always provision the latest version
cli: latest
bb: latest

- name: Install and Build 🔧
run: |
cd playground && bb build

- name: Setup Pages
uses: actions/configure-pages@v3

- name: Upload artifact
uses: actions/upload-pages-artifact@v2
with:
path: 'playground/www'

- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v2
4 changes: 4 additions & 0 deletions playground/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
www/js/
node_modules/
package-lock.json
yarn.lock
6 changes: 6 additions & 0 deletions playground/bb.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{:tasks
{build {:doc "Build the static 'SCI Playground' site with sci and an editor"
:task (do (shell "yarn install")
(clojure "-M:dev:shadow-cli release playground")
(println "Built www"))}
watch (clojure "-M:dev:shadow-cli watch playground")}}
18 changes: 18 additions & 0 deletions playground/deps.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{:deps {; SCI
org.babashka/sci.configs {:local/root ".."}
org.babashka/sci {:git/url "https://github.com/babashka/sci"
:git/sha "987910fb38fdd166865458c3fd4b468a22fb9992"}
;; Editor
io.github.nextjournal/clojure-mode {:git/sha "7b911bf6feab0f67b60236036d124997627cbe5e"}
;; Included libs
org.clojure/clojurescript {:mvn/version "1.11.51"}
applied-science/js-interop {:mvn/version "0.3.3"}
cljs-bean/cljs-bean {:mvn/version "1.9.0"}
com.fulcrologic/fulcro {:mvn/version "3.6.10"}
datascript/datascript {:mvn/version "1.5.3"}
funcool/promesa {:git/url "https://github.com/funcool/promesa"
:git/sha "e503874b154224ce85b223144e80b697df91d18e"}
reagent/reagent {:mvn/version "1.1.0"}
re-frame/re-frame {:mvn/version "1.3.0"}}
:aliases {:dev {:extra-deps {thheller/shadow-cljs {:mvn/version "2.25.7"}}}
:shadow-cli {:main-opts ["-m" "shadow.cljs.devtools.cli"]}}}
25 changes: 25 additions & 0 deletions playground/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "sci_playground",
"version": "1.0.0",
"devDependencies": {
"@codemirror/autocomplete": "^6.0.2",
"@codemirror/commands": "^6.0.0",
"@codemirror/lang-markdown": "6.0.0",
"@codemirror/language": "^6.1.0",
"@codemirror/lint": "^6.0.0",
"@codemirror/search": "^6.0.0",
"@codemirror/state": "^6.0.1",
"@codemirror/view": "^6.0.2",
"@lezer/common": "^1.0.0",
"@lezer/generator": "^1.0.0",
"@lezer/highlight": "^1.0.0",
"@lezer/lr": "^1.0.0",
"@nextjournal/lezer-clojure": "1.0.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"shadow-cljs": "^2.25.7"
},
"dependencies": {
"w3c-keyname": "^2.2.4"
}
}
11 changes: 11 additions & 0 deletions playground/shadow-cljs.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{:deps {:aliases [:dev]}
:nrepl {:port 9000}
:dev-http {8081 "www"}
:builds {:playground {:compiler-options {:output-feature-set :es8
:optimizations :advanced
:source-map true
:output-wrapper false}
:target :browser
:output-dir "www/js"
:modules {:playground {:init-fn playground/init}}
:devtools {:after-load playground/reload}}}}
171 changes: 171 additions & 0 deletions playground/src/playground.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
(ns playground
"Build CodeMirror editor with SCI evaluation for the SCI Playground."
(:require
[sci.core :as sci]
[clojure.string :as str]

;; All the configs
sci.configs.applied-science.js-interop
sci.configs.cljs.pprint
sci.configs.cljs.test
;sci.configs.clojure.test
sci.configs.fulcro.fulcro
sci.configs.funcool.promesa
sci.configs.mfikes.cljs-bean
sci.configs.re-frame.re-frame
sci.configs.reagent.reagent
sci.configs.reagent.reagent-dom-server
sci.configs.tonsky.datascript
; sci.configs.clojure-1-11

;; Code editor
;; Inspiration: https://github.com/nextjournal/clojure-mode/blob/main/demo/src/nextjournal/clojure_mode/demo.cljs
["@codemirror/commands" :refer [history historyKeymap]]
["@codemirror/language" :refer [#_foldGutter
syntaxHighlighting
defaultHighlightStyle]]
["@codemirror/state" :refer [EditorState]]
["@codemirror/view" :as view :refer [EditorView lineNumbers showPanel]]


;; JS deps for re-export to sci
["react" :as react]
["react-dom" :as react-dom]

[nextjournal.clojure-mode :as cm-clj]
))

;; Necessary to avoid the error 'Attempting to call unbound fn: #'clojure.core/*print-fn*'
;; when calling `println` inside the evaluated code
(enable-console-print!)
(sci/alter-var-root sci/print-fn (constantly *print-fn*))
(sci/alter-var-root sci/print-err-fn (constantly *print-err-fn*))

;; ------------------------------------------------------------ SCI eval

(def all-configs ; vars so that we can extract ns info
[#'sci.configs.applied-science.js-interop/config
#'sci.configs.cljs.pprint/config
#'sci.configs.cljs.test/config
;#'sci.configs.clojure.test/config
#'sci.configs.fulcro.fulcro/config
#'sci.configs.funcool.promesa/config
#'sci.configs.mfikes.cljs-bean/config
#'sci.configs.re-frame.re-frame/config
#'sci.configs.reagent.reagent/config
#'sci.configs.reagent.reagent-dom-server/config
#'sci.configs.tonsky.datascript/config])

(def sci-ctx
(->> all-configs
(map deref)
(reduce
sci/merge-opts
(sci/init {:classes {'js js/globalThis :allow :all}
:js-libs {"react" react
"react-dom" react-dom}}))))

(defn eval-code [code]
(try (sci/eval-string* sci-ctx code)
(catch :default e
(try (js/console.log "Evaluation failed:" (ex-message e)
(some-> e ex-data clj->js))
(catch :default _))
{::error (str (.-message e)) :data (ex-data e)})))

(defn eval-all [on-result x]
(on-result (some->> (.-doc (.-state x)) str eval-code))
true)

(defn sci-extension [on-result]
(.of view/keymap
#js [#js {:key "Mod-Enter" ; Cmd or Ctrl
:run (partial eval-all on-result)}]))

;; ------------------------------------------------------------ Code editor

(defn mac? []
(some? (re-find #"(Mac)|(iPhone)|(iPad)|(iPod)" js/navigator.platform)))

(defn output-panel-extension
"Display a panel below the editor with the output of the
last evaluation (read from the passed-in `result-atom`)"
[result-atom]
(let [dom (js/document.createElement "div")]
(add-watch result-atom :output-panel
(fn [_ _ _ new]
(if (::error new)
(do
(.add (.-classList dom) "error")
(set! (.-textContent dom) (str "ERROR: " (::error new)
(some->> new :data pr-str (str " ")))))
(do
(.remove (.-classList dom) "error")
(set! (.-textContent dom) (str ";; => " (pr-str new)))))))
(set! (.-className dom) "cm-output-panel")
(set! (.-textContent dom)
(str "Press "
(if (mac?) "Cmd" "Ctrl")
"-Enter in the editor to evaluate it. Return value will show up here."))
(.of showPanel
(fn [_view] #js {:dom dom}))))

(def theme
(.theme
EditorView
#js {".cm-output-panel.error" #js {:color "red"}}))

(defonce extensions
#js[theme
(history)
(syntaxHighlighting defaultHighlightStyle)
(view/drawSelection)
(lineNumbers)
(.. EditorState -allowMultipleSelections (of true))
cm-clj/default-extensions
(.of view/keymap cm-clj/complete-keymap)
(.of view/keymap historyKeymap)])

(defn bind-editor! [el code]
{:pre [el code]}
(let [target-el (js/document.createElement "div")
last-result (atom nil)
exts (.concat extensions
#js [(sci-extension (partial reset! last-result))
(output-panel-extension last-result)])]
(.replaceWith el target-el)
(new EditorView
#js {:parent target-el
:state (.create EditorState #js {:doc code
:extensions exts})})))

(defn list-libraries [all-config-vars]
(->> all-config-vars
(map (comp name :ns meta))
(map #(clojure.string/replace % #"^sci\.configs\.[\w-]+\." ""))
(remove #{"pprint" "test"})
sort
(str/join ", ")))

(defn ^:export init []
(let [code-el (js/document.getElementById "code")
code (.-textContent code-el)
libs-el (js/document.getElementById "libs")]
(set! (.-textContent libs-el) (list-libraries all-configs))
(bind-editor! code-el code))
(println "Init run"))

(defn ^:export reload []
(println "Reload run (noop)"))

(comment

(def X #'sci.configs.cljs.pprint/config)


(-> X meta :ns name
(clojure.string/replace-first "sci.configs." ""))



)
43 changes: 43 additions & 0 deletions playground/www/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8" />
<title>SCI Playground</title>
<link rel="stylesheet" href="/css/blog.css">
</head>

<body>
<h1>SCI Playground</h1>
<p>Write and evaluate SCI Clojure using any of the libraries in sci.configs
in the editor below. Use Cmd / Ctr - Enter to evaluate.</p>
<p>Supported libraries: <span id="libs">todo</span>.</p>

<pre><code id="code">(ns test1
(:require
[applied-science.js-interop :as j]
[promesa.core :as p]
[cljs-bean.core :refer [bean ->clj ->js]]
[re-frame.core :as rf]
[re-frame.db :as r.db]
[reagent.core :as r]
[reagent.dom.server :as rds]
[reagent.debug]
[reagent.ratom :as ratom]
[datascript.core :as d]
[datascript.db :as d.db]
[com.fulcrologic.fulcro.application :as app]
[com.fulcrologic.fulcro.components :as comp :refer [defsc]]
[com.fulcrologic.fulcro.dom :as dom]))
(defsc Root [this props]
(dom/div (dom/h3 "Hello from SCI!")
(dom/p "Here you can play with Fulcro and Reagent apps and much more!")))
(app/mount! (app/fulcro-app) Root "app")
</code></pre>
<div id="app" style="border: 1px dashed; padding: 0.4rem">
<em>You can use this <code>&lt;div id="app"&gt;</code> to render DOM.</em>
</div>
</body>
<script src="js/playground.js"></script>

</html>