commit 9928b8a4878b4e1b27e6ce0b44dfda199d577246
parent 84b9da46983ece285801189ae7b613b074485d82
Author: massi <mdsiboldi@gmail.com>
Date: Wed, 31 Jul 2024 22:01:52 -0700
organization, disorganization, link fns
Diffstat:
8 files changed, 217 insertions(+), 55 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -4,4 +4,6 @@ build
**/*.draft
.cpcache
.nrepl-port
-node_modules
-\ No newline at end of file
+node_modules
+/cert.pem
+/key.pem
diff --git a/Makefile b/Makefile
@@ -22,7 +22,7 @@ build:
serve:
make clean
MW_ENV=dev make build
- http-server build -p 8080 & while true; do \
+ http-server build -p 8080 -S -C cert.pem & while true; do \
inotifywait @./build -qre close_write .; \
make clean; \
MW_ENV=dev make build; \
diff --git a/README.org b/README.org
@@ -0,0 +1,36 @@
+* massi-world 🌎
+It's my website. It's a work in progress. I'm building up a static
+site generator in clojure from the ground up becuse it's interesting
+and I've been meaning to use a lisp more. clojure is pretty cool so
+far.
+
+* Tips ‼
+** SSL on dev
+Run this in project root for ssl on dev server (so we can keep
+https:// hardcoded):
+
+=openssl req -newkey rsa:2048 -new -nodes -x509
+-days 3650 -keyout key.pem -out cert.pem=
+
+However, there's a warning about self-signing the cert and i'm not
+sure how to get that to go away.
+https://www.npmjs.com/package/http-server seems like it has some
+advice.
+
+** Publishing
+Edit =~/.ssh/config= like so the Makefile and your computer are in
+agreement about where to push.
+#+BEGIN_SRC
+Host mw
+ Hostname ssh.xyz.example.net
+ User xxx
+#+END_SRC
+
+* Notes ✍
+- Running make build will build using the prod env
+- Make serve will build using dev
+- To make a one-off dev build, run =MW_ENV=dev make build=
+
+* Todo 😴
+- Split out js in swatchbuckler
+- Finish the website
diff --git a/site/manifest.templ.json b/site/manifest.templ.json
@@ -2,10 +2,10 @@
"name": "massi world",
"icons": [
{
- "src": "@(web-root)/shared-assets/icon-192-192.png",
+ "src": "@(icon-192)",
"type": "image/png",
"sizes": "192x192"
}
],
- "start_url": "@(web-root)/index.html"
+ "start_url": "@(index-url)"
}
diff --git a/src/core.clj b/src/core.clj
@@ -5,11 +5,73 @@
[clojure.string :as cstr]))
(def WEB_ROOT (or (System/getenv "WEB_ROOT") ""))
-(println WEB_ROOT)
+
+(defn without-index [path-vec]
+ (if (= (last path-vec) "index.html")
+ (butlast path-vec)
+ path-vec))
+
+(defn dev?
+ ([] (dev? (or (System/getenv "MW_ENV") "")))
+ ([mw-env] (= "DEV" (cstr/upper-case mw-env))))
+
+(defn mk-path-fns [domain getspec]
+ (letfn [(p
+ ([rest-str]
+ (p rest-str (dev?)))
+ ([rest-str is-dev]
+ (str (if is-dev
+ (str "/" domain rest-str)
+ rest-str))))
+ (network-path
+ ([pg-key-or-spec]
+ (network-path pg-key-or-spec (dev?)))
+ ([pg-key-or-spec is-dev]
+ (->> pg-key-or-spec
+ getspec
+ :path
+ (into [domain])
+ (into (if is-dev ["localhost:8080"] []))
+ without-index
+ (cstr/join "/"))))
+ (url
+ ([pg-key-or-spec] (url pg-key-or-spec (dev?)))
+ ([pg-key-or-spec is-dev]
+ (str "https://" (network-path pg-key-or-spec is-dev))))
+ (path
+ ([pg-key-or-spec]
+ (path pg-key-or-spec (dev?)))
+ ([pg-key-or-spec is-dev]
+ (->> pg-key-or-spec
+ getspec
+ :path
+ without-index
+ (into (if is-dev [domain] []))
+ (cstr/join "/")
+ (str "/"))))
+ (outfile [pg-key-or-spec]
+ (->> pg-key-or-spec
+ getspec
+ :path
+ (into ["build" domain])
+ (cstr/join "/")))]
+ {:p p
+ :p-network-path network-path
+ :p-url url
+ :p-out outfile
+ :p-path path}))
+
+
+(defn inject-path-fns [domain getspec]
+ (doseq [[k v] (mk-path-fns domain getspec)]
+ (eval `(def ~(symbol k) ~v))))
(defn p [path] (str WEB_ROOT path))
+(defn mk-p [domain] (if (= (clojure.string/upper-case (or (System/getenv "MW_ENV") "")) "DEV")
+ (fn [path] (str "/" domain path))
+ identity))
-(defn base-head-stuff [ {:keys [path title desc img]}]
+(defn base-head-stuff [url {:keys [title desc img]}]
(list [:meta {:charset "UTF-8"}]
[:meta {:name "viewport"
:content "width=device-width"
@@ -23,14 +85,15 @@ document.documentElement.classList.add('js');")]
[:meta {:property "og:image:alt" :content (get img :desc)}]
[:meta {:property "og:locale" :content "en_US"}]
[:meta {:property "og:type" :content "website"}]
- [:meta {:property "og:url" :content path}]
+ [:meta {:property "og:url" :content url}]
[:meta {:name "theme-color" :content "#000033"}]
- [:link {:rel "canonical" :href path}]))
+ [:link {:rel "canonical" :href url}]))
-(defn massi-world-domain-stuff [{:or {img {:src "https://massi.world/shared-assets/icon-180-180.png"
+;; todo figure out how to thread project-specific p stuff into this.
+(defn massi-world-domain-stuff [url p {:or {img {:src "https://massi.world/shared-assets/icon-180-180.png"
:desc "an undiscovered planet."}}
:as argmap}]
- (concat (base-head-stuff argmap)
+ (concat (base-head-stuff url argmap)
(list [:link {:rel "shortcut icon" :href (p "/favicon.ico")}]
[:link {:rel "icon" :type "image/png" :sizes "16x16" :href (p "/shared-assets/icon-16-16.png")}]
[:link {:rel "icon" :type "image/png" :sizes "32x32" :href (p "/shared-assets/icon-32-32.png")}]
diff --git a/src/site.clj b/src/site.clj
@@ -5,21 +5,65 @@
[clojure.string :as cstr]
[core]))
-(defn site-header [argmap]
- (concat (core/massi-world-domain-stuff argmap)
- (list [:link {:rel "stylesheet" :href (core/p "/style.css")}]
- [:link {:rel "manifest" :href (core/p "/manifest.json")}])))
+(def domain "massi.world")
+(def pages {})
+(defn getspec [key-or-spec]
+ (if (map? key-or-spec)
+ key-or-spec
+ (if (nil? (pages key-or-spec))
+ (throw (Exception. (str "ensure check failed! page " key-or-spec " not found.")))
+ (pages key-or-spec))))
-(defn with-page [argmap & body]
+(core/inject-path-fns domain getspec)
+
+(defn test-path [pgkey]
+ (println)
+ (println (str "paths for " pgkey ":\n"))
+ (letfn [(mypp [obj]
+ (doseq [[k v] obj]
+ (println (str " " k))
+ (println (str " " v)))
+ )]
+ (println "dev:")
+ (mypp {:p (p "/is/a/path.txt" true)
+ :network-path (p-network-path pgkey true)
+ :url (p-url pgkey true)
+ :path (p-path pgkey true)})
+
+ (println "prod:")
+ (mypp {:p (p "/is/a/path.txt")
+ :network-path (p-network-path pgkey)
+ :url (p-url pgkey)
+ :path (p-path pgkey)})
+
+ (println "other:")
+ (mypp
+ {:outfile (p-out pgkey)})))
+
+(defn site-header [spec]
+ (concat (core/massi-world-domain-stuff (p-url spec) p spec)
+ (list [:link {:rel "stylesheet" :href (p "/style.css")}]
+ [:link {:rel "manifest" :href (p "/manifest.json")}])))
+
+(defn with-head [pg-key-or-spec & body]
(h/html (h/raw "<!DOCTYPE html>")
[:html.no-js
[:head
(site-header
- (merge argmap
- {:path (str "https://massi.world" (get argmap :path))}))]]
+ (merge (getspec pg-key-or-spec)
+ {:path (p-url pg-key-or-spec)}))]]
[:body (seq body)]))
+(defmacro defpage [key spec & render]
+ `(def pages
+ (merge pages
+ {~key (merge {:render
+ (fn []
+ (with-head ~spec
+ ~@render))} ~spec)})))
+
+
(defn header []
[:header "massi world 🦝"])
(defn footer []
@@ -28,17 +72,6 @@
(.format (java.text.SimpleDateFormat. "MM/dd/yyyy hh:mm:ssa z")
(new java.util.Date))])
-(defn mk-home [path]
- (with-page {:path path
- :title "massi world"
- :desc "home"}
- (header)
- [:section
- [:h1 "projects"]
- [:ul
- [:li [:a {:href (core/p "/projects/color-synth.html")} "color-synth"]]]
- (footer)]))
-
(defn mk-page [{:keys [path fn]}]
(let* [out-dir "build/massi.world"
out-file (str out-dir path)
@@ -51,7 +84,8 @@
(defn build-manifest []
(core/process-templ "site/manifest.templ.json"
"build/massi.world/manifest.json"
- {:web-root core/WEB_ROOT})
+ {:icon-192 (p "/shared-assets/icon-192-192.png")
+ :index-url (p-url :home)})
(println "wrote manifest."))
(defn build-css []
@@ -60,6 +94,41 @@
{:web-root core/WEB_ROOT})
(println "wrote style.css"))
+(defn render-page [pgkey]
+ (let* [out-file (p-out pgkey)
+ out-str (str ((-> pgkey getspec :render)))]
+ (io/make-parents out-file)
+ (spit out-file out-str)
+ (println "wrote" out-file)))
+
+(defpage :home {:path ["index.html"]
+ :title "massi world"
+ :desc "a website"}
+ (header)
+ [:section
+ [:h1 "projects"]
+ [:ul
+ [:li [:a {:href (p-path :color-synth)} "color-synth"]]]]
+ (footer))
+
+(defpage :color-synth {:path ["projects"
+ "color-synth.html"]
+ :title "color-synth"
+ :desc "a modular digital video synthesizer on the web"}
+ (header)
+ [:main.color-synth
+ [:div.md (core/md "site/md/color-synth.templ.md"
+ {:samples [:div.samples
+ [:img {:src (p "/assets/color-synth-sample-1.webp")
+ :alt "a pixelated wobbling smiley face"}]
+ [:img {:src (p "/assets/color-synth-sample-2.webp")
+ :alt "jagged vibrant waves"}]
+ [:img {:src (p "/assets/color-synth-sample-3.webp")
+ :alt "a complicated animation. fuzzy, sharp, and checkered"}]
+ [:img {:src (p "/assets/color-synth-sample-4.webp")
+ :alt "mellow swampy waves"}]]})]]
+ (footer))
+
;; _ arg is so we can call this with clj -X massi-world/build
;; _ is expected to be a map, and clojure complains if we don't accept it
(defn build [_]
@@ -67,23 +136,7 @@
(build-manifest)
(build-css)
(time
- (doseq [spec [{:path "/index.html" :fn mk-home}
- {:path "/projects/color-synth.html"
- :fn #(with-page {:path %
- :title "projects -> color-synth"
- :desc "a digital video synthesizer on the web"}
- (header)
- [:main.color-synth
- [:div.md (core/md "site/md/color-synth.templ.md"
- {:samples [:div.samples
- [:img {:src (core/p "/assets/color-synth-sample-1.webp")
- :alt "a pixelated wobbling smiley face"}]
- [:img {:src (core/p "/assets/color-synth-sample-2.webp")
- :alt "jagged vibrant waves"}]
- [:img {:src (core/p "/assets/color-synth-sample-3.webp")
- :alt "a complicated animation. fuzzy, sharp, and checkered"}]
- [:img {:src (core/p "/assets/color-synth-sample-4.webp")
- :alt "mellow swampy waves"}]]})]]
- (footer))}]]
- (mk-page spec))))
+ (doseq [pgkey (keys pages)]
+ (render-page pgkey))))
+(build nil)
diff --git a/src/swatchbuckler.clj b/src/swatchbuckler.clj
@@ -1,16 +1,25 @@
(ns swatchbuckler
(:require [core]))
+(def domain "swatchbuckler.massi.world")
+(core/inject-path-fns domain identity)
+
+(def spec {:path ["index.html"]
+ :title "swatchbuckler"
+ :desc "generate fg/bg pairs from a midtone"})
+
(defn build [_]
(core/process-templ
"swatchbuckler/index.templ.html"
"build/swatchbuckler.massi.world/index.html"
- {:head-content (core/massi-world-domain-stuff {:path "https://swatchbuckler.massi.world"
- :title "swatchbuckler"
- :desc "generate fg/bg pairs from a midtone"})})
+ {:head-content (core/massi-world-domain-stuff
+ (p-url spec)
+ p
+ spec)})
(println "wrote build/swatchbuckler.massi.world/index.html")
(core/process-templ
"swatchbuckler/manifest.templ.json"
"build/swatchbuckler.massi.world/manifest.json"
- {:web-root core/WEB_ROOT}))
+ {:icon-192 (p "/shared-assets/icon-192-192.png")
+ :index-url (p-url spec)}))
diff --git a/swatchbuckler/manifest.templ.json b/swatchbuckler/manifest.templ.json
@@ -2,10 +2,10 @@
"name": "swatchbuckler",
"icons": [
{
- "src": "@(web-root)/shared-assets/icon-192-192.png",
+ "src": "@(icon-192)",
"type": "image/png",
"sizes": "192x192"
}
],
- "start_url": "@(web-root)/index.html"
+ "start_url": "@(index-url)"
}