diff --git a/bb.edn b/bb.edn new file mode 100644 index 0000000..135a51d --- /dev/null +++ b/bb.edn @@ -0,0 +1,77 @@ +{:deps {io.github.babashka/sci.nrepl + #_{:local/root "../sci.nrepl"} + {:git/sha "2f8a9ed2d39a1b09d2b4d34d95494b56468f4a23"} + io.github.babashka/http-server + {:git/tag "v0.1.14" + :git/sha "4af3c76"} + io.github.scittle/build + {:local/root "build"}} + + :tasks + {:requires ([scittle.build :as build] + [babashka.fs :as fs] + [cheshire.core :as json] + [babashka.process :as p :refer [process]]) + + clean {:doc "Start from clean slate." + :task (do (fs/delete-tree (fs/file "resources" "public" "js")) + (fs/delete-tree ".cpcache") + (fs/delete-tree ".shadow-cljs"))} + + shadow:watch {:doc "Development build. Starts webserver and watches for changes." + :task (build/build {:action "watch" + :args *command-line-args*})} + + http-server {:doc "Starts http server for serving static files" + :requires ([babashka.http-server :as http]) + :task (do (http/serve {:port 1341 :dir "resources/public"}) + (println "Serving static assets at http://localhost:1341"))} + + browser-nrepl {:doc "Start browser nREPL" + :requires ([sci.nrepl.browser-server :as bp]) + :task (bp/start! {})} + + -dev {:depends [shadow:watch browser-nrepl http-server]} + + dev {:doc "Development build. Starts webserver and watches for changes." + :task (do (run '-dev {:parallel true}) + (deref (promise)))} + + prod {:doc "Builds production artifacts." + :task (build/build {}) + :depends [clean]} + + dist {:doc "Prepare dist folder for npm package" + :depends [prod] + :task (do + (fs/delete-tree "dist") + (fs/create-dirs "dist/dev") + (run! (fn [f] (fs/copy f "dist" {:replace-existing true})) + (fs/glob "resources/public/js" "*.{js,js.map}")) + (run! (fn [f] (fs/copy f "dist/dev" {:replace-existing true})) + (fs/glob "resources/public/js/dev" "*.{js,js.map}")))} + + bump-version {:doc "Bumps package.json and pushes new git tag" + :task (do (shell "npm version patch") + (shell "git push --atomic origin main" + (str "v" (:version (json/parse-string (slurp "package.json") true)))))} + + npm-publish {:doc "Updates NPM ibrary" + :task (do (run 'dist) + (run 'bump-version) + (shell "npm publish"))} + + replace-version {:doc "Ported from bash one-liners. Expects two versions. + TODO: port to Clojure. + TODO: skip changelog.md + " + :task + (let [[prev next] *command-line-args*] + (-> (process ["bash" "-c" + (format "rg %s --files-with-matches -g '!/CHANGELOG.md' | xargs sed -i '' 's/%s/%s/g'" + prev prev next)] + {:inherit true}) + p/check))} + + gh-pages {:doc "Updates Github pages with new release build." + :task (shell "script/release.clj")}}} diff --git a/build/deps.edn b/build/deps.edn new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/build/deps.edn @@ -0,0 +1 @@ +{} diff --git a/build/src/scittle/build.clj b/build/src/scittle/build.clj new file mode 100644 index 0000000..02382e5 --- /dev/null +++ b/build/src/scittle/build.clj @@ -0,0 +1,83 @@ +(ns scittle.build + "Provides bb tasks for building and releasing scittle" + (:require + [babashka.classpath :as classpath] + [babashka.fs :as fs] + [babashka.tasks :refer [clojure]] + [clojure.edn :as edn] + [clojure.string :as str])) + +(defn- feature-files + [] + (filter fs/exists? + (map (fn [d] + (fs/file d "scittle_plugin.edn")) + (classpath/split-classpath (classpath/get-classpath))))) + +(defn- read-configs + [files] + (->> files + (mapcat (comp edn/read-string slurp str)))) + +(defn- build-cmd [cmd scittle-dir] + (let [files (feature-files) + feature-configs (read-configs files) + ;; Each ./src/scittle_plugin.edn has a ./deps.edn + feature-dirs (map (comp fs/parent fs/parent) files) + cmd' (if (seq files) + (format "-Sdeps '%s' %s" + {:deps + (merge (into {} + (map (fn [dir] + [(symbol (str (fs/file-name dir) "/deps")) + {:local/root (str dir)}]) + feature-dirs)) + {'scittle/deps {:local/root scittle-dir}})} + cmd) + cmd)] + (when (seq feature-configs) + (println "Building features:" (str/join ", " (map :name feature-configs)) "...")) + (if (seq feature-configs) + (apply str cmd' + (map (fn [m] (format " --config-merge '%s'" (pr-str (:shadow-config m)))) + feature-configs)) + cmd'))) + +(defn- build* + [cmd] + (let [building-outside-scittle? (not (fs/exists? "shadow-cljs.edn")) + scittle-dir (when building-outside-scittle? + (->> (classpath/get-classpath) + classpath/split-classpath + ;; Pull out scittle from local/root or git/url + (some #(when (re-find #"(scittle/[0-9a-f]+|scittle)/src" %) %)) + fs/parent))] + (when building-outside-scittle? + (fs/copy (fs/file scittle-dir "shadow-cljs.edn") "shadow-cljs.edn")) + (let [cmd (build-cmd cmd (str scittle-dir))] + (println "> clojure" cmd) + (clojure {:extra-env {"SCI_ELIDE_VARS" "true"}} cmd)) + (when building-outside-scittle? + (fs/delete "shadow-cljs.edn")))) + +(defn build + "Build scittle shadow builds using clojure cmd and commandline args. Features on + classpath are automatically added. + + Options: + + * :action - compile action, defaults to release, but may also be compile or watch" + [{:keys [action + args] :or {action "release"}}] + (build* (format "-M -m shadow.cljs.devtools.cli --force-spawn %s main %s" action (str/join " " args))) + (when (= "release" action) + (println "Also building dev release build") + (build* (format "-M -m shadow.cljs.devtools.cli --force-spawn %s main %s %s" + action + "--config-merge '{:compiler-options {:optimizations :simple + :pretty-print true + :pseudo-names true} + :output-dir \"resources/public/js/dev\" + :modules {:scittle.cljs-devtools {:entries [scittle.cljs-devtools] + :depends-on #{:scittle}}}}'" + (str/join " " args))))) diff --git a/deps.edn b/deps.edn new file mode 100644 index 0000000..8733a60 --- /dev/null +++ b/deps.edn @@ -0,0 +1,30 @@ +{:paths ["src" "resources"] + :deps + {org.clojure/clojure {:mvn/version "1.11.1"} + thheller/shadow-cljs {:mvn/version "3.1.8"} + org.babashka/sci {:git/url "https://github.com/babashka/sci" + :git/sha "756376056b32198d96dd5b272cee8fc483db60df"} + #_{:local/root "../babashka/sci"} + reagent/reagent {:mvn/version "1.1.1"} + no.cjohansen/replicant {:mvn/version "2025.03.27"} + re-frame/re-frame {:mvn/version "1.3.0"} + cljsjs/react {:mvn/version "18.2.0-1"} + cljsjs/react-dom {:mvn/version "18.2.0-1"} + cljsjs/react-dom-server {:mvn/version "18.2.0-1"} + cljs-ajax/cljs-ajax {:mvn/version "0.8.4"} + applied-science/js-interop {:mvn/version "0.4.2"} + funcool/promesa {:mvn/version "11.0.678"} + io.github.babashka/sci.nrepl + #_{:local/root "../sci.nrepl"} + {:git/url "https://github.com/babashka/sci.nrepl" + :git/sha "75f379c685bbd58c3e23f531339eb144e104937d"} + io.github.babashka/sci.configs + #_{:local/root "/Users/borkdude/dev/sci.configs"} + {:git/url "https://github.com/babashka/sci.configs" + :git/sha "aa84a1b4f1fe45735e5b748769309fc842f737c1" + :exclusions [org.babashka/sci]} + binaryage/devtools {:mvn/version "1.0.7"}} + :aliases + {:dev + {:extra-paths ["dev"] + :extra-deps {}}}} diff --git a/package.json b/package.json new file mode 100644 index 0000000..71d9dbd --- /dev/null +++ b/package.json @@ -0,0 +1,11 @@ +{ + "name": "scittle", + "version": "0.7.27", + "files": [ + "dist" + ], + "devDependencies": { + "react": "17.0.1", + "react-dom": "17.0.1" + } +} diff --git a/plugins/datascript/deps.edn b/plugins/datascript/deps.edn new file mode 100644 index 0000000..467f4cd --- /dev/null +++ b/plugins/datascript/deps.edn @@ -0,0 +1,4 @@ +{:deps + {datascript/datascript {:mvn/version "1.3.12"} + io.github.babashka/sci.configs {:git/sha "aa84a1b4f1fe45735e5b748769309fc842f737c1" + :exclusions [org.babashka/sci]}}} diff --git a/plugins/datascript/src/scittle/datascript.cljs b/plugins/datascript/src/scittle/datascript.cljs new file mode 100644 index 0000000..f3dac97 --- /dev/null +++ b/plugins/datascript/src/scittle/datascript.cljs @@ -0,0 +1,9 @@ +(ns scittle.datascript + {:no-doc true} + (:require [sci.configs.tonsky.datascript :refer [config]] + [scittle.core :as scittle])) + +(defn init [] + (scittle/register-plugin! + ::datascript + config)) diff --git a/plugins/datascript/src/scittle_plugin.edn b/plugins/datascript/src/scittle_plugin.edn new file mode 100644 index 0000000..09eae58 --- /dev/null +++ b/plugins/datascript/src/scittle_plugin.edn @@ -0,0 +1,12 @@ +[{:name scittle/datascript + :namespaces [datascript.core datascript.db] + :js "./scittle.datascript.js" + :shadow-config + {:compiler-options {:externs ["datascript/externs.js"]} + :modules + {:scittle.datascript + {:init-fn scittle.datascript/init + ;; From https://github.com/tonsky/datascript/issues/298#issuecomment-813790783 + :prepend "globalThis.datascript = {};" + :depends-on #{:scittle} + :entries [datascript.core]}}}}] diff --git a/plugins/dataspex/deps.edn b/plugins/dataspex/deps.edn new file mode 100644 index 0000000..badf11e --- /dev/null +++ b/plugins/dataspex/deps.edn @@ -0,0 +1,8 @@ +{:deps + {no.cjohansen/dataspex {:git/url "https://github.com/cjohansen/dataspex" + :git/sha "02112200651c2bd932907bb69fba1ff50b881741" + :exclusions [ring/ring-core + ring/ring-jetty-adapter + com.cognitect/transit-clj]} + io.github.babashka/sci.configs {:git/sha "aa84a1b4f1fe45735e5b748769309fc842f737c1" + :exclusions [org.babashka/sci]}}} diff --git a/plugins/dataspex/src/scittle/dataspex.cljs b/plugins/dataspex/src/scittle/dataspex.cljs new file mode 100644 index 0000000..66b3908 --- /dev/null +++ b/plugins/dataspex/src/scittle/dataspex.cljs @@ -0,0 +1,9 @@ +(ns scittle.dataspex + {:no-doc true} + (:require [sci.configs.cjohansen.dataspex :refer [config]] + [scittle.core :as scittle])) + +(defn init [] + (scittle/register-plugin! + ::dataspex + config)) diff --git a/plugins/dataspex/src/scittle_plugin.edn b/plugins/dataspex/src/scittle_plugin.edn new file mode 100644 index 0000000..af629e2 --- /dev/null +++ b/plugins/dataspex/src/scittle_plugin.edn @@ -0,0 +1,8 @@ +[{:name scittle/dataspex + :namespaces [dataspex.core] + :js "./scittle.dataspex.js" + :shadow-config + {:modules + {:scittle.dataspex {:init-fn scittle.dataspex/init + :depends-on #{:scittle :scittle.datascript} + :entries [dataspex.core]}}}}] diff --git a/plugins/demo/README.md b/plugins/demo/README.md new file mode 100644 index 0000000..7bd15f8 --- /dev/null +++ b/plugins/demo/README.md @@ -0,0 +1,29 @@ +# Demo + +A demo project of a custom scittle build. + +This demo project uses the `scittle.javelin` and `scittle.hoplon` plugins which aren't part of the normal scittle distribution. + +To produce release `.js` files, run: `bb release`. + +See: + +- `bb.edn` with + - `:deps` which includes: + - a dependency on the `scittle.build` project to build scittle + custom features + - zero or more plugin dependencies + - helpers like static file server + - development `:tasks`. Run `bb dev` for development and `bb release` to produce release artifacts. +- `deps.edn`: this only contains a dependency on scittle itself + +Available plugins are in the `plugins` directory inside the top level directory of this repo. + +Writing a plugin involves writing + +- SCI configuration (this can be shared via the [sci.configs](https://github.com/babashka/sci.configs) project too) +- Adding a `scittle_plugin.edn` file on the plugin's classpath (e.g. in the `src` directory). This EDN file contains: + - `:name`, name of the plugin + - `:namespaces`: the namespaces exposed to SCI + - `:js`: the name of the produced `.js` module file + - `:shadow-config`: the shadow-cljs configuration specific to this plugin +- A `.cljs` file with an `init` function which calls `scittle/register-plugin!`. diff --git a/plugins/demo/bb.edn b/plugins/demo/bb.edn new file mode 100644 index 0000000..e7486c2 --- /dev/null +++ b/plugins/demo/bb.edn @@ -0,0 +1,22 @@ +{:deps {io.github.babashka/scittle.build {:local/root "../../build"} + ;; datascript plugin + ; io.github.babashka/scittle.datascript {:local/root "../../plugins/datascript"} + io.github.babashka/scittle.dataspex {:local/root "../../plugins/dataspex"} + io.github.babashka/scittle.javelin {:local/root "../../plugins/javelin"} + io.github.babashka/scittle.hoplon {:local/root "../../plugins/hoplon"} + io.github.babashka/http-server + {:git/sha "b38c1f16ad2c618adae2c3b102a5520c261a7dd3"}} + :tasks + {:requires ([scittle.build :as build]) + watch {:doc "Watch build" + :task (build/build {:action "watch"})} + serve {:doc "Starts http server for serving static files" + :requires ([babashka.http-server :as http]) + :task (do (http/serve {:port 1341 :dir "resources/public"}) + (println "Serving static assets at http://localhost:1341"))} + -dev {:depends [watch serve]} + dev {:doc "Run compilation in watch mode and start http server" + :task (do (run '-dev {:parallel true}) + (deref (promise)))} + release {:doc "Release build (advanced compiled JS)" + :task (build/build {})}}} diff --git a/plugins/demo/deps.edn b/plugins/demo/deps.edn new file mode 100644 index 0000000..62915a5 --- /dev/null +++ b/plugins/demo/deps.edn @@ -0,0 +1 @@ +{:deps {io.github.babashka/scittle {:local/root "../.."}}} diff --git a/plugins/demo/resources/public/index.html b/plugins/demo/resources/public/index.html new file mode 100644 index 0000000..7f328cc --- /dev/null +++ b/plugins/demo/resources/public/index.html @@ -0,0 +1,21 @@ + + + + + + + + + + +

Hello Hoplon!

+ + diff --git a/plugins/demo/shadow-cljs.edn b/plugins/demo/shadow-cljs.edn new file mode 100644 index 0000000..47e5deb --- /dev/null +++ b/plugins/demo/shadow-cljs.edn @@ -0,0 +1,32 @@ +{:deps + {:aliases [:dev]} + + :dev-http + {8000 "classpath:public"} + + :builds + {:main + {:target :browser + :js-options + {:resolve {"react" {:target :global + :global "React"} + "react-dom" {:target :global + :global "ReactDOM"}}} + :modules + {:scittle {:entries [scittle.core]} + :scittle.nrepl {:entries [scittle.nrepl] + :depends-on #{:scittle}} + :scittle.promesa {:entries [scittle.promesa] + :depends-on #{:scittle}} + :scittle.pprint {:entries [scittle.pprint] + :depends-on #{:scittle}} + :scittle.reagent {:entries [scittle.reagent] + :depends-on #{:scittle}} + :scittle.re-frame {:entries [scittle.re-frame] + :depends-on #{:scittle.reagent + :scittle}} + :scittle.cljs-ajax {:entries [scittle.cljs-ajax] + :depends-on #{:scittle}}} + :build-hooks [(shadow.cljs.build-report/hook)] + :output-dir "resources/public/js" + :devtools {:repl-pprint true}}}} diff --git a/plugins/hoplon/deps.edn b/plugins/hoplon/deps.edn new file mode 100644 index 0000000..0eab577 --- /dev/null +++ b/plugins/hoplon/deps.edn @@ -0,0 +1,4 @@ +{:deps + {hoplon/hoplon {:mvn/version "7.5.0"} + io.github.babashka/sci.configs {:git/sha "aa84a1b4f1fe45735e5b748769309fc842f737c1" + :exclusions [org.babashka/sci]}}} diff --git a/plugins/hoplon/src/scittle/hoplon.cljs b/plugins/hoplon/src/scittle/hoplon.cljs new file mode 100644 index 0000000..46e5a3b --- /dev/null +++ b/plugins/hoplon/src/scittle/hoplon.cljs @@ -0,0 +1,9 @@ +(ns scittle.hoplon + {:no-doc true} + (:require [sci.configs.hoplon.hoplon :refer [config]] + [scittle.core :as scittle])) + +(defn init [] + (scittle/register-plugin! + ::hoplon + config)) diff --git a/plugins/hoplon/src/scittle/javelin.cljs b/plugins/hoplon/src/scittle/javelin.cljs new file mode 100644 index 0000000..7334a2d --- /dev/null +++ b/plugins/hoplon/src/scittle/javelin.cljs @@ -0,0 +1,9 @@ +(ns scittle.javelin + {:no-doc true} + (:require [sci.configs.hoplon.javelin :refer [config]] + [scittle.core :as scittle])) + +(defn init [] + (scittle/register-plugin! + ::javelin + config)) diff --git a/plugins/hoplon/src/scittle_plugin.edn b/plugins/hoplon/src/scittle_plugin.edn new file mode 100644 index 0000000..5a9f8f6 --- /dev/null +++ b/plugins/hoplon/src/scittle_plugin.edn @@ -0,0 +1,13 @@ +[{:name scittle/hoplon + :namespaces [javelin.core + hoplon.core + hoplon.dom] + :js "./scittle.hoplon.js" + :shadow-config + {:modules + {:scittle.hoplon {:init-fn scittle.hoplon/init + :depends-on #{:scittle :scittle.javelin} + :entries [hoplon.core hoplon.dom]} + :scittle.javelin {:init-fn scittle.javelin/init + :depends-on #{:scittle} + :entries [javelin.core]}}}}] diff --git a/plugins/javelin/deps.edn b/plugins/javelin/deps.edn new file mode 100644 index 0000000..f4b4533 --- /dev/null +++ b/plugins/javelin/deps.edn @@ -0,0 +1,4 @@ +{:deps + {hoplon/javelin {:mvn/version "3.9.3"} + io.github.babashka/sci.configs {:git/sha "aa84a1b4f1fe45735e5b748769309fc842f737c1" + :exclusions [org.babashka/sci]}}} diff --git a/plugins/javelin/src/scittle/javelin.cljs b/plugins/javelin/src/scittle/javelin.cljs new file mode 100644 index 0000000..7334a2d --- /dev/null +++ b/plugins/javelin/src/scittle/javelin.cljs @@ -0,0 +1,9 @@ +(ns scittle.javelin + {:no-doc true} + (:require [sci.configs.hoplon.javelin :refer [config]] + [scittle.core :as scittle])) + +(defn init [] + (scittle/register-plugin! + ::javelin + config)) diff --git a/plugins/javelin/src/scittle_plugin.edn b/plugins/javelin/src/scittle_plugin.edn new file mode 100644 index 0000000..c34873f --- /dev/null +++ b/plugins/javelin/src/scittle_plugin.edn @@ -0,0 +1,8 @@ +[{:name scittle/javelin + :namespaces [javelin.core] + :js "./scittle.javelin.js" + :shadow-config + {:modules + {:scittle.javelin {:init-fn scittle.javelin/init + :depends-on #{:scittle} + :entries [javelin.core]}}}}] diff --git a/japji/resources/audio/japji_bindranwale.mp3 b/resources/public/audio/japji_bindranwale.mp3 similarity index 100% rename from japji/resources/audio/japji_bindranwale.mp3 rename to resources/public/audio/japji_bindranwale.mp3 diff --git a/resources/public/cljs/bookmarklet.cljs b/resources/public/cljs/bookmarklet.cljs new file mode 100644 index 0000000..69d2169 --- /dev/null +++ b/resources/public/cljs/bookmarklet.cljs @@ -0,0 +1,140 @@ +(ns bookmarklet + (:require [reagent.core :as r] + [reagent.dom :as rdom])) + +(defn append-tag [tag {:keys [body onload onerror] :as attributes}] + (str "var s=document.createElement('" (name tag) "');" + (clojure.string/join ";" (map (fn [[k v]] (str "s.setAttribute('" (name k) "','" (name v) "')")) (dissoc attributes :body :onload :onerror))) + (when body + (str ";s.innerText=" body)) + (when onload + (str ";s.onload=" onload)) + (when onerror + (str ";s.onerror=" onerror)) + ";document.body.appendChild(s);")) + +(defn pr-code [code-str] + (pr-str (str "#_CODE_" code-str "#_CODE_"))) + +(defn read-code [code-str] + (when-let [raw-code (second (re-find #"#_CODE_(.+)#_CODE_" code-str))] + ;; Use read-string to undo escaping of characters by pr-str (e.g. newlines) + (read-string (str "\"" raw-code "\"")))) + +(defn load-gist [gist callback] + (let [set-content (fn [progress-event] + (callback (.. progress-event -srcElement -responseText))) + oreq (js/XMLHttpRequest.)] + (.addEventListener oreq "load" set-content) + (.open oreq "GET" (str "https://gist.githubusercontent.com/" gist "/raw")) + (.send oreq))) + + +(defn bookmarklet-href [code-str] + (str "javascript:(function(){" + "var runCode = function() { + try { + scittle.core.eval_string(" (pr-code code-str) ") + } catch (error) { + console.log('Error in code', error); + alert('Error running code, see console') + } + };" + "if(typeof scittle === 'undefined'){" + (append-tag :script {:src "https://babashka.github.io/scittle/js/scittle.js" + :onerror "function(){alert('Error loading ' + this.src)}" + :onload "runCode"}) + "} else { + runCode() }" + "})();")) + +(defn query-params [] + (let [query-str (.substring js/window.location.search 1)] + (into {} + (map (fn [pair] + (let [[k v] (.split pair "=" 2)] + [(keyword (js/decodeURIComponent k)) + (js/decodeURIComponent v)]))) + (.split query-str "&")))) + + +(def *initial-name (r/atom nil)) +(def *initial-code (r/atom nil)) + +;; Initialize code +(let [{:keys [gist code name]} (query-params)] + (cond gist + (do + (reset! *initial-name "---") + (reset! *initial-code ";; loading from gist") + (load-gist gist (fn [content] + (let [[code meta-str] (reverse (clojure.string/split content #";;---+\n")) + {bookmark-name :name} (when meta-str + (read-string meta-str))] + (when bookmark-name + (reset! *initial-name bookmark-name)) + (reset! *initial-code code))))) + code + (do + (reset! *initial-name (or name "My first bookmarklet")) + (reset! *initial-code code)) + :else + (do + (reset! *initial-name "My first bookmarklet") + (reset! *initial-code (str "; This is the code of your bookmarklet\n" + (pr-str '(js/alert "Hello"))))))) + +(defn bookmark-name-field [initial-name *bookmark-name] + (let [*name (r/atom initial-name)] + [(fn [] + [:input {:type "text" + :placeholder "The name of the Bookmarklet" + :value @*name + :on-change (fn [e] + (let [v (.. e -target -value)] + (reset! *name v) + (reset! *bookmark-name + (if (clojure.string/blank? v) + (str "Bookmarklet " (rand-int 1000)) + v))))}])])) + +(defn editor [*code] + [:textarea + {:rows 10 :cols 80 + :value @*code + :on-drop (fn [e] + (let [bookmarklet (js/decodeURIComponent (.. e -dataTransfer (getData "text"))) + cljs-snippet (read-code bookmarklet) + new-code (if cljs-snippet + (str "; Extracted snippet\n" cljs-snippet) + (str "; Failed to extract snippet\n" bookmarklet))] + (js/console.log "Dropped" bookmarklet) + (set! (.. e -target -value) new-code) + (reset! *code new-code) + (.preventDefault e))) + :on-change (fn [e] (reset! *code (.. e -target -value)))}]) + + + +(defn workspace [] + (let [value @*initial-code + *code (r/atom value) + bookmark-name @*initial-name + *bookmark-name (r/atom bookmark-name)] + [:div + [bookmark-name-field bookmark-name *bookmark-name] + [:br] + [editor *code] + [:br] + [:br] + "Click the following link or drag it to the bookmarks bar: " + [(fn [] + [(fn [] [:a {:href (bookmarklet-href @*code)} @*bookmark-name])]) + *code] + [:br] + [(fn [] + [:a {:href (str "?name=" (js/encodeURIComponent @*bookmark-name) + "&code=" (js/encodeURIComponent @*code) + "%20")} "Copy this link to share ⤴️"])]])) + +(rdom/render [workspace] (.getElementById js/document "app")) diff --git a/resources/public/cljs/codemirror.cljs b/resources/public/cljs/codemirror.cljs new file mode 100644 index 0000000..db28746 --- /dev/null +++ b/resources/public/cljs/codemirror.cljs @@ -0,0 +1,56 @@ +(require '[clojure.string :as str]) +(declare cm) + +(defn eval-me [] + (js/scittle.core.eval_string (-> cm .-state .-doc .toString))) + +(def extension + (.of js/cv.keymap + (clj->js [{:key "Mod-Enter" + :run (fn [] + (eval-me))} + #_{:key (str modifier "-Enter") + :shift (partial eval-top-level on-result) + :run (partial eval-at-cursor on-result)}]))) +(def cm + (let [doc (str/trim " +(require '[reagent.core :as r] + '[reagent.dom :as rdom] + '[re-frame.core :as rf]) + +(rf/reg-event-fx ::click (fn [{:keys [db]} _] {:db (update db :clicks (fnil inc 0))})) +(rf/reg-sub ::clicks (fn [db] (:clicks db))) + +(defn my-component [] + (let [clicks (rf/subscribe [::clicks])] + [:div + [:p \"Clicks: \" @clicks] + [:p [:button {:on-click #(rf/dispatch [::click])} + \"Click me!\"]]])) + +(rdom/render [my-component] (.getElementById js/document \"reagent\")) +")] + (js/cm.EditorView. #js {:doc doc + :extensions #js [js/cm.basicSetup, (js/lc.clojure), (.highest js/cs.Prec extension)] + :parent (js/document.querySelector "#app") + #_#_:dispatch (fn [tr] (-> cm (.update #js [tr])) (eval-me)) + }))) +(set! (.-eval_me js/globalThis) eval-me) +(set! (.-cm_instance js/globalThis) cm) + +(defn linux? [] + (some? (re-find #"(Linux)|(X11)" js/navigator.userAgent))) + +(defn mac? [] + (and (not (linux?)) + (some? (re-find #"(Mac)|(iPhone)|(iPad)|(iPod)" js/navigator.platform)))) + +(let [elt (js/document.getElementById "evalMe") + txt (.-innerText elt) + mod-symbol (if (mac?) + "⌘" + "⌃") + txt (str txt " " mod-symbol"-⏎")] + (set! (.-innerHTML elt) txt)) + +(eval-me) diff --git a/resources/public/cljs/nrepl_playground.cljs b/resources/public/cljs/nrepl_playground.cljs new file mode 100644 index 0000000..2c71307 --- /dev/null +++ b/resources/public/cljs/nrepl_playground.cljs @@ -0,0 +1,15 @@ +(ns nrepl-playground) + +(+ 1 2 3) + +(-> + (js/document.getElementsByTagName "body") + first + (.append + (doto (js/document.createElement "p") + (.append + (js/document.createTextNode "there"))))) + +(defn foo []) + +(js/alert "Isn't this cool? :)") diff --git a/resources/public/cljs/replicant_tictactoe/core.cljs b/resources/public/cljs/replicant_tictactoe/core.cljs new file mode 100644 index 0000000..b5ad81f --- /dev/null +++ b/resources/public/cljs/replicant_tictactoe/core.cljs @@ -0,0 +1,33 @@ +;; COPIED FROM https://github.com/cjohansen/replicant-tic-tac-toe/blob/7a33fb12f0cd6658b2f555ff673dee031d4aa921/src/tic_tac_toe/core.cljs + +(ns replicant-tictactoe.core + (:require [replicant.dom :as r] + [replicant-tictactoe.game :as game] + [replicant-tictactoe.ui :as ui])) + +(defn start-new-game [store] + (reset! store (game/create-game {:size 3}))) + +(defn main [] + ;; Set up the atom + (let [store (atom nil) + el (js/document.getElementById "app")] + + ;; Globally handle DOM events + (r/set-dispatch! + (fn [_ [action & args]] + (case action + :tic (apply swap! store game/tic args) + :reset (start-new-game store)))) + + ;; Render on every change + (add-watch store ::render + (fn [_ _ _ game] + (->> (ui/game->ui-data game) + ui/render-game + (r/render el)))) + + ;; Trigger the first render by initializing the game. + (start-new-game store))) + +(main) diff --git a/resources/public/cljs/replicant_tictactoe/game.cljs b/resources/public/cljs/replicant_tictactoe/game.cljs new file mode 100644 index 0000000..3f62d7f --- /dev/null +++ b/resources/public/cljs/replicant_tictactoe/game.cljs @@ -0,0 +1,41 @@ +;; COPIED FROM https://github.com/cjohansen/replicant-tic-tac-toe/blob/7a33fb12f0cd6658b2f555ff673dee031d4aa921/src/tic_tac_toe/game.cljs + +(ns replicant-tictactoe.game) + +(defn create-game [{:keys [size]}] + {:next-player :x + :size size}) + +(def next-player {:x :o, :o :x}) + +(defn winner? [tics path] + (when (= 1 (count (set (map tics path)))) + path)) + +(defn get-winning-path [{:keys [size tics]} y x] + (or (winner? tics (mapv #(vector y %) (range 0 size))) + (winner? tics (mapv #(vector % x) (range 0 size))) + (when (= y x) + (winner? tics (mapv #(vector % %) (range 0 size)))))) + +(defn maybe-conclude [game y x] + (if-let [path (get-winning-path game y x)] + (-> (dissoc game :next-player) + (assoc :over? true + :victory {:player (get-in game [:tics [y x]]) + :path path})) + (let [tie? (= (count (:tics game)) (* (:size game) (:size game)))] + (cond-> game + tie? (dissoc :next-player) + tie? (assoc :over? true))))) + +(defn tic [game y x] + (let [player (:next-player game)] + (if (or (get-in game [:tics [y x]]) + (<= (:size game) x) + (<= (:size game) y)) + game + (-> game + (assoc-in [:tics [y x]] player) + (assoc :next-player (next-player player)) + (maybe-conclude y x))))) \ No newline at end of file diff --git a/resources/public/cljs/replicant_tictactoe/style.css b/resources/public/cljs/replicant_tictactoe/style.css new file mode 100644 index 0000000..7ec052a --- /dev/null +++ b/resources/public/cljs/replicant_tictactoe/style.css @@ -0,0 +1,50 @@ +/* COPIED from https://github.com/cjohansen/replicant-tic-tac-toe/blob/7a33fb12f0cd6658b2f555ff673dee031d4aa921/resources/public/styles.css */ +.cell { + aspect-ratio: 1 / 1; + background: rgba(255, 255, 255, 0.8); + border-radius: 6%; + border: none; + display: block; + flex: 1 1 0%; + outline: none; + position: relative; + width: 100%; +} + +.cell-content { + opacity: 1; + transition: opacity 0.25s; +} + +.transparent { + opacity: 0; +} + +.cell-dim { + background: rgba(249, 249, 240, 0.3); +} + +.cell-highlight { + background: #fcfcf3; +} + +.clickable { + cursor: pointer; +} + +.board { + --gap: 0.75rem; + background: #833ab4; + background: linear-gradient(90deg, #833ab4 0%, #fd1d1d 50%, #fcb045 100%); + display: flex; + flex-direction: column; + gap: var(--gap); + padding: var(--gap); + max-width: 80vh; +} + +.row { + display: flex; + flex-direction: row; + gap: var(--gap); +} \ No newline at end of file diff --git a/resources/public/cljs/replicant_tictactoe/ui.cljs b/resources/public/cljs/replicant_tictactoe/ui.cljs new file mode 100644 index 0000000..c53dc65 --- /dev/null +++ b/resources/public/cljs/replicant_tictactoe/ui.cljs @@ -0,0 +1,75 @@ +;; COPIED FROM https://github.com/cjohansen/replicant-tic-tac-toe/blob/7a33fb12f0cd6658b2f555ff673dee031d4aa921/src/tic_tac_toe/ui.cljs + +(ns replicant-tictactoe.ui) + +(def mark-x + [:svg {:xmlns "http://www.w3.org/2000/svg" + :viewBox "0 -10 108 100"} + [:path + {:fill "currentColor" + :d "m1.753 69.19.36-1.08q.35-1.09 1.92-2.97 1.58-1.87 3.85-3.84 2.29-1.97 4.6-3.54 2.31-1.57 4.93-3.24 2.62-1.66 4.65-2.9 2.04-1.23 3.91-2.27 1.87-1.05 3.98-2.31 2.11-1.27 4.12-2.5 2.01-1.24 4.33-2.51l4.6-2.52q2.27-1.25 4.84-2.86 2.56-1.62 5.03-3.09 2.47-1.47 4.5-2.88 2.03-1.4 3.82-2.82t3.81-3.47q2.01-2.06 3.7-3.51 1.69-1.46 3.47-3.03 1.77-1.57 4.01-3.69 2.24-2.11 4.13-3.7 1.89-1.58 3.93-2.97 2.04-1.39 4.05-2.49 2.01-1.11 5.26-2.54 3.24-1.44 4.48-1.46 1.24-.01 2.42.37 1.18.37 2.18 1.11 1 .74 1.71 1.75.71 1.02 1.06 2.21.34 1.19.3 2.43-.05 1.24-.5 2.39-.44 1.16-1.23 2.12-.79.95-1.84 1.61-1.05.65-2.26.94-1.21.28-2.44.16-1.23-.11-2.37-.62-1.13-.5-2.04-1.34-.91-.84-1.51-1.93-.6-1.08-.81-2.3-.22-1.22-.04-2.45.18-1.23.75-2.33.56-1.1 1.45-1.97.89-.86 2.01-1.4 1.11-.54 2.35-.69 1.23-.15 2.44.1t2.29.87q1.07.63 1.88 1.56.82.93 1.29 2.08.48 1.14.56 2.38.09 1.24-.23 2.44-.31 1.19-.99 2.23-.68 1.04-1.66 1.8-.98.76-2.15 1.18l-1.16.41-2.28 1.17q-2.28 1.18-4.38 2.7-2.1 1.51-4.2 3.44-2.1 1.92-4.18 3.7-2.08 1.77-3.9 3.44-1.81 1.68-3.41 3.13-1.6 1.46-3.38 3.09-1.79 1.62-3.44 2.97-1.66 1.34-3.53 2.4-1.88 1.06-4.17 2.65-2.3 1.6-4.79 2.74-2.48 1.14-4.98 2.71-2.5 1.57-4.51 2.47-2.01.9-3.99 1.87-1.98.97-3.88 2.02-1.91 1.05-4.38 2.34-2.46 1.28-4.94 2.53-2.47 1.25-4.48 2.38-2 1.12-3.96 2.14-1.95 1.01-3.83 1.99-1.89.98-4.37 2.05-2.48 1.06-2.96 2.01-.48.96-.78 1.49-.3.53-.71.97-.41.44-.92.77-.51.34-1.09.54-.57.2-1.17.25-.6.06-1.2-.03t-1.16-.32q-.56-.23-1.05-.59-.49-.35-.89-.82-.39-.46-.65-1.01-.27-.54-.4-1.14-.13-.59-.12-1.19.02-.6.18-1.19l.16-.59Z"}] + [:path + {:fill "currentColor" + :d "m28.099 4.991 2.69 1.97q2.69 1.96 4.5 3.22 1.8 1.28 4.54 3.46 2.74 2.18 4.57 3.89t3.38 3.72q1.54 2.02 2.88 4.3 1.34 2.28 2.83 4.46 1.48 2.18 2.63 4.14 1.15 1.96 2.74 4.07 1.59 2.1 3.59 4.19 1.99 2.08 4.23 4.48 2.24 2.4 3.7 4.04 1.47 1.64 2.91 3.23 1.44 1.59 3.08 3.58 1.64 1.99 3.51 4.08 1.87 2.09 3.55 3.77 1.69 1.68 4.1 3.51 2.42 1.83 3.9 2.58 1.48.74 2.14 1.34.66.6 1.15 1.33.5.74.8 1.57.31.84.4 1.72.1.88-.02 1.76-.12.88-.44 1.71-.33.82-.84 1.55-.51.72-1.19 1.3-.67.58-1.46.98-.79.41-1.65.61-.87.2-1.76.19-.88-.01-1.74-.24-.86-.22-1.64-.64-.78-.42-2.27-2.72-1.48-2.3-1.52-3.49-.03-1.19.31-2.33.35-1.14 1.04-2.11.69-.97 1.66-1.67.96-.7 2.1-1.05 1.14-.35 2.33-.32 1.19.02 2.31.43t2.05 1.15q.93.75 1.58 1.75.64 1 .93 2.15.29 1.16.2 2.35-.09 1.18-.56 2.28-.47 1.1-1.26 1.99-.79.88-1.83 1.47t-2.2.82q-1.17.23-2.35.07-1.19-.16-2.25-.68-1.07-.53-1.92-1.37-.84-.84-1.37-1.9-.54-1.07-.7-2.25-.17-1.18.06-2.35.22-1.17.8-2.21.58-1.04 1.47-1.84.88-.79 1.98-1.27 1.09-.47 2.28-.57 1.18-.1 2.34.18 1.16.29 2.16.93 1.01.63 1.76 1.56.74.93-.33-.26-1.07-1.18-.41-.58.66.59 1.15 1.33.5.74.8 1.57.31.83.4 1.72.1.88-.02 1.76-.12.88-.44 1.7-.33.83-.84 1.55-.51.73-1.19 1.31-.67.58-1.46.98-.79.41-1.65.61-.87.2-1.75.19-.89-.01-1.75-.24-.86-.22-1.64-.64-.78-.42-2.73-1.57-1.95-1.14-4.26-2.95-2.31-1.8-3.87-3.43-1.57-1.62-3.17-3.29-1.6-1.66-3.55-4.05-1.95-2.39-3.33-4.15-1.39-1.76-2.77-3.4-1.38-1.64-3.07-3.56-1.7-1.91-3.91-4.13-2.2-2.22-3.74-4.1-1.54-1.88-2.79-3.75-1.24-1.87-2.4-4.33t-2.39-4.46q-1.23-2.01-2.4-4.59-1.17-2.59-2.53-5.01-1.36-2.43-3.35-4.44-1.99-2.02-4.52-4.27-2.54-2.25-5.33-4.04-2.81-1.79-3.28-2.21-.47-.41-.83-.92-.35-.51-.58-1.1-.22-.58-.3-1.2-.08-.62-.01-1.23.08-.62.29-1.21.22-.58.58-1.1.35-.51.81-.93.47-.42 1.02-.71t1.16-.45q.61-.15 1.23-.15t1.22.14q.61.15 1.17.44l.55.28Z"}]]) + +(def mark-o + [:svg {:xmlns "http://www.w3.org/2000/svg" + :viewBox "0 0 114 114"} + [:path + {:fill "none" + :stroke "currentColor" + :stroke-linecap "round" + :stroke-width "6" + :d "M74.616 8.935c7.73 2.38 15.96 9.34 21.58 16.04 5.63 6.69 10.57 15.46 12.18 24.11 1.6 8.65.74 19.67-2.53 27.77-3.27 8.11-10.12 15.37-17.09 20.88-6.98 5.51-16.07 10.81-24.76 12.17-8.7 1.35-19.32-.76-27.42-4.06-8.1-3.29-15.73-8.93-21.21-15.73-5.48-6.81-10.32-16.5-11.67-25.09-1.35-8.6.19-18.39 3.57-26.51 3.38-8.11 9.99-16.6 16.71-22.19 6.72-5.59 13.95-10.52 23.63-11.36 9.68-.84 28.04 4.34 34.45 6.32 6.42 1.97 4.37 4.6 4.04 5.55m-48.33-9.69c7.65-3.32 19.78-3.63 28.63-2.01 8.86 1.63 17.85 5.89 24.49 11.76 6.64 5.87 12.7 15.08 15.37 23.48 2.67 8.41 2.5 18.4.65 26.95-1.85 8.54-5.98 17.59-11.77 24.34-5.78 6.74-14.56 13.05-22.93 16.11-8.37 3.06-18.75 4.19-27.29 2.25-8.54-1.93-17.37-7.89-23.96-13.87-6.59-5.97-12.89-13.58-15.57-21.96-2.69-8.39-2.31-19.94-.56-28.34 1.75-8.4 5.21-15.74 11.06-22.09 5.85-6.35 19.92-13.32 24.04-16.01 4.12-2.7.37-1.1.67-.16"}]]) + +(defn render-cell [{:keys [content on-click dim? highlight? clickable?]}] + [:button.cell + {:on {:click on-click} + :class (cond-> [] + dim? (conj "cell-dim") + highlight? (conj "cell-highlight") + clickable? (conj "clickable"))} + (when content + [:div.cell-content + {:replicant/mounting {:class "transparent"} + :replicant/unmounting {:class "transparent"}} + content])]) + +(defn render-board [{:keys [rows]}] + [:div.board + (for [row rows] + [:div.row + (for [cell row] + (render-cell cell))])]) + +(defn render-game [{:keys [board button]}] + [:div + (render-board board) + (when button + [:button {:on {:click (:on-click button)} + :style {:margin-top 20 + :font-size 20}} + (:text button)])]) + +(def player->mark + {:x mark-x + :o mark-o}) + +(defn game->ui-data [{:keys [size tics victory over?]}] + (let [highlight? (set (:path victory))] + {:button (when over? + {:text "Start over" + :on-click [:reset]}) + :board + {:rows + (for [y (range size)] + (for [x (range size)] + (if-let [player (get tics [y x])] + (let [victorious? (highlight? [y x])] + (cond-> {:content (player->mark player)} + victorious? (assoc :highlight? true) + (and over? (not victorious?)) (assoc :dim? true))) + (if over? + {:dim? true} + {:clickable? true + :on-click [:tic y x]}))))}})) \ No newline at end of file diff --git a/resources/public/cljs/script.cljs b/resources/public/cljs/script.cljs new file mode 100644 index 0000000..27b8b45 --- /dev/null +++ b/resources/public/cljs/script.cljs @@ -0,0 +1,2 @@ +(defn my-alert2 [] + (js/alert "My alert 2!")) diff --git a/resources/public/cljs/tictactoe.cljs b/resources/public/cljs/tictactoe.cljs new file mode 100644 index 0000000..d348658 --- /dev/null +++ b/resources/public/cljs/tictactoe.cljs @@ -0,0 +1,85 @@ +(ns tictactoe + "Ported from https://github.com/borkdude/tictactoe-cljs" + (:require [reagent.core :as r] + [reagent.dom :as rdom])) + +(def empty-board [[\- \- \-] + [\- \- \-] + [\- \- \-]]) + +(def state (r/atom {:board empty-board :player \X})) + +(defn get-board-cell + ([board row col] + (get-in board [row col]))) + +(defn get-player [app-state] + (-> app-state :game-state :player)) + +(defn other-player [player] + (if (= player \X) \O \X)) + +(defn winner-in-rows? [board player] + (boolean (some (fn [row] (every? (fn [c] (= c player)) row)) board))) + +(defn transposed-board [board] + (vec (apply map vector board))) + +(defn winner-in-cols? [board player] + (winner-in-rows? (transposed-board board) player)) + +(defn winner-in-diagonals? [board player] + (let [diag-coords [[[0 0] [1 1] [2 2]] + [[0 2] [1 1] [2 0]]]] + (boolean (some (fn [coords] + (every? (fn [coord] + (= player (apply get-board-cell board coord))) + coords)) + diag-coords)))) + +(defn winner? + "checks if there is a winner. when called with no args, checks for player X and player O. +returns the character for the winning player, nil if there is no winner" + ([board] + (boolean (or (winner? board \X) + (winner? board \O)))) + ([board player] + (when (or (winner-in-rows? board player) + (winner-in-cols? board player) + (winner-in-diagonals? board player)) + player))) + +(defn full-board? + [board] + (let [all-cells (apply concat board)] + (not-any? #(= % \-) all-cells))) + +(defn new-state [old-state row col] + (if (and (= (get-board-cell (:board old-state) row col) \-) + (not (winner? (:board old-state)))) + {:board (assoc-in (:board old-state) [row col] (:player old-state)) + :player (other-player (:player old-state))} + old-state)) + +(defn tictactoe [] + [:div + (if (winner? (:board @state)) + (str "The winner is " (other-player (:player @state))) + (if (full-board? (:board @state)) + "It's a draw" + (str "Your turn, player " (:player @state)))) + (let [board (-> @state :board)] + [:table + [:tbody + (map-indexed + (fn [i row] + ^{:key i} + [:tr + (map-indexed (fn [j elt] + ^{:key j} + [:td {:on-click (fn [] + (swap! state new-state i j))}elt]) + row)]) + board)]])]) + +(rdom/render [tictactoe] (.getElementById js/document "app")) diff --git a/japji/resources/css/style.css b/resources/public/css/style.css similarity index 100% rename from japji/resources/css/style.css rename to resources/public/css/style.css diff --git a/japji/resources/data/japji-nihung-timings.edn b/resources/public/data/japji-nihung-timings.edn similarity index 100% rename from japji/resources/data/japji-nihung-timings.edn rename to resources/public/data/japji-nihung-timings.edn diff --git a/japji/resources/data/japji-nihung-timings.json b/resources/public/data/japji-nihung-timings.json similarity index 100% rename from japji/resources/data/japji-nihung-timings.json rename to resources/public/data/japji-nihung-timings.json diff --git a/japji/resources/fonts/NotoSansGurmukhi-Medium.ttf b/resources/public/fonts/NotoSansGurmukhi-Medium.ttf similarity index 100% rename from japji/resources/fonts/NotoSansGurmukhi-Medium.ttf rename to resources/public/fonts/NotoSansGurmukhi-Medium.ttf diff --git a/japji/resources/fonts/NotoSansGurmukhi-VariableFont_wdth,wght.ttf b/resources/public/fonts/NotoSansGurmukhi-VariableFont_wdth,wght.ttf similarity index 100% rename from japji/resources/fonts/NotoSansGurmukhi-VariableFont_wdth,wght.ttf rename to resources/public/fonts/NotoSansGurmukhi-VariableFont_wdth,wght.ttf diff --git a/japji/resources/fonts/README.md b/resources/public/fonts/README.md similarity index 100% rename from japji/resources/fonts/README.md rename to resources/public/fonts/README.md diff --git a/japji/resources/fonts/bulara_5.ttf b/resources/public/fonts/bulara_5.ttf similarity index 100% rename from japji/resources/fonts/bulara_5.ttf rename to resources/public/fonts/bulara_5.ttf diff --git a/japji/resources/fonts/bulara_6.ttf b/resources/public/fonts/bulara_6.ttf similarity index 100% rename from japji/resources/fonts/bulara_6.ttf rename to resources/public/fonts/bulara_6.ttf diff --git a/japji/resources/fonts/bulara_8.ttf b/resources/public/fonts/bulara_8.ttf similarity index 100% rename from japji/resources/fonts/bulara_8.ttf rename to resources/public/fonts/bulara_8.ttf diff --git a/japji/resources/fonts/bulara_9.ttf b/resources/public/fonts/bulara_9.ttf similarity index 100% rename from japji/resources/fonts/bulara_9.ttf rename to resources/public/fonts/bulara_9.ttf diff --git a/japji/resources/fonts/bularab5.ttf b/resources/public/fonts/bularab5.ttf similarity index 100% rename from japji/resources/fonts/bularab5.ttf rename to resources/public/fonts/bularab5.ttf diff --git a/japji/resources/fonts/bularah5.ttf b/resources/public/fonts/bularah5.ttf similarity index 100% rename from japji/resources/fonts/bularah5.ttf rename to resources/public/fonts/bularah5.ttf diff --git a/japji/resources/fonts/bularah7.ttf b/resources/public/fonts/bularah7.ttf similarity index 100% rename from japji/resources/fonts/bularah7.ttf rename to resources/public/fonts/bularah7.ttf diff --git a/japji/resources/fonts/bularao5.ttf b/resources/public/fonts/bularao5.ttf similarity index 100% rename from japji/resources/fonts/bularao5.ttf rename to resources/public/fonts/bularao5.ttf diff --git a/japji/resources/fonts/bularap5.ttf b/resources/public/fonts/bularap5.ttf similarity index 100% rename from japji/resources/fonts/bularap5.ttf rename to resources/public/fonts/bularap5.ttf diff --git a/resources/public/html/cljs-ajax.html b/resources/public/html/cljs-ajax.html new file mode 100644 index 0000000..e83446c --- /dev/null +++ b/resources/public/html/cljs-ajax.html @@ -0,0 +1,23 @@ + + + + + + + + + + diff --git a/resources/public/html/export.html b/resources/public/html/export.html new file mode 100644 index 0000000..a66f73b --- /dev/null +++ b/resources/public/html/export.html @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/resources/public/html/local.html b/resources/public/html/local.html new file mode 100644 index 0000000..d9c36bf --- /dev/null +++ b/resources/public/html/local.html @@ -0,0 +1,15 @@ + + + + + + + + + +
+ + diff --git a/resources/public/html/reagent.html b/resources/public/html/reagent.html new file mode 100644 index 0000000..f0f1468 --- /dev/null +++ b/resources/public/html/reagent.html @@ -0,0 +1,25 @@ + + + + + + + + + +
+ + diff --git a/japji/index.html b/resources/public/index.html similarity index 99% rename from japji/index.html rename to resources/public/index.html index 3c1250a..6fae6bf 100644 --- a/japji/index.html +++ b/resources/public/index.html @@ -7,13 +7,13 @@ - - + - + @@ -1723,7 +1723,7 @@ (def student-recordings (atom (apply vector (repeat (count data) nil)))) - (defn enable-play-button [phrase-no]) + (defn enable-play-button! [phrase-no]) (defn record-student-sound! [phrase-no] @@ -1732,10 +1732,10 @@ (try (.then (.getUserMedia (.mediaDevices js/navigator) {:audio true}) (fn [arg] - (let [media-recorder (MediaRecorder. arg) + (let [media-recorder (js/MediaRecorder. arg) audio-chunks (atom [])] (.start media-recorder) - (set! media-recorder onerror + (set! (.-onerror media-recorder) (fn [s] (.log js/console (str "Error while recording sound: " s)))) (.addEventListener media-recorder "dataavailable" @@ -1747,7 +1747,7 @@ (js/console.log "data available after MediaRecorder.stop() called.") (if (> (count @audio-chunks) 0) (do - ;; Store the blob in the student-sounds data structure + ;; Store the blob in the student-recordings data structure (swap! student-recordings assoc phrase-no (js/Blob. (clj->js @audio-chunks))) (enable-play-button! phrase-no)))))))) @@ -1801,7 +1801,7 @@ (defn play-student! [phrase-no] - (.play (js/Audio. (.createObjectURL js/URL (@student-sounds phrase-no))))) + (.play (js/Audio. (.createObjectURL js/URL (@student-recordings phrase-no))))) (defn animate-progress-bar! [id duration] @@ -1900,7 +1900,7 @@

Select words to hear them. Select the bullet • to hear the whole line. Select three dots ... to record your own voice.

- +
ਕ੍ਰਿਪਾ ਕਰਕੇ ਉਡੀਕ ਕਰੋ...