Skip to content

Commit

Permalink
Merge branch 'master' into roman/expose-linter
Browse files Browse the repository at this point in the history
  • Loading branch information
roman01la authored Jan 28, 2023
2 parents f9d9a25 + 79eccb3 commit 977a7d3
Show file tree
Hide file tree
Showing 5 changed files with 293 additions and 3 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ yarn add [email protected] [email protected]
- [React DevTools](/docs/react-devtools.md)
- [Code linting](/docs/code-linting.md)
- [Utilities](/docs/utilities.md)
- [Examples](/core/dev/uix/examples.cljs)

## Testing

Expand Down
8 changes: 7 additions & 1 deletion core/deps.edn
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,10 @@
cljsjs/react-dom-server {:mvn/version "16.13.1-0"}
clj-diffmatchpatch/clj-diffmatchpatch {:mvn/version "0.0.9.3"}}}
:release {:extra-deps {appliedscience/deps-library {:mvn/version "0.3.4"}}
:main-opts ["-m" "deps-library.release"]}}}
:main-opts ["-m" "deps-library.release"]}

:examples {:extra-paths ["dev"]
:extra-deps {org.clojure/clojure {:mvn/version "1.10.3"}
org.clojure/clojurescript {:mvn/version "1.10.879"}
thheller/shadow-cljs {:mvn/version "2.15.5"}
uix.dom/uix.dom {:local/root "../dom"}}}}}
265 changes: 264 additions & 1 deletion core/dev/uix/examples.cljs
Original file line number Diff line number Diff line change
@@ -1 +1,264 @@
(ns uix.examples)
(ns uix.examples
(:require [uix.core :as uix :refer [$ defui]]
[uix.dom]
[uix.dev]))

;; dev setup
(uix.dev/init-fast-refresh!)

(defn ^:dev/after-load refresh []
(uix.dev/refresh!))

;; app code
(def tools [:rect :circle :text])

(defui tool-button [{:keys [selected? label on-press]}]
($ :div {:on-click on-press
:style {:padding "4px 8px"
:cursor :pointer
:border-radius 3
:color (when selected? "#fff")
:background-color (when selected? "#ff89da")}}
label))

(defui toolbar [{:keys [state set-state on-add-shape]}]
(let [{:keys [grid?]} state]
($ :div {:style {:padding "8px 16px"
:height 46
:display :flex
:align-items :center
:background-color "#fff"
:position :relative
:box-shadow "0 1px 1px rgba(0, 0, 10, 0.2)"}}
($ :img {:src "https://raw.githubusercontent.com/pitch-io/uix/master/logo.png"
:style {:height "100%"
:margin "0 16px 0 0"}})
(for [t tools]
($ tool-button {:key t :label (name t) :on-press #(on-add-shape t)}))
($ :div {:style {:width 1 :height "60%" :background-color "#c1cdd0" :margin "0 8px"}})
($ tool-button {:label "grid"
:selected? grid?
:on-press #(set-state (update state :grid? not))}))))

(def canvas-grid
(uix/memo
(uix/fn [{:keys [width height size color]}]
(let [wn (Math/ceil (/ width size))
hn (Math/ceil (/ height size))]
($ :<>
(for [widx (range wn)]
($ :line {:key widx
:x1 (* size widx)
:x2 (* size widx)
:y1 0
:y2 height
:stroke color}))
(for [hidx (range hn)]
($ :line {:key hidx
:y1 (* size hidx)
:y2 (* size hidx)
:x1 0
:x2 width
:stroke color})))))))

(defui cursor [{:keys [mx my r color]}]
(let [mx (+ mx (/ r 2))
my (+ my (/ r 2))]
($ :circle {:cx (- mx (/ r 2)) :cy (- my (/ r 2)) :r r :fill color})))

(defui rect [{:keys [x y width height fill-color stroke-width stroke-color
children on-mouse-down on-mouse-up]}]
($ :rect
{:on-mouse-down on-mouse-down
:on-mouse-up on-mouse-up
:width width
:height height
:x x
:y y
:fill fill-color
:stroke-width stroke-width
:stroke stroke-color}
children))

(defui circle [{:keys [x y width height fill-color stroke-width stroke-color on-mouse-down]}]
($ :ellipse
{:on-mouse-down on-mouse-down
:cx (+ x (/ width 2))
:cy (+ y (/ height 2))
:rx (/ width 2)
:ry (/ height 2)
:fill fill-color
:stroke-width stroke-width
:stroke stroke-color}))

(defui text [{:keys [x y width height fill-color stroke-width stroke-color
value font-size font-family font-style
on-mouse-down]}]
($ :text
{:on-mouse-down on-mouse-down
:x x
:y y
:font-family font-family
:font-size font-size
:font-style font-style}
value))

(defn map-object [object size]
(-> object
(update :x * size)
(update :y * size)
(update :width * size)
(update :height * size)))

(def objects-layer
(uix/memo
(uix/fn [{:keys [objects size on-select]}]
(for [{:keys [id] :as object} objects]
(let [idx (.indexOf objects object)
object (-> (map-object object size)
(assoc :key id :on-mouse-down #(on-select idx)))]
(case (:type object)
:rect ($ rect object)
:circle ($ circle object)
:text ($ text object)))))))

(def edit-layer
(uix/memo
(uix/fn [{:keys [mx my on-object-changed on-select idx selected size]}]
(let [[active? set-active] (uix/use-state false)
selected? (some? selected)
on-move (fn [x y]
(on-object-changed idx (assoc selected :x x :y y)))
on-resize (fn [object idx width height]
(on-object-changed idx (assoc object :width width :height height)))]

(uix/use-effect
#(when active?
(on-move mx my))
[selected? active? mx my])

(uix/use-effect
#(when selected?
(set-active true))
[selected?])

(when selected
($ rect
(-> (map-object selected size)
(assoc
:on-mouse-down #(set-active true)
:on-mouse-up #(set-active false)
:stroke-width 1
:stroke-color "#0000ff"
:fill-color :transparent))))))))

(def background-layer
(uix/memo
(uix/fn [{:keys [width height on-mouse-down]}]
($ rect
{:on-mouse-down #(on-mouse-down)
:x 0
:y 0
:width width
:height height
:fill-color :transparent
:stroke-color :none}))))

(defui canvas [{:keys [state on-object-changed on-object-select]}]
(let [{:keys [grid? canvas]} state
[[width height] set-size] (uix/use-state [0 0])
[[ox oy] set-offset] (uix/use-state [0 0])
[[mx my] set-mouse] (uix/use-state [0 0])
ref (uix/use-ref)
size 8
mx (quot (- mx ox) size)
my (quot (- my oy) size)]
(uix/use-effect
(fn []
(set-offset [(.-offsetLeft @ref) (.-offsetTop @ref)])
(set-size [(.-width js/screen) (.-height js/screen)]))
[])
($ :div {:ref ref
:on-mouse-move (fn [^js e]
(set-mouse [(.-clientX e) (.-clientY e)]))
:style {:flex 1
:position :relative
:background-color "#ebeff0"}}
($ :svg {:style {:width width
:height height
:position :absolute
:left 0
:top 0}
:view-box (str "0 0 " width " " height)}
(when grid?
($ :<>
($ canvas-grid {:width width :height height :size size :color "#c1cdd0"})
($ cursor {:r 2
:color "#4f7f8b"
:mx (* size mx)
:my (* size my)})))
($ background-layer
{:width width
:height height
:on-mouse-down on-object-select})
($ objects-layer
{:objects (:objects canvas)
:size size
:on-select on-object-select})
($ edit-layer
{:size size
:on-select on-object-select
:on-object-changed on-object-changed
:mx mx
:my my
:idx (:selected canvas)
:selected (when (:selected canvas)
(nth (:objects canvas) (:selected canvas)))})))))

(def default-styles
{:x 32
:y 32
:width 12
:height 12
:stroke-width 2
:stroke-color "#ff0000"
:fill-color "#00ff00"})

(defui app []
(let [[state set-state] (uix/use-state {:grid? true
:canvas {:selected nil
:objects []}})
on-add-shape (fn [shape]
(let [id (random-uuid)]
(set-state
(->> (case shape
:rect (merge default-styles {:type :rect :id id})
:circle (merge default-styles {:type :circle :id id})
:text (merge default-styles {:type :text :id id
:value "text" :font-family "Inter"
:font-size 32 :font-style :normal}))
(update-in state [:canvas :objects] conj)))))
on-object-select (fn
([]
(set-state (assoc-in state [:canvas :selected] nil)))
([idx]
(set-state (assoc-in state [:canvas :selected] idx))))
on-object-changed (fn [idx object]
(set-state
(assoc-in state [:canvas :objects idx] object)))]
($ :div {:style {:font-family "Inter"
:font-size 14
:display :flex
:flex-direction :column
:width "100vw"
:height "100vh"}}
($ toolbar {:state state :set-state set-state :on-add-shape on-add-shape})
($ canvas {:state state
:on-object-select on-object-select
:on-object-changed on-object-changed}))))

;; init app
(defonce -init
(let [root (uix.dom/create-root (js/document.getElementById "root"))]
(uix.dom/render-root ($ app) root)
nil))
12 changes: 12 additions & 0 deletions core/scripts/examples
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env bash

set -e
set -o pipefail

echo "Installing NPM deps..."
yarn install --frozen-lockfile

echo "<link rel=\"stylesheet\" href=\"https://unpkg.com/[email protected]/src/css/preflight.css\"><link rel=\"stylesheet\" href=\"https://rsms.me/inter/inter.css?v=3.19\"><div id=root></div><script src="out/main.js"></script>" > index.html

echo "Starting examples build server..."
clojure -A:examples -M -m shadow.cljs.devtools.cli watch examples
10 changes: 9 additions & 1 deletion core/shadow-cljs.edn
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{:deps true
:dev-http {3000 "./"}
:builds
{:test {:target :browser
:output-dir "out"
Expand All @@ -12,4 +13,11 @@
:closure-defines {goog.DEBUG false}}}}
:linter-test {:target :browser
:output-dir "out"
:modules {:main {:entries [uix.linter-test]}}}}}
:modules {:main {:entries [uix.linter-test]}}}

:examples {:target :browser
:output-dir "out"
:asset-path "/out"
:modules {:main {:entries [uix.examples]}}
:release {:compiler-options {:infer-externs true
:closure-defines {goog.DEBUG false}}}}}}

0 comments on commit 977a7d3

Please sign in to comment.