Skip to content

Instantly share code, notes, and snippets.

@exupero
Created June 5, 2023 12:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save exupero/469496ac7bb179199b8714d96bc2aae4 to your computer and use it in GitHub Desktop.
Save exupero/469496ac7bb179199b8714d96bc2aae4 to your computer and use it in GitHub Desktop.
#!/usr/bin/env bb
(require '[babashka.deps :as deps])
(deps/add-deps '{:deps {org.clojars.askonomm/ruuter {:mvn/version "1.3.2"}}})
(require '[clojure.java.browse :as browse]
'[clojure.string :as str]
'[cheshire.core :as json]
'[org.httpkit.server :as srv]
'[ruuter.core :as ruuter]
'[hiccup.core :as h])
(import '[java.net URLDecoder])
(defn re-map [re f s & ss]
(remove #{"" ::padding}
(interleave
(str/split s re)
(concat (apply map f (re-seq re s) ss) [::padding]))))
(defn render [dom & [status]]
{:status (or status 200)
:body (h/html dom)})
(def style
"body {max-width: 800px; margin: 0 auto}
body, textarea {font-size: 18pt; line-height: 1.5; font-family: 'PT Sans'}
section {margin-bottom: 2rem; display: flex}
ol {padding: 0 0 0 2.5rem; margin: 0 2rem 0 0}
strong {color: red}")
(defn template [dom]
(list
"<!DOCTYPE html>"
(h/html
[:head
[:meta {:charset "UTF-8"}]
[:meta {:content "width=device-width, initial-scale=1" :name "viewport"}]
[:title "Wish Lab Mad Lib"]
[:script {:src "https://unpkg.com/htmx.org@1.5.0/dist/htmx.min.js" :defer true}]
[:script {:src "https://unpkg.com/htmx.org@1.5.0/dist/ext/json-enc.js" :defer true}]
[:style {:type "text/css"} style]]
[:body
dom])))
(defn wordlist [s]
(map second (re-seq #"\[([^\]]+)\]" s)))
(defn selections []
[:textarea
{:name :selections
:hx-post "/madlib"
:hx-target "#madlib"
:hx-ext "json-enc"}])
(defn word-count [s]
(let [c (count (re-seq #"\[[^\[]+\]|[A-Za-z'-]+" s))]
[:em "(" c " words)"]))
(defn madlib-content
([s] (madlib-content s nil))
([s words]
[:div
(-> s
(str/replace #"___" "")
(as-> $ (re-map #"\[[^\[]+\]"
#(do [:strong (or %2 %1)])
$
(concat words (repeat nil)))))]))
(defn index [script-file _]
(let [s (slurp script-file)]
(render
(template
[:div
[:section
[:ol
(for [word (wordlist s)]
[:li word])]
(selections)]
[:section
[:div
(word-count s)
[:br]
[:div#madlib
(madlib-content s)]]]]))))
(defn madlib [script-file {:keys [body]}]
(let [s (slurp script-file)
{:keys [selections]} (json/parse-string (slurp body) true)
words (map str/trim (str/split-lines selections))]
(render
(madlib-content s words))))
(defn routes [script-file]
[{:path "/"
:method :get
:response (partial index script-file)}
{:path "/madlib"
:method :post
:response (partial madlib script-file)}])
(defonce server (atom nil))
(defn start-server [port routes]
(when-let [s @server]
(s :timeout 100)
(reset! server nil))
(let [s (srv/run-server #(ruuter/route (routes) %) {:port port})]
(reset! server s)))
(when (= *file* (System/getProperty "babashka.file"))
(let [[script-file] *command-line-args*
port 9999
url (str "http://localhost:" port "/")]
(start-server port #(routes script-file))
(println "serving" url)
(browse/browse-url url)
@(promise)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment