Refactor movement code to be more generic and easier to test.
continuous-integration/drone/push Build is failing Details

This commit is contained in:
Oliver 2026-03-25 13:36:19 +00:00
parent eed0874c2d
commit 0232946798
16 changed files with 422 additions and 209 deletions

View File

@ -19,8 +19,8 @@
:aliases {:dev {:extra-paths :aliases {:dev {:extra-paths
["components/ui-hiccup/src"] ["components/ui-hiccup/src"]
:extra-deps {thheller/shadow-cljs {:mvn/version "2.25.2"} :extra-deps {thheller/shadow-cljs {:mvn/version "2.25.2"}
cider/cider-nrepl {:mvn/version "0.50.2"} cider/cider-nrepl {:mvn/version "0.58.0"}
refactor-nrepl/refactor-nrepl {:mvn/version "3.10.0"} refactor-nrepl/refactor-nrepl {:mvn/version "3.11.3"}
cider/piggieback {:mvn/version "0.5.3"}}} cider/piggieback {:mvn/version "0.5.3"}}}
:test {:extra-paths ["test"] :test {:extra-paths ["test"]

View File

@ -135,8 +135,8 @@
(let [search (r/atom "")] (let [search (r/atom "")]
(fn [{:keys [sidebar body]}] (fn [{:keys [sidebar body]}]
[:div.h-100.flex.items-stretch [:div.h-100.flex.items-stretch
[:div.dn.db-l.pa3.bg-blue {:style {:flex-basis "20rem" :flex-grow "1"}} sidebar] #_[:div.dn.db-l.pa3.bg-blue {:style {:flex-basis "20rem" :flex-grow "1"}} sidebar]
[:div.ma3.pa3 {:style {:flex-basis "0" :flex-grow "999"}} #_[:div.ma3.pa3 {:style {:flex-basis "0" :flex-grow "999"}}
[ui-search search] [ui-search search]
body]]))) body]])))

View File

@ -0,0 +1,47 @@
(ns com.oly.static-sites.do-blog.pages.chess.board)
(defn calculate-black-white [pos]
(if (even? (first pos))
(if (even? (second pos))
:black :white)
(if (even? (second pos))
:white :black)))
(defn square-defaults [pos]
{:piece {}
:bg-colour (name (calculate-black-white pos))})
(defn create-board-data [size]
(loop [x-pos 1
y-pos 1
result []]
(if (> y-pos size) #_(and (= x-pos size))
result
(if (= size x-pos)
(recur 1
(inc y-pos)
(conj result [x-pos y-pos]))
(recur (inc x-pos)
y-pos
(conj result [x-pos y-pos]))))))
(defn create-board-data-map
([size] (create-board-data-map size square-defaults))
([size square-defaults-map]
(->> (create-board-data size)
(mapv #(vector % (square-defaults-map %)))
(into {}))))
(defn merge-board-piece
"Merge in piece changes at position"
[board position piece]
(update board position update :piece merge piece))
(comment
(create-board-data 5)
(create-board-data-map 5)
(-> (create-board-data-map 5)
(update-board-piece [1 1] {:type :pawn}))
)

View File

@ -1,4 +1,6 @@
(ns com.oly.static-sites.do-blog.pages.chess.movement) (ns com.oly.static-sites.do-blog.pages.chess.movement
(:require
[cljs.test :refer [deftest]]))
(defn get-square [pos game-state] (defn get-square [pos game-state]
(get game-state pos {})) (get game-state pos {}))
@ -7,62 +9,86 @@
[( + 1 (first (keep-indexed #(when (= (first chars) %2) %1) [\A \B "C" \D \E \F \G \H]))) [( + 1 (first (keep-indexed #(when (= (first chars) %2) %1) [\A \B "C" \D \E \F \G \H])))
(js/parseInt (second chars))]) (js/parseInt (second chars))])
(defn inside-grid-edge?
"Return true if x and y are inside the grid"
[size x y]
(let [board-size (+ 1 size)]
(and (and (< x board-size) (< y board-size))
(and (> x -1) (> y -1)))))
(defn outside-grid-edge?
"Return true if x and y are outside the grid"
[size x y]
(not (inside-grid-edge? size x y)))
(defn edge? (defn edge?
"Return true if x and are inside the grid" "Return true if x and y are inside the grid"
[[distance x y]] [[distance x y]]
(if (or (nil? distance) (= distance 1)) (if (or (nil? distance) (= distance 1))
true true
(and (and (< x 9) (< y 9)) (and (and (< x 9) (< y 9))
(and (> x 0) (> y 0))))) (and (> x 0) (> y 0)))))
(defn opposite-piece? [src-pos dest-pos board] (defn opposite-piece?
(prn (str "opposite piece" dest-pos)) "Check the board for a piece, and check its a different colour"
[src-pos dest-pos board]
(and (-> (get board dest-pos) :piece :type some?) (and (-> (get board dest-pos) :piece :type some?)
(not= (-> (get board src-pos) :piece :colour) (not= (-> (get board src-pos) :piece :colour)
(-> (get board dest-pos) :piece :colour)))) (-> (get board dest-pos) :piece :colour))))
(defn piece? (defn piece-at-destination?
"Is the destination spot a piece or empty square ?" "Is the destination spot a piece or empty square ?"
[src-pos dest-pos board] [src-pos dest-pos board]
(prn (str "piece" dest-pos))
(-> (get board dest-pos) :piece :type some?)) (-> (get board dest-pos) :piece :type some?))
(defn end-seq? [s] (defn end-seq?
"Check if its an empty sequence or the sequence has ended with a nil"
[s]
(if (empty? s) (if (empty? s)
false false
(nil? (last s)))) (nil? (last s))))
(defn identity-step [value _] value) (defn identity-step [value _] value)
(defn line-step
"Given if the move to the next position is valid"
[board size step x1 y1 x2 y2 cords]
(prn "1")
(if (outside-grid-edge? size x2 y2) #_(and
(piece-at-destination? [x1 y1] [x2 y2] board))
(do (prn "2") (conj cords nil))
(if (opposite-piece? [x1 y1] [x2 y2] board)
(do (prn "4") (conj cords nil))
(do (prn "3") (conj cords [step x2 y2]))
)))
(defn line-move (defn line-move
"Use the same function for horizontal vertical and diagonals "Use the same function for horizontal vertical and diagonals
We can abstract this because all the change is which axes we calculate on We can abstract this because all that change's is which axes we calculate on
Just adjust the x1-fn x2-fn y1-fn y2-fn fn's" Just adjust the x1-fn x2-fn y1-fn y2-fn fn's"
[[x y] size x1-fn y1-fn x2-fn y2-fn board] [[x y] size x1-fn y1-fn x2-fn y2-fn board]
(prn "line-move") (prn "move")
(loop [step 1 (loop [step 1
cords-set-one [] cords-set-one []
cords-set-two []] cords-set-two []]
;; nil at end of list indicates end of valid moves ;; nil at end of list indicates end of valid moves
(prn (concat
cords-set-one
cords-set-two))
(if (and (end-seq? cords-set-one) (if (and (end-seq? cords-set-one)
(end-seq? cords-set-two)) (end-seq? cords-set-two))
(concat cords-set-one cords-set-two) (concat
(drop-last cords-set-one)
(drop-last cords-set-two))
(recur (+ step 1) (recur (+ step 1)
(if (end-seq? cords-set-one) (if (end-seq? cords-set-one)
cords-set-one cords-set-one
(if (and (edge? [step (x1-fn x step) (y1-fn y step)]) (line-step board size step x y (x1-fn x step) (y1-fn x step) cords-set-one))
(piece? [x y] [(x1-fn x step) (y1-fn y step)] board))
(conj cords-set-one [step (x1-fn x step) (y1-fn y step)])
(conj cords-set-one
(when (opposite-piece? [x y] [(x1-fn x step) (y1-fn y step)] board)
[(x1-fn x step) (y1-fn y step)] nil) nil)))
(if (end-seq? cords-set-two) (if (end-seq? cords-set-two)
cords-set-two cords-set-two
(if (and (edge? [step (x2-fn x step) (y2-fn y step)]) (line-step board size step x y (x2-fn x step) (y2-fn x step) cords-set-two)
(piece? [x y] [(x2-fn x step) (y2-fn y step)] board)) )))))
(conj cords-set-two [step (x2-fn x step) (y2-fn y step)])
(conj cords-set-two nil)))))))
(defn line-horizontal [[x y] size board] (defn line-horizontal [[x y] size board]
(prn "horizontal") (prn "horizontal")
@ -126,22 +152,15 @@
[0 (- x 1) (- y 1)] [0 x (- y 1)] [0 (+ 1 x) (- y 1)]]) [0 (- x 1) (- y 1)] [0 x (- y 1)] [0 (+ 1 x) (- y 1)]])
(defn pawn-projection [[x y] direction size board] (defn pawn-projection [[x y] direction size board]
(prn "pawn diagonal") (concat [(when (opposite-piece? [x y] [(+ x 1) (+ y direction)] board)
(prn (piece? [x y] [(+ x 1) (+ y direction)] board)) [0 (+ x 1) (+ y direction)])
(prn (piece? [x y] [(- x 1) (+ y direction)] board)) (when (opposite-piece? [x y] [(- x 1) (+ y direction)] board)
#_(piece? [x y] [(+ x direction) y] board) [0 (- x 1) (+ y direction)])]
(prn (concat [(when (piece? [x y] [(+ x 1) (+ y direction)] board) [0 (+ x 1) (+ y direction)])
(when (piece? [x y] [(- x 1) (+ y direction)] board) [0 (- x 1) (+ y direction)])]
(if (or (= y 2) (= y 7))
[[0 x (+ y direction)] [1 x (+ y (* 2 direction))]]
[[0 x (+ y direction)]])))
(concat [(when (opposite-piece? [x y] [(+ x 1) (+ y direction)] board) [0 (+ x 1) (+ y direction)])
(when (opposite-piece? [x y] [(- x 1) (+ y direction)] board) [0 (- x 1) (+ y direction)])]
(if (or (= y 2) (= y 7)) (if (or (= y 2) (= y 7))
[[0 x (+ y direction)] [1 x (+ y (* 2 direction))]] [[0 x (+ y direction)] [1 x (+ y (* 2 direction))]]
[[0 x (+ y direction)]]))) [[0 x (+ y direction)]])))
(defn fetch-selected-piece-moves [[pos {:keys [piece]}] game-state] (defn fetch-selected-piece-moves [[pos {:keys [piece]}] game-state]
(case (:type piece) (case (:type piece)
:king (all-around-projection pos #_(:pos piece) 8) :king (all-around-projection pos #_(:pos piece) 8)

View File

@ -1,14 +1,12 @@
(ns com.oly.static-sites.do-blog.pages.chess.render (ns com.oly.static-sites.do-blog.pages.chess.render
(:require (:require
[com.oly.static-sites.do-blog.pages.chess.state :refer [game-state white-square black-square]] [com.oly.static-sites.do-blog.pages.chess.board
[com.oly.static-sites.do-blog.pages.chess.movement :refer [fetch-selected-piece-moves]])) :refer [calculate-black-white create-board-data-map]]
[com.oly.static-sites.do-blog.pages.chess.movement
(defn calculate-black-white [pos] :refer [fetch-selected-piece-moves]]
(if (even? (first pos)) [com.oly.static-sites.do-blog.pages.chess.state
(if (even? (second pos)) :refer
:black :white) [black-square game-state white-square]]))
(if (even? (second pos))
:white :black)))
(defn draw-square [pos pieces] (defn draw-square [pos pieces]
(let [square (calculate-black-white pos) (let [square (calculate-black-white pos)
@ -31,34 +29,8 @@
"black-80" "black-80"
"white-80"))))) "white-80")))))
(defn draw-board [pieces]
(loop [x 1
y 1
result []]
(if (>= x 8)
(if (>= y 8)
(conj result (draw-square [x y] pieces))
(recur 1 (+ 1 y) (conj result (draw-square [x y] pieces))))
(recur (+ 1 x) y (conj result (draw-square [x y] pieces))))))
(defn board-test [size]
(loop [x-pos 1
y-pos 1
result []]
(if (and (= x-pos size) (= y-pos size))
result
(if (= size x-pos)
(recur 1
(inc y-pos)
(conj result [x-pos y-pos]))
(recur (inc x-pos)
y-pos
(conj result [x-pos y-pos]))))))
(defn create-board [size square-defaults] (defn create-board [size square-defaults]
(->> (board-test size) (create-board-data-map size square-defaults))
(mapv #(vector % (square-defaults %)) )
(into {})))
(defn enhance-board [board on-click-fn] (defn enhance-board [board on-click-fn]
(reduce-kv (reduce-kv
@ -85,3 +57,6 @@
(str (if (= :white (:colour piece)) " white " " black")))})))) (str (if (= :white (:colour piece)) " white " " black")))}))))
board board
pieces)) pieces))
(comment (create-board 5))

View File

@ -1,15 +1,15 @@
(ns com.oly.static-sites.do-blog.pages.chess-board (ns com.oly.static-sites.do-blog.pages.chess-board
(:require (:require
[com.oly.static-sites.do-blog.pages.chess.board
:refer [square-defaults]]
[com.oly.static-sites.do-blog.pages.chess.movement [com.oly.static-sites.do-blog.pages.chess.movement
:refer [fetch-selected-piece-moves valid-move? chess-pos->coords ]] :refer [chess-pos->coords fetch-selected-piece-moves valid-move?]]
[com.oly.static-sites.do-blog.pages.chess.render [com.oly.static-sites.do-blog.pages.chess.render
:refer [calculate-black-white create-board enhance-board place-pieces-on-board]] :refer [create-board enhance-board place-pieces-on-board]]
[com.oly.static-sites.do-blog.pages.chess.state
[com.oly.static-sites.do-blog.pages.chess.state :refer [game-state start-state translate-char->piece find-piece]] :refer [find-piece game-state start-state translate-char->piece]]
[com.oly.static-sites.do-blog.pages.chess.vstate :as v :refer [viking-start-state]] [com.oly.static-sites.do-blog.pages.chess.vstate :as v]
[com.oly.static-sites.ui-hiccup.interface :refer [board]] [com.oly.static-sites.ui-hiccup.interface :refer [board]]))
[reagent.core :as r]))
;;/addwidget https://blog-test.digitaloctave.com/chess?widgetId=dochess ;;/addwidget https://blog-test.digitaloctave.com/chess?widgetId=dochess
;;/addwidget https://blog-test.digitaloctave.com/chess?roomI=!YOyzcCyoomnjylcOFP:matrix.org&widgetId=dochess ;;/addwidget https://blog-test.digitaloctave.com/chess?roomI=!YOyzcCyoomnjylcOFP:matrix.org&widgetId=dochess
@ -55,7 +55,8 @@
(defn site-startup [] (defn site-startup []
(prn "site start up") (prn "site start up")
(.addEventListener js/window "message" ;; experiment in matrix widget api
#_(.addEventListener js/window "message"
(fn [event] (fn [event]
(prn "message from element ") (prn "message from element ")
(.log js/console event) (.log js/console event)
@ -73,6 +74,7 @@
(prn "sending capabilities") (prn "sending capabilities")
(swap! widget assoc :widget-id (aget event "data" "widgetId")) (swap! widget assoc :widget-id (aget event "data" "widgetId"))
(send-to-parent "capabilities" :capabilities #js ["m.capability.screenshot"])) (send-to-parent "capabilities" :capabilities #js ["m.capability.screenshot"]))
"notify_capabilities" "notify_capabilities"
(do (do
(send-to-parent "capabilities" :capabilities #js ["m.capability.screenshot"])) (send-to-parent "capabilities" :capabilities #js ["m.capability.screenshot"]))
@ -133,61 +135,52 @@
(defonce test-event (setup)) (defonce test-event (setup))
(defn square-defaults [pos] (defn get-square [board-state pos]
{:piece {} (get @board-state [:board pos] {}))
:bg-colour (name (calculate-black-white pos))
#_(if (= (calculate-black-white pos) :black)
"bg-slate-200 black-80"
"bg-slate-800 white-80")})
(defn board-test [size]
(loop [x-pos 1
y-pos 1
result []]
(if (and (= x-pos size) (= y-pos size))
result
(if (= size x-pos)
(recur 1
(inc y-pos)
(conj result [x-pos y-pos]))
(recur (inc x-pos)
y-pos
(conj result [x-pos y-pos]))))))
(defn get-square [pos]
(get @game-state [:board pos] {}))
(defn reset-square (defn reset-square
([board pos] (reset-square board pos (square-defaults pos))) ([board pos] (reset-square board pos (square-defaults pos)))
([board pos value] ([board-state pos value]
(swap! board assoc-in [:board pos] value))) (prn "reset")
(prn pos)
(swap! board-state assoc-in [:board pos] value)))
(defn update-square [pos value] (defn update-square
(prn (str "update square " pos " " value)) ([pos value] (update-square game-state pos value))
(swap! game-state update-in [:board pos] ([board-state pos value]
merge #_(get-in @game-state [:board pos] {}) (prn (str "update square " pos " " value))
value)) (swap! board-state update-in [:board pos]
merge
value)))
(defn collisions [positions] (defn collisions [board-state positions]
(filterv (fn [[distance x y]] (filterv (fn [[distance x y]]
(let [piece (get-square [x y])] (let [piece (get-square board-state [x y])]
(prn (str "collision = " [x y] " - " (:type piece) " - " (:colour piece))) (prn (str "collision = " [x y] " - " (:type piece) " - " (:colour piece)))
(and (nil? (:type piece)) (and (nil? (:type piece))
(nil? (:colour piece))))) positions)) (nil? (:colour piece))))) positions))
(defn highlight-moves [pos] (defn highlight-moves
(prn "highlight") ([pos] (highlight-moves pos game-state))
(prn (fetch-selected-piece-moves ([pos board-state]
(first (filter (fn [[k v]] (:selected v)) (-> @game-state :board))) (prn "highlight moves")
(-> @game-state :board))) (->> (fetch-selected-piece-moves
(->> (fetch-selected-piece-moves (first (filter (fn [[k v]] (:selected v)) (-> @board-state :board)))
(first (filter (fn [[k v]] (:selected v)) (-> @game-state :board))) (-> @board-state :board))
(-> @game-state :board)) (mapv (fn [[distance x y]]
(mapv (fn [[distance x y]] (update-square
(update-square board-state
[x y] [x y]
{:highlight (str " bg-green-" (+ 2 distance) "00 ") {:highlight
:pos [x y]}))))) (case (+ 2 distance)
2 (str " bg-green-200 ")
3 (str " bg-green-300 ")
4 (str " bg-green-400 ")
5 (str " bg-green-500 ")
6 (str " bg-green-600 ")
7 (str " bg-green-700 ")
8 (str " bg-green-800 "))
:pos [x y]}))))))
(defn clear-keys [key] (defn clear-keys [key]
(swap! game-state (swap! game-state
@ -225,37 +218,46 @@
(-> @game-state :player-two))) (-> @game-state :player-two)))
(defn move-piece (defn move-piece
[selected-piece dest-square] ([selected-piece dest-square] (move-piece game-state selected-piece dest-square))
;; check the colours don't match can't land on our own piece ([board-state selected-piece dest-square]
(if (piece-attribute-match? selected-piece dest-square :colour) ;; check the colours don't match can't land on our own piece
nil (if (piece-attribute-match? selected-piece dest-square :colour)
(when nil
(valid-move? (:pos dest-square) (-> @game-state :board)) (when
(prn "--------------") (valid-move? (:pos dest-square) (-> @board-state :board))
(switch-player) (prn "--------------")
(when (take-piece? selected-piece dest-square) (switch-player)
(prn (str "taking " dest-square)) (when (take-piece? selected-piece dest-square)
(prn (str "taking " (:colour dest-square))) (prn (str "taking " dest-square))
(swap! game-state update (if (= :white (:colour selected-piece)) :player-one :player-two) conj dest-square)) (prn (str "taking " (:colour dest-square)))
(swap! board-state update (if (= :white (:colour selected-piece)) :player-one :player-two) conj dest-square))
(prn "#####") (prn "#####")
(update-square (:pos dest-square) (merge dest-square {:piece (assoc selected-piece :pos (:pos dest-square))})) (update-square
(reset-square game-state (:pos selected-piece) (square-defaults (:pos selected-piece)))))) (:pos dest-square)
(merge dest-square {:piece (assoc selected-piece :pos (:pos dest-square))}))
(reset-square board-state
(:pos selected-piece)
(square-defaults (:pos selected-piece)))))))
(defn click-square [evt p] (defn click-square
(let [[selected-pos {selected-piece :piece} #_selected-piece] (get-selected-square) ([evt p] (click-square game-state evt p))
clicked-square p] ([board-state evt p]
(clear-keys :highlight) (prn @game-state)
(when (piece-attribute-match? (current-player) selected-piece :colour) (let [[selected-pos {selected-piece :piece}] (get-selected-square)
(when selected-pos clicked-square p]
(prn "previously selected piece") (prn "click square")
(move-piece selected-piece clicked-square))) (clear-keys :highlight)
(when (piece-attribute-match? (current-player) selected-piece :colour)
(when selected-pos
(prn "previously selected piece")
(move-piece board-state selected-piece clicked-square)))
(clear-keys :selected) (clear-keys :selected)
(clear-keys :highlight) (clear-keys :highlight)
;; set new square as selected ;; set new square as selected
(update-square (:pos p) (assoc (get-square (:pos p)) :selected true)) (update-square board-state (:pos p) (assoc (get-square board-state (:pos p)) :selected true))
(highlight-moves (:pos p)))) (highlight-moves (:pos p) board-state))))
(defonce viking-chess-board-setup (defonce viking-chess-board-setup
(reset! v/game-state (reset! v/game-state
@ -267,8 +269,8 @@
:selected false} :selected false}
:board :board
(-> (create-board 11 square-defaults) (-> (create-board 11 square-defaults)
(enhance-board click-square) (enhance-board (partial click-square @game-state))
(place-pieces-on-board v/viking-start-state click-square))})) (place-pieces-on-board v/viking-start-state (partial click-square @game-state)))}))
(defn chess-board-setup [start-state] (defn chess-board-setup [start-state]
(reset! game-state (reset! game-state
@ -284,11 +286,6 @@
(place-pieces-on-board start-state click-square))})) (place-pieces-on-board start-state click-square))}))
(defn chess-page [{:keys [path-params query-params] :as route}] (defn chess-page [{:keys [path-params query-params] :as route}]
(prn route)
(prn (:pieces query-params))
(prn start-state)
(prn (chars->map (:pieces query-params)))
(if (:pieces query-params) (if (:pieces query-params)
(chess-board-setup (chars->map (:pieces query-params))) (chess-board-setup (chars->map (:pieces query-params)))
(chess-board-setup start-state)) (chess-board-setup start-state))
@ -315,6 +312,9 @@
[:div (board 11 (-> @v/game-state :board))]])) [:div (board 11 (-> @v/game-state :board))]]))
(comment (comment
(board-test 5)
(board 5 (-> @game-state :board))
(get-selected-square) (get-selected-square)
@game-state) @game-state)

View File

@ -30,12 +30,16 @@
[(get-else $ ?e :thumbnail :nil) ?thumbnail] [(get-else $ ?e :thumbnail :nil) ?thumbnail]
[?e :relative-path ?path]]}) [?e :relative-path ?path]]})
(defn check-match [re-patt title]
(prn re-patt)
(prn title)
(re-find re-patt title))
(defn db-search-filter (defn db-search-filter
"Add where clauses to the datalog query when supplied" "Add where clauses to the datalog query when supplied"
[{:keys [search tag]}] [{:keys [search tag]}]
(let [re-search (if (not (str/blank? search)) #_(js/RegEx (str "(?i)" search)) (let [re-search (if (not (str/blank? search)) #_(js/RegEx (str "(?i)" search))
(re-pattern (str "(?i)" search)) nil)] (re-pattern (str "(?i)" search)) nil)]
(prn re-search)
(cond-> db-search (cond-> db-search
(not (str/blank? tag)) (not (str/blank? tag))
(update-in [:where] #(conj % ['?e :tags tag])) (update-in [:where] #(conj % ['?e :tags tag]))

View File

@ -0,0 +1,2 @@
(ns com.oly.static-sites.portfolio.chess)

View File

@ -18,7 +18,7 @@
y-pos 1 y-pos 1
row [:div.h-8.md:h-12.lg:h-24] row [:div.h-8.md:h-12.lg:h-24]
result [:div]] result [:div]]
(if (and (= size (- y-pos 1)) (= size x-pos)) (if (> y-pos size )
result result
(if (= size x-pos) (if (= size x-pos)
(recur 1 (recur 1

View File

@ -1,28 +1,28 @@
{:paths ["development/src" "bases/portfolio/src" "bases/do-blog/src"] {:paths ["development/src" "bases/portfolio/src" "bases/do-blog/src"]
:deps {cjohansen/dumdom {:mvn/version "2023.11.06"} :deps {cjohansen/dumdom {:mvn/version "2023.11.06"}
org.clojure/clojurescript {:mvn/version "1.11.60"} org.clojure/clojurescript {:mvn/version "1.12.134"}
no.cjohansen/portfolio {:mvn/version "2026.03.1"}}
no.cjohansen/portfolio {:mvn/version "2023.07.15"}}
:aliases {:dev {:extra-paths ["development/src" "bases/portfolio/src" "bases/do-blog/src"] :aliases {:dev {:extra-paths ["development/src" "bases/portfolio/src" "bases/do-blog/src"]
:extra-deps {org.clojure/clojure {:mvn/version "1.10.3"} :extra-deps {org.clojure/clojure {:mvn/version "1.10.3"}
org.clojure/clojurescript {:mvn/version "1.11.60"} org.clojure/clojurescript {:mvn/version "1.12.134"}
org.clojure/tools.deps.alpha {:mvn/version "0.12.1003"} org.clojure/tools.deps.alpha {:mvn/version "0.12.1003"}
cljs-ajax/cljs-ajax {:mvn/version "0.8.4"} cljs-ajax/cljs-ajax {:mvn/version "0.8.4"}
;; dev libraries ;; dev libraries
thheller/shadow-cljs {:mvn/version "2.25.2"} thheller/shadow-cljs {:mvn/version "3.3.6"}
;;refactor-nrepl/refactor-nrepl {:mvn/version "3.9.0"} ;;refactor-nrepl/refactor-nrepl {:mvn/version "3.9.0"}
;;cider/cider-nrepl {:mvn/version "0.43.1"} ;;cider/cider-nrepl {:mvn/version "0.43.1"}
no.cjohansen/portfolio {:mvn/version "2023.07.15"} no.cjohansen/portfolio {:mvn/version "2026.03.1"}
djblue/portal {:mvn/version "0.48.0"}}} djblue/portal {:mvn/version "0.48.0"}}}
:blog {:extra-paths ["components/ui-hiccup/src" :blog {:extra-paths ["components/ui-hiccup/src"
"development/src" "bases/do-blog/src"] "development/src" "bases/do-blog/src"
"bases/do-blog/test"]
:extra-deps { :extra-deps {
org.clojure/core.async {:mvn/version "1.6.673"} org.clojure/core.async {:mvn/version "1.6.673"}
org.clojure/clojurescript {:mvn/version "1.11.60"} org.clojure/clojurescript {:mvn/version "1.12.134"}
reagent/reagent {:mvn/version "1.1.1"} reagent/reagent {:mvn/version "1.1.1"}
tick/tick {:mvn/version "0.5.0"} tick/tick {:mvn/version "0.5.0"}
@ -40,9 +40,9 @@
:shadow-cljs-run :shadow-cljs-run
{:extra-deps {thheller/shadow-cljs {:mvn/version "2.25.2"} {:extra-deps {thheller/shadow-cljs {:mvn/version "3.3.6"}
cider/cider-nrepl {:mvn/version "0.50.2"} cider/cider-nrepl {:mvn/version "0.58.0"}
refactor-nrepl/refactor-nrepl {:mvn/version "3.10.0"} refactor-nrepl/refactor-nrepl {:mvn/version "3.11.0"}
cider/piggieback {:mvn/version "0.5.3"}} cider/piggieback {:mvn/version "0.5.3"}}
:extra-paths ["dev" "bases/do-blog/src" "components/ui_hiccup/src"] :extra-paths ["dev" "bases/do-blog/src" "components/ui_hiccup/src"]
:main-opts ["-m" "shadow.cljs.devtools.cli"]} :main-opts ["-m" "shadow.cljs.devtools.cli"]}

View File

@ -546,35 +546,59 @@ video {
@tailwind forms; @tailwind forms;
.\!container {
width: 100% !important;
}
.container { .container {
width: 100%; width: 100%;
} }
@media (min-width: 640px) { @media (min-width: 640px) {
.\!container {
max-width: 640px !important;
}
.container { .container {
max-width: 640px; max-width: 640px;
} }
} }
@media (min-width: 768px) { @media (min-width: 768px) {
.\!container {
max-width: 768px !important;
}
.container { .container {
max-width: 768px; max-width: 768px;
} }
} }
@media (min-width: 1024px) { @media (min-width: 1024px) {
.\!container {
max-width: 1024px !important;
}
.container { .container {
max-width: 1024px; max-width: 1024px;
} }
} }
@media (min-width: 1280px) { @media (min-width: 1280px) {
.\!container {
max-width: 1280px !important;
}
.container { .container {
max-width: 1280px; max-width: 1280px;
} }
} }
@media (min-width: 1536px) { @media (min-width: 1536px) {
.\!container {
max-width: 1536px !important;
}
.container { .container {
max-width: 1536px; max-width: 1536px;
} }
@ -604,6 +628,14 @@ video {
position: relative; position: relative;
} }
.order-1 {
order: 1;
}
.order-2 {
order: 2;
}
.m-2 { .m-2 {
margin: 0.5rem; margin: 0.5rem;
} }
@ -652,6 +684,10 @@ video {
margin-right: 2rem; margin-right: 2rem;
} }
.mt-0 {
margin-top: 0px;
}
.mt-4 { .mt-4 {
margin-top: 1rem; margin-top: 1rem;
} }
@ -676,6 +712,10 @@ video {
display: flex; display: flex;
} }
.inline-flex {
display: inline-flex;
}
.table { .table {
display: table; display: table;
} }
@ -704,6 +744,10 @@ video {
height: 16rem; height: 16rem;
} }
.h-8 {
height: 2rem;
}
.h-96 { .h-96 {
height: 24rem; height: 24rem;
} }
@ -720,6 +764,10 @@ video {
width: 12rem; width: 12rem;
} }
.w-8 {
width: 2rem;
}
.w-96 { .w-96 {
width: 24rem; width: 24rem;
} }
@ -740,6 +788,10 @@ video {
flex-grow: 1; flex-grow: 1;
} }
.grow {
flex-grow: 1;
}
.skew-x-12 { .skew-x-12 {
--tw-skew-x: 12deg; --tw-skew-x: 12deg;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
@ -769,16 +821,40 @@ video {
flex-direction: column; flex-direction: column;
} }
.flex-wrap {
flex-wrap: wrap;
}
.items-center {
align-items: center;
}
.items-stretch {
align-items: stretch;
}
.justify-around {
justify-content: space-around;
}
.gap-4 { .gap-4 {
gap: 1rem; gap: 1rem;
} }
.overflow-auto {
overflow: auto;
}
.truncate { .truncate {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
} }
.rounded {
border-radius: 0.25rem;
}
.rounded-full { .rounded-full {
border-radius: 9999px; border-radius: 9999px;
} }
@ -800,6 +876,11 @@ video {
border-color: rgb(15 23 42 / var(--tw-border-opacity)); border-color: rgb(15 23 42 / var(--tw-border-opacity));
} }
.bg-black {
--tw-bg-opacity: 1;
background-color: rgb(0 0 0 / var(--tw-bg-opacity));
}
.bg-slate-200 { .bg-slate-200 {
--tw-bg-opacity: 1; --tw-bg-opacity: 1;
background-color: rgb(226 232 240 / var(--tw-bg-opacity)); background-color: rgb(226 232 240 / var(--tw-bg-opacity));
@ -810,6 +891,46 @@ video {
background-color: rgb(148 163 184 / var(--tw-bg-opacity)); background-color: rgb(148 163 184 / var(--tw-bg-opacity));
} }
.bg-white {
--tw-bg-opacity: 1;
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
}
.bg-green-200 {
--tw-bg-opacity: 1;
background-color: rgb(187 247 208 / var(--tw-bg-opacity));
}
.bg-green-300 {
--tw-bg-opacity: 1;
background-color: rgb(134 239 172 / var(--tw-bg-opacity));
}
.bg-green-400 {
--tw-bg-opacity: 1;
background-color: rgb(74 222 128 / var(--tw-bg-opacity));
}
.bg-green-500 {
--tw-bg-opacity: 1;
background-color: rgb(34 197 94 / var(--tw-bg-opacity));
}
.bg-green-600 {
--tw-bg-opacity: 1;
background-color: rgb(22 163 74 / var(--tw-bg-opacity));
}
.bg-green-700 {
--tw-bg-opacity: 1;
background-color: rgb(21 128 61 / var(--tw-bg-opacity));
}
.bg-green-800 {
--tw-bg-opacity: 1;
background-color: rgb(22 101 52 / var(--tw-bg-opacity));
}
.object-cover { .object-cover {
-o-object-fit: cover; -o-object-fit: cover;
object-fit: cover; object-fit: cover;
@ -889,6 +1010,10 @@ video {
text-transform: uppercase; text-transform: uppercase;
} }
.lowercase {
text-transform: lowercase;
}
.capitalize { .capitalize {
text-transform: capitalize; text-transform: capitalize;
} }
@ -916,6 +1041,10 @@ video {
text-decoration-line: underline; text-decoration-line: underline;
} }
.no-underline {
text-decoration-line: none;
}
.opacity-15 { .opacity-15 {
opacity: 0.15; opacity: 0.15;
} }
@ -926,6 +1055,10 @@ video {
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
} }
.outline {
outline-style: solid;
}
.ring { .ring {
--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);
--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color); --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);
@ -974,6 +1107,14 @@ video {
display: block; display: block;
} }
.md\:h-12 {
height: 3rem;
}
.md\:w-12 {
width: 3rem;
}
.md\:w-4\/5 { .md\:w-4\/5 {
width: 80%; width: 80%;
} }
@ -993,6 +1134,14 @@ video {
} }
@media (min-width: 1024px) { @media (min-width: 1024px) {
.lg\:h-24 {
height: 6rem;
}
.lg\:w-24 {
width: 6rem;
}
.lg\:w-4\/5 { .lg\:w-4\/5 {
width: 80%; width: 80%;
} }

View File

@ -1,30 +1,20 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html><head><title>portfolio.runner</title><meta charset="utf-8">
<head> <script src="https://cdn.tailwindcss.com"></script>
<title>Personal portfolio for olymk2</title> <style type="text/css" media="screen">
<meta charset="utf-8" /> #loading {
<meta content="#da532c" name="msapplication-TileColor" /> -webkit-animation: rotation 2s infinite linear;
<meta content="#ffffff" name="theme-color" /> }
<link
href="https://cdn.jsdelivr.net/gh/devicons/devicon@v2.15.1/devicon.min.css" @-webkit-keyframes rotation {
rel="stylesheet" from {
type="text/css" -webkit-transform: rotate(0deg);
/> }
<link
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" to {
rel="stylesheet" -webkit-transform: rotate(359deg);
type="text/css" }
/> }
<link rel="stylesheet" href="./css/styles.css" type="text/css" /> </style>
<meta content="Personal portfolio" property="og:title" />
<meta </head><body><script src="/js/portfolio.js"></script></body></html>
content="Portfolio of projects worked on past to present"
property="og:description"
/>
</head>
<body>
<div id="app"></div>
<script src="/cljs-out/base.js" type="application/javascript"></script>
<script src="/cljs-out/portfolio.js" type="application/javascript"></script>
</body>
</html>

View File

@ -2,6 +2,7 @@
(:require [portfolio.ui :as ui] (:require [portfolio.ui :as ui]
[portfolio.dumdom :as d] [portfolio.dumdom :as d]
[portfolio.dom :as r] [portfolio.dom :as r]
[blog.chess-scene :as chess]
[com.oly.static-sites.portfolio.page :as c])) [com.oly.static-sites.portfolio.page :as c]))
(d/defscene circle-flow (d/defscene circle-flow

View File

@ -11,3 +11,4 @@ clj -M:blog:shadow-cljs-run watch blog
docker build -t europe-west2-docker.pkg.dev/blog-9d51d/blog/caddy . docker build -t europe-west2-docker.pkg.dev/blog-9d51d/blog/caddy .
docker push europe-west2-docker.pkg.dev/blog-9d51d/blog/caddy docker push europe-west2-docker.pkg.dev/blog-9d51d/blog/caddy
clj -M:blog:shadow-cljs-run watch app ui blog blog-tests

View File

@ -2,14 +2,34 @@
:dev-http {8080 ["bases/do-blog/resources/public" "classpath:public"] :dev-http {8080 ["bases/do-blog/resources/public" "classpath:public"]
8081 ["development/resources/public/" "classpath:public"]} 8081 ["development/resources/public/" "classpath:public"]}
;:nrepl {:middleware [refactor-nrepl.middleware/wrap-refactor]} ;:nrepl {:middleware [refactor-nrepl.middleware/wrap-refactor]}
:nrepl {:middleware [refactor-nrepl.middleware/wrap-refactor]} ;;:nrepl {:middleware [refactor-nrepl.middleware/wrap-refactor]}
;; :source ["devlopment/src" "bases/portfolio/src"] ;;"src" ;; :source ["devlopment/src" "bases/portfolio/src"] ;;"src"
;; "../../components/web-ui/src" ;; "../../components/web-ui/src"
;; "../../components/web-api/src" ;; "../../components/web-api/src"
;; "../../components/polyculture/src" ;; "../../components/polyculture/src"
;; "../../components/svg-generation/src" ;; "../../components/svg-generation/src"
;; "../../components/local-store/src"] ;; "../../components/local-store/src"]
:builds {:app {:output-dir "bases/portfolio/resources/public/js" :builds {:ui {:output-dir "development/resources/public/js"
;:asset-path "."
:target :portfolio
:title "My UI components library"
;;:runner-ns blog.chess-scene
:portfolio.ui/config {
:css-paths ["/css/styles.css"
"https://unpkg.com/tachyons@4.12.0/css/tachyons.min.css"]}
:html-file {
:path "development/resources/public/portfolio.html"}
:compiler-options {:infer-externs :auto :output-feature-set :es6}
;; :modules {:base {:entries [com.oly.static-sites.portfolio.core]}
;; ;; :app {:init-fn com.oly.static-sites.portfolio.core/launch
;; ;; :depends-on #{:base}
;; ;; }
;; ;; :portfolio {;;:init-fn design/launch
;; ;; :depends-on #{:app}}
;; }
:devtools {:after-load app.main/reload!}}
:app {:output-dir "development/resources/public/js"
;:asset-path "." ;:asset-path "."
:target :browser :target :browser
:compiler-options {:infer-externs :auto :output-feature-set :es6} :compiler-options {:infer-externs :auto :output-feature-set :es6}
@ -30,4 +50,9 @@
} }
:devtools {:after-load app.main/reload!} :devtools {:after-load app.main/reload!}
} }
:blog-tests {:target :browser-test
:test-dir "development/resources/public/test/"
:ns-regexp "-test$"
:devtools {:http-port 8091
:http-root "development/resources/public/test"}}
}} }}

View File

@ -1,5 +1,5 @@
module.exports = { module.exports = {
content: ['./development/resources/public/**/*.{html,js}'], content: ['./development/resources/public/**/*.{html,js,cljs}'],
theme: { theme: {
extend: { extend: {
backgroundImage: { backgroundImage: {