mirror of
https://github.com/penpot/penpot.git
synced 2025-05-17 20:16:11 +02:00
🎉 Pixel picker
This commit is contained in:
parent
8aad43883f
commit
f8b3baef3f
18 changed files with 494 additions and 199 deletions
4
frontend/resources/images/cursors/picker.svg
Normal file
4
frontend/resources/images/cursors/picker.svg
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="24px" height="24px">
|
||||||
|
<path fill="#fff" d="M.607 13.076v2.401l2.224.025 7.86-7.405s-.05-.885-.253-1.087c-.202-.202-2.25-1.744-2.25-1.744z"/>
|
||||||
|
<path fill="#000" d="M.343 15.974a.514.514 0 01-.317-.321c-.023-.07-.026-.23-.026-1.43 0-1.468-.001-1.445.09-1.586.02-.032 1.703-1.724 3.74-3.759a596.805 596.805 0 003.7-3.716c0-.009-.367-.384-.816-.833a29.9 29.9 0 01-.817-.833c0-.01.474-.49 1.054-1.07l1.053-1.053.948.946.947.947 1.417-1.413C12.366.806 12.765.418 12.856.357c.238-.161.52-.28.792-.334.17-.034.586-.03.76.008.801.173 1.41.794 1.57 1.603.03.15.03.569 0 .718a2.227 2.227 0 01-.334.793c-.061.09-.45.49-1.496 1.54L12.734 6.1l.947.948.947.947-1.053 1.054c-.58.58-1.061 1.054-1.07 1.054-.01 0-.384-.368-.833-.817-.45-.45-.824-.817-.834-.817-.009 0-1.68 1.666-3.716 3.701a493.093 493.093 0 01-3.759 3.74c-.14.091-.117.09-1.59.089-1.187 0-1.366-.004-1.43-.027zm6.024-4.633a592.723 592.723 0 003.663-3.68c0-.02-1.67-1.69-1.69-1.69-.01 0-1.666 1.648-3.68 3.663L.996 13.297v.834c0 .627.005.839.02.854.015.014.227.02.854.02h.833l3.664-3.664z"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -1743,19 +1743,19 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"workspace.libraries.colors.file-library" : {
|
"workspace.libraries.colors.file-library" : {
|
||||||
"used-in" : [ "src/app/main/ui/workspace/colorpicker.cljs:277", "src/app/main/ui/workspace/colorpalette.cljs:149" ],
|
"used-in" : [ "src/app/main/ui/workspace/colorpicker.cljs:314", "src/app/main/ui/workspace/colorpalette.cljs:149" ],
|
||||||
"translations" : {
|
"translations" : {
|
||||||
"en" : "File library"
|
"en" : "File library"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"workspace.libraries.colors.recent-colors" : {
|
"workspace.libraries.colors.recent-colors" : {
|
||||||
"used-in" : [ "src/app/main/ui/workspace/colorpicker.cljs:276", "src/app/main/ui/workspace/colorpalette.cljs:159" ],
|
"used-in" : [ "src/app/main/ui/workspace/colorpicker.cljs:313", "src/app/main/ui/workspace/colorpalette.cljs:159" ],
|
||||||
"translations" : {
|
"translations" : {
|
||||||
"en" : "Recent colors"
|
"en" : "Recent colors"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"workspace.libraries.colors.save-color" : {
|
"workspace.libraries.colors.save-color" : {
|
||||||
"used-in" : [ "src/app/main/ui/workspace/colorpicker.cljs:312" ],
|
"used-in" : [ "src/app/main/ui/workspace/colorpicker.cljs:349" ],
|
||||||
"translations" : {
|
"translations" : {
|
||||||
"en" : "Save color"
|
"en" : "Save color"
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,54 @@
|
||||||
.colorpicker {
|
.colorpicker {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
width: 13rem;
|
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
background-color: $color-white;
|
background-color: $color-white;
|
||||||
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
|
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
|
||||||
|
|
||||||
|
& > * {
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-actions {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
|
||||||
|
.picker-btn {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&.active,
|
||||||
|
&:hover svg {
|
||||||
|
fill: $color-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.picker-detail-wrapper {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.center-circle {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
border: 2px solid $color-white;
|
||||||
|
border-radius: 8px;
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(-7px, -7px);
|
||||||
|
filter: drop-shadow(0px 4px 4px rgba(0, 0, 0, 0.25));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#picker-detail {
|
||||||
|
border: 1px solid $color-gray-10;
|
||||||
|
}
|
||||||
|
|
||||||
.handler {
|
.handler {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 12px;
|
width: 12px;
|
||||||
|
@ -25,7 +68,6 @@
|
||||||
background-color: rgba(var(--hue));
|
background-color: rgba(var(--hue));
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 6.75rem;
|
height: 6.75rem;
|
||||||
width: 100%;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
.handler {
|
.handler {
|
||||||
|
@ -137,6 +179,7 @@
|
||||||
border-top: 1px solid $color-gray-10;
|
border-top: 1px solid $color-gray-10;
|
||||||
padding-top: 0.5rem;
|
padding-top: 0.5rem;
|
||||||
margin-top: 0.25rem;
|
margin-top: 0.25rem;
|
||||||
|
width: 200px;
|
||||||
|
|
||||||
select {
|
select {
|
||||||
background-image: url(/images/icons/arrow-down.svg);
|
background-image: url(/images/icons/arrow-down.svg);
|
||||||
|
@ -162,7 +205,8 @@
|
||||||
grid-template-columns: repeat(8, 1fr);
|
grid-template-columns: repeat(8, 1fr);
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin-right: -8px;
|
margin-right: -8px;
|
||||||
overflow: scroll;
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
max-height: 5.5rem;
|
max-height: 5.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -129,3 +129,31 @@
|
||||||
(-> state
|
(-> state
|
||||||
(update :workspace-layout conj :colorpalette)
|
(update :workspace-layout conj :colorpalette)
|
||||||
(assoc-in [:workspace-local :selected-palette] selected)))))
|
(assoc-in [:workspace-local :selected-palette] selected)))))
|
||||||
|
|
||||||
|
(defn start-picker []
|
||||||
|
(ptk/reify ::start-picker
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(-> state
|
||||||
|
(assoc-in [:workspace-local :picking-color?] true)))))
|
||||||
|
|
||||||
|
(defn stop-picker []
|
||||||
|
(ptk/reify ::stop-picker
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(-> state
|
||||||
|
(assoc-in [:workspace-local :picking-color?] false)))))
|
||||||
|
|
||||||
|
(defn pick-color [rgba]
|
||||||
|
(ptk/reify ::pick-color
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(-> state
|
||||||
|
(assoc-in [:workspace-local :picked-color] rgba)))))
|
||||||
|
|
||||||
|
(defn pick-color-select [value]
|
||||||
|
(ptk/reify ::pick-color
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(-> state
|
||||||
|
(assoc-in [:workspace-local :picked-color-select] value)))))
|
||||||
|
|
22
frontend/src/app/main/data/fetch.cljs
Normal file
22
frontend/src/app/main/data/fetch.cljs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
;;
|
||||||
|
;; This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||||
|
;; defined by the Mozilla Public License, v. 2.0.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) 2020 UXBOX Labs SL
|
||||||
|
|
||||||
|
(ns app.main.data.fetch
|
||||||
|
(:require
|
||||||
|
[promesa.core :as p]
|
||||||
|
[app.util.object :as obj]))
|
||||||
|
|
||||||
|
(defn fetch-as-data-uri [url]
|
||||||
|
(-> (js/fetch url)
|
||||||
|
(p/then (fn [res] (.blob res)))
|
||||||
|
(p/then (fn [blob]
|
||||||
|
(let [reader (js/FileReader.)]
|
||||||
|
(p/create (fn [resolve reject]
|
||||||
|
(obj/set! reader "onload" #(resolve [url (.-result reader)]))
|
||||||
|
(.readAsDataURL reader blob))))))))
|
|
@ -102,7 +102,10 @@
|
||||||
:right-sidebar? true
|
:right-sidebar? true
|
||||||
:color-for-rename nil
|
:color-for-rename nil
|
||||||
:selected-palette :recent
|
:selected-palette :recent
|
||||||
:selected-palette-size :big})
|
:selected-palette-size :big
|
||||||
|
:picking-color? false
|
||||||
|
:picked-color nil
|
||||||
|
:picked-color-select false})
|
||||||
|
|
||||||
(def initialize-layout
|
(def initialize-layout
|
||||||
(ptk/reify ::initialize-layout
|
(ptk/reify ::initialize-layout
|
||||||
|
|
|
@ -114,6 +114,11 @@
|
||||||
(unchecked-set node "type" "text/css")
|
(unchecked-set node "type" "text/css")
|
||||||
node))
|
node))
|
||||||
|
|
||||||
|
(defn gfont-url [family variants]
|
||||||
|
(let [base (str "https://fonts.googleapis.com/css?family=" family)
|
||||||
|
variants (str/join "," (map :id variants))]
|
||||||
|
(str base ":" variants "&display=block")))
|
||||||
|
|
||||||
(defmulti ^:private load-font :backend)
|
(defmulti ^:private load-font :backend)
|
||||||
|
|
||||||
(defmethod load-font :builtin
|
(defmethod load-font :builtin
|
||||||
|
@ -126,10 +131,7 @@
|
||||||
[{:keys [id family variants ::on-loaded] :as font}]
|
[{:keys [id family variants ::on-loaded] :as font}]
|
||||||
(when (exists? js/window)
|
(when (exists? js/window)
|
||||||
(js/console.log "[debug:fonts]: loading google font" id)
|
(js/console.log "[debug:fonts]: loading google font" id)
|
||||||
(let [base (str "https://fonts.googleapis.com/css?family=" family)
|
(let [node (create-link-node (gfont-url family variants))]
|
||||||
variants (str/join "," (map :id variants))
|
|
||||||
uri (str base ":" variants "&display=block")
|
|
||||||
node (create-link-node uri)]
|
|
||||||
(.addEventListener node "load" (fn [event] (when (fn? on-loaded)
|
(.addEventListener node "load" (fn [event] (when (fn? on-loaded)
|
||||||
(on-loaded id))))
|
(on-loaded id))))
|
||||||
(.append (.-head js/document) node)
|
(.append (.-head js/document) node)
|
||||||
|
|
|
@ -80,6 +80,14 @@
|
||||||
(def current-hover
|
(def current-hover
|
||||||
(l/derived :hover workspace-local))
|
(l/derived :hover workspace-local))
|
||||||
|
|
||||||
|
(def picking-color?
|
||||||
|
(l/derived :picking-color? workspace-local))
|
||||||
|
|
||||||
|
(def picked-color
|
||||||
|
(l/derived :picked-color workspace-local))
|
||||||
|
|
||||||
|
(def picked-color-select
|
||||||
|
(l/derived :picked-color-select workspace-local))
|
||||||
|
|
||||||
(def workspace-layout
|
(def workspace-layout
|
||||||
(l/derived :workspace-layout st/state))
|
(l/derived :workspace-layout st/state))
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
(def resize-ns (cursor-fn :resize-h 90))
|
(def resize-ns (cursor-fn :resize-h 90))
|
||||||
(def rotate (cursor-fn :rotate 90))
|
(def rotate (cursor-fn :rotate 90))
|
||||||
(def text (cursor-ref :text))
|
(def text (cursor-ref :text))
|
||||||
|
(def picker (cursor-ref :picker 0 0 24))
|
||||||
|
|
||||||
(mf/defc debug-preview
|
(mf/defc debug-preview
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
(:import goog.events.EventType))
|
(:import goog.events.EventType))
|
||||||
|
|
||||||
(defonce state (atom nil))
|
(defonce state (atom nil))
|
||||||
|
(defonce can-click-outside (atom false))
|
||||||
|
|
||||||
(defn show!
|
(defn show!
|
||||||
[component props]
|
[component props]
|
||||||
|
@ -25,13 +26,12 @@
|
||||||
(reset! state nil)
|
(reset! state nil)
|
||||||
(dom/stop-propagation event)))
|
(dom/stop-propagation event)))
|
||||||
|
|
||||||
(defn- on-parent-clicked
|
(defn- on-click
|
||||||
[event parent-ref]
|
[event wrapper-ref]
|
||||||
(let [parent (mf/ref-val parent-ref)
|
(let [wrapper (mf/ref-val wrapper-ref)
|
||||||
current (dom/get-target event)]
|
current (dom/get-target event)]
|
||||||
;; (js/console.log current (.-className ^js current))
|
|
||||||
(when (and (dom/equals? (.-firstElementChild ^js parent) current)
|
(when (and (not @can-click-outside) (not (.contains wrapper current)))
|
||||||
(str/includes? (.-className ^js current) "modal-overlay"))
|
|
||||||
(dom/stop-propagation event)
|
(dom/stop-propagation event)
|
||||||
(dom/prevent-default event)
|
(dom/prevent-default event)
|
||||||
(reset! state nil))))
|
(reset! state nil))))
|
||||||
|
@ -39,15 +39,19 @@
|
||||||
(mf/defc modal-wrapper
|
(mf/defc modal-wrapper
|
||||||
[{:keys [component props]}]
|
[{:keys [component props]}]
|
||||||
|
|
||||||
(mf/use-effect
|
(let [wrapper-ref (mf/use-ref nil)]
|
||||||
(fn []
|
(mf/use-effect
|
||||||
(let [key (events/listen js/document EventType.KEYDOWN on-esc-clicked)]
|
(fn []
|
||||||
#(events/unlistenByKey %))))
|
(let [key (events/listen js/document EventType.KEYDOWN on-esc-clicked)]
|
||||||
|
#(events/unlistenByKey key))))
|
||||||
|
|
||||||
|
(mf/use-effect
|
||||||
|
(fn []
|
||||||
|
(let [key (events/listen js/document EventType.CLICK #(on-click % wrapper-ref))]
|
||||||
|
#(events/unlistenByKey key))))
|
||||||
|
|
||||||
(let [ref (mf/use-ref nil)]
|
|
||||||
[:div.modal-wrapper
|
[:div.modal-wrapper
|
||||||
{:ref ref
|
{:ref wrapper-ref}
|
||||||
:on-click #(on-parent-clicked % ref)}
|
|
||||||
[:& component props]]))
|
[:& component props]]))
|
||||||
|
|
||||||
(mf/defc modal
|
(mf/defc modal
|
||||||
|
@ -58,4 +62,8 @@
|
||||||
:key (random-uuid)}]))
|
:key (random-uuid)}]))
|
||||||
|
|
||||||
|
|
||||||
|
(defn allow-click-outside! []
|
||||||
|
(reset! can-click-outside true))
|
||||||
|
|
||||||
|
(defn disallow-click-outside! []
|
||||||
|
(reset! can-click-outside false))
|
||||||
|
|
|
@ -13,23 +13,43 @@
|
||||||
[app.config :as cfg]
|
[app.config :as cfg]
|
||||||
[app.common.geom.shapes :as geom]
|
[app.common.geom.shapes :as geom]
|
||||||
[app.main.ui.shapes.attrs :as attrs]
|
[app.main.ui.shapes.attrs :as attrs]
|
||||||
[app.util.object :as obj]))
|
[app.util.object :as obj]
|
||||||
|
[app.main.data.fetch :as df]
|
||||||
|
[promesa.core :as p]))
|
||||||
|
|
||||||
(mf/defc image-shape
|
(mf/defc image-shape
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
[props]
|
[props]
|
||||||
|
|
||||||
(let [shape (unchecked-get props "shape")
|
(let [shape (unchecked-get props "shape")
|
||||||
{:keys [id x y width height rotation metadata]} shape
|
{:keys [id x y width height rotation metadata]} shape
|
||||||
transform (geom/transform-matrix shape)
|
uri (cfg/resolve-media-path (:path metadata))
|
||||||
uri (cfg/resolve-media-path (:path metadata))
|
data-uri (mf/use-state nil)]
|
||||||
props (-> (attrs/extract-style-attrs shape)
|
|
||||||
(obj/merge!
|
(mf/use-effect
|
||||||
#js {:x x
|
(mf/deps shape)
|
||||||
:y y
|
(fn []
|
||||||
:transform transform
|
(-> (df/fetch-as-data-uri uri)
|
||||||
:id (str "shape-" id)
|
(p/then #(reset! data-uri (second %))))))
|
||||||
:preserveAspectRatio "none"
|
|
||||||
:xlinkHref uri
|
(let [transform (geom/transform-matrix shape)
|
||||||
:width width
|
props (-> (attrs/extract-style-attrs shape)
|
||||||
:height height}))]
|
(obj/merge!
|
||||||
[:> "image" props]))
|
#js {:x x
|
||||||
|
:y y
|
||||||
|
:transform transform
|
||||||
|
:id (str "shape-" id)
|
||||||
|
:width width
|
||||||
|
:height height
|
||||||
|
:preserveAspectRatio "none"}))]
|
||||||
|
(if (nil? @data-uri)
|
||||||
|
[:> "rect" (obj/merge!
|
||||||
|
props
|
||||||
|
#js {:fill "#E8E9EA"
|
||||||
|
:stroke "#000000"})]
|
||||||
|
[:> "image" (obj/merge!
|
||||||
|
props
|
||||||
|
#js {:xlinkHref @data-uri})]))
|
||||||
|
|
||||||
|
|
||||||
|
))
|
||||||
|
|
|
@ -6,12 +6,16 @@
|
||||||
|
|
||||||
(ns app.main.ui.shapes.text
|
(ns app.main.ui.shapes.text
|
||||||
(:require
|
(:require
|
||||||
|
[promesa.core :as p]
|
||||||
|
[cuerdas.core :as str]
|
||||||
[rumext.alpha :as mf]
|
[rumext.alpha :as mf]
|
||||||
|
[app.main.data.fetch :as df]
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.geom.shapes :as geom]
|
[app.common.geom.shapes :as geom]
|
||||||
[app.common.geom.matrix :as gmt]
|
[app.common.geom.matrix :as gmt]
|
||||||
[app.main.fonts :as fonts]
|
[app.main.fonts :as fonts]
|
||||||
[app.util.object :as obj]))
|
[app.util.object :as obj]
|
||||||
|
[clojure.set :as set]))
|
||||||
|
|
||||||
;; --- Text Editor Rendering
|
;; --- Text Editor Rendering
|
||||||
|
|
||||||
|
@ -55,7 +59,8 @@
|
||||||
base #js {:textDecoration text-decoration
|
base #js {:textDecoration text-decoration
|
||||||
:color fill
|
:color fill
|
||||||
:opacity opacity
|
:opacity opacity
|
||||||
:textTransform text-transform}]
|
:textTransform text-transform
|
||||||
|
:lineHeight "inherit"}]
|
||||||
|
|
||||||
(when (and (string? letter-spacing)
|
(when (and (string? letter-spacing)
|
||||||
(pos? (alength letter-spacing)))
|
(pos? (alength letter-spacing)))
|
||||||
|
@ -83,33 +88,69 @@
|
||||||
|
|
||||||
base))
|
base))
|
||||||
|
|
||||||
|
(defn get-all-fonts [node]
|
||||||
|
(let [current-font (if (not (nil? (:font-id node)))
|
||||||
|
#{(:font-id node)}
|
||||||
|
#{})
|
||||||
|
children-font (map get-all-fonts (:children node))]
|
||||||
|
(reduce set/union (conj children-font current-font))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn fetch-font [font-id]
|
||||||
|
(let [{:keys [family variants]} (get @fonts/fontsdb font-id)]
|
||||||
|
(-> (js/fetch (fonts/gfont-url family variants))
|
||||||
|
(p/then (fn [res] (.text res))))))
|
||||||
|
|
||||||
|
(defn embed-font [font-id]
|
||||||
|
(p/let [font-text (fetch-font font-id)
|
||||||
|
url-to-data (->> font-text
|
||||||
|
(re-seq #"url\(([^)]+)\)")
|
||||||
|
(map second)
|
||||||
|
(map df/fetch-as-data-uri)
|
||||||
|
(p/all))]
|
||||||
|
(reduce (fn [text [url data]] (str/replace text url data)) font-text url-to-data)))
|
||||||
|
|
||||||
(defn- render-text-node
|
(defn- render-text-node
|
||||||
([node] (render-text-node 0 node))
|
([node] (render-text-node 0 node))
|
||||||
([index {:keys [type text children] :as node}]
|
([index {:keys [type text children] :as node}]
|
||||||
(mf/html
|
(mf/html
|
||||||
(if (string? text)
|
(let [embeded-fonts (mf/use-state nil)]
|
||||||
(let [style (generate-text-styles (clj->js node))]
|
(mf/use-effect
|
||||||
[:span {:style style :key index} text])
|
(mf/deps node)
|
||||||
(let [children (map-indexed render-text-node children)]
|
(fn []
|
||||||
(case type
|
(when (= type "root")
|
||||||
"root"
|
(let [font-to-embed (get-all-fonts node)
|
||||||
(let [style (generate-root-styles (clj->js node))]
|
embeded (map embed-font font-to-embed)]
|
||||||
[:div.root.rich-text
|
(-> (p/all embeded)
|
||||||
{:key index
|
(p/then (fn [result] (reset! embeded-fonts (str/join "\n" result)))))))))
|
||||||
:style style
|
|
||||||
:xmlns "http://www.w3.org/1999/xhtml"}
|
|
||||||
children])
|
|
||||||
|
|
||||||
"paragraph-set"
|
(if (string? text)
|
||||||
(let [style #js {:display "inline-block"
|
(let [style (generate-text-styles (clj->js node))]
|
||||||
:width "100%"}]
|
[:span {:style style :key index} text])
|
||||||
[:div.paragraphs {:key index :style style} children])
|
(let [children (map-indexed render-text-node children)]
|
||||||
|
(case type
|
||||||
|
"root"
|
||||||
|
(let [style (generate-root-styles (clj->js node))]
|
||||||
|
|
||||||
|
[:div.root.rich-text
|
||||||
|
{:key index
|
||||||
|
:style style
|
||||||
|
:xmlns "http://www.w3.org/1999/xhtml"}
|
||||||
|
[:*
|
||||||
|
(when (not (nil? @embeded-fonts))
|
||||||
|
[:style @embeded-fonts])
|
||||||
|
children]])
|
||||||
|
|
||||||
"paragraph"
|
"paragraph-set"
|
||||||
(let [style (generate-paragraph-styles (clj->js node))]
|
(let [style #js {:display "inline-block"
|
||||||
[:p {:key index :style style} children])
|
:width "100%"}]
|
||||||
|
[:div.paragraphs {:key index :style style} children])
|
||||||
|
|
||||||
nil))))))
|
"paragraph"
|
||||||
|
(let [style (generate-paragraph-styles (clj->js node))]
|
||||||
|
[:p {:key index :style style} children])
|
||||||
|
|
||||||
|
nil)))))))
|
||||||
|
|
||||||
(mf/defc text-content
|
(mf/defc text-content
|
||||||
{::mf/wrap-props false
|
{::mf/wrap-props false
|
||||||
|
|
|
@ -102,6 +102,10 @@
|
||||||
shared-libs (mf/deref refs/workspace-libraries)
|
shared-libs (mf/deref refs/workspace-libraries)
|
||||||
recent-colors (mf/deref refs/workspace-recent-colors)
|
recent-colors (mf/deref refs/workspace-recent-colors)
|
||||||
|
|
||||||
|
picking-color? (mf/deref refs/picking-color?)
|
||||||
|
picked-color (mf/deref refs/picked-color)
|
||||||
|
picked-color-select (mf/deref refs/picked-color-select)
|
||||||
|
|
||||||
locale (mf/deref i18n/locale)
|
locale (mf/deref i18n/locale)
|
||||||
|
|
||||||
value-ref (mf/use-var value)
|
value-ref (mf/use-var value)
|
||||||
|
@ -154,37 +158,70 @@
|
||||||
|
|
||||||
;; When closing the modal we update the recent-color list
|
;; When closing the modal we update the recent-color list
|
||||||
(mf/use-effect
|
(mf/use-effect
|
||||||
(fn [] #(st/emit! (dwl/add-recent-color @value-ref))))
|
(fn [] #(st/emit! (dwc/stop-picker)
|
||||||
|
(dwl/add-recent-color @value-ref))))
|
||||||
|
|
||||||
|
(mf/use-effect
|
||||||
|
(mf/deps picking-color? picked-color)
|
||||||
|
(fn [] (when picking-color?
|
||||||
|
(let [[r g b] picked-color
|
||||||
|
hex (uc/rgb->hex [r g b])
|
||||||
|
[h s v] (uc/hex->hsv hex)]
|
||||||
|
(swap! current-color assoc
|
||||||
|
:r r :g g :b b
|
||||||
|
:h h :s s :v v
|
||||||
|
:hex hex)
|
||||||
|
(when picked-color-select
|
||||||
|
(on-change hex (:alpha @current-color)))))))
|
||||||
|
|
||||||
|
(mf/use-effect
|
||||||
|
(mf/deps picking-color? picked-color-select)
|
||||||
|
(fn [] (when picking-color?
|
||||||
|
(on-change (:hex @current-color) (:alpha @current-color)))))
|
||||||
|
|
||||||
[:div.colorpicker {:ref ref-picker}
|
[:div.colorpicker {:ref ref-picker}
|
||||||
[:& value-selector {:hue (:h @current-color)
|
[:div.top-actions
|
||||||
:saturation (:s @current-color)
|
[:button.picker-btn
|
||||||
:value (:v @current-color)
|
{:class (when picking-color? "active")
|
||||||
:on-change (fn [s v]
|
:on-click (fn []
|
||||||
(let [hex (uc/hsv->hex [(:h @current-color) s v])
|
(modal/allow-click-outside!)
|
||||||
[r g b] (uc/hex->rgb hex)]
|
(st/emit! (dwc/start-picker)))}
|
||||||
(swap! current-color assoc
|
i/picker]]
|
||||||
:hex hex
|
|
||||||
:r r :g g :b b
|
(if picking-color?
|
||||||
:s s :v v)
|
[:div.picker-detail-wrapper
|
||||||
(reset! value-ref hex)
|
[:div.center-circle]
|
||||||
(on-change hex (:alpha @current-color))))}]
|
[:canvas#picker-detail {:width 200
|
||||||
[:div.shade-selector
|
:height 160}]]
|
||||||
[:div.color-bullet]
|
[:& value-selector {:hue (:h @current-color)
|
||||||
[:& hue-selector {:hue (:h @current-color)
|
:saturation (:s @current-color)
|
||||||
:on-change (fn [h]
|
:value (:v @current-color)
|
||||||
(let [hex (uc/hsv->hex [h (:s @current-color) (:v @current-color)])
|
:on-change (fn [s v]
|
||||||
[r g b] (uc/hex->rgb hex)]
|
(let [hex (uc/hsv->hex [(:h @current-color) s v])
|
||||||
(swap! current-color assoc
|
[r g b] (uc/hex->rgb hex)]
|
||||||
:hex hex
|
(swap! current-color assoc
|
||||||
:r r :g g :b b
|
:hex hex
|
||||||
:h h )
|
:r r :g g :b b
|
||||||
(reset! value-ref hex)
|
:s s :v v)
|
||||||
(on-change hex (:alpha @current-color))))}]
|
(reset! value-ref hex)
|
||||||
[:& opacity-selector {:opacity (:alpha @current-color)
|
(on-change hex (:alpha @current-color))))}])
|
||||||
:on-change (fn [alpha]
|
(when (not picking-color?)
|
||||||
(swap! current-color assoc :alpha alpha)
|
[:div.shade-selector
|
||||||
(on-change (:hex @current-color) alpha))}]]
|
[:div.color-bullet]
|
||||||
|
[:& hue-selector {:hue (:h @current-color)
|
||||||
|
:on-change (fn [h]
|
||||||
|
(let [hex (uc/hsv->hex [h (:s @current-color) (:v @current-color)])
|
||||||
|
[r g b] (uc/hex->rgb hex)]
|
||||||
|
(swap! current-color assoc
|
||||||
|
:hex hex
|
||||||
|
:r r :g g :b b
|
||||||
|
:h h )
|
||||||
|
(reset! value-ref hex)
|
||||||
|
(on-change hex (:alpha @current-color))))}]
|
||||||
|
[:& opacity-selector {:opacity (:alpha @current-color)
|
||||||
|
:on-change (fn [alpha]
|
||||||
|
(swap! current-color assoc :alpha alpha)
|
||||||
|
(on-change (:hex @current-color) alpha))}]])
|
||||||
|
|
||||||
[:div.color-values
|
[:div.color-values
|
||||||
[:input.hex-value {:id "hex-value"
|
[:input.hex-value {:id "hex-value"
|
||||||
|
@ -320,12 +357,11 @@
|
||||||
:top (str (- y 50) "px")}
|
:top (str (- y 50) "px")}
|
||||||
:right {:left (str (+ x 24) "px")
|
:right {:left (str (+ x 24) "px")
|
||||||
:top (str (- y 50) "px")})]
|
:top (str (- y 50) "px")})]
|
||||||
[:div.modal-overlay.transparent
|
[:div.colorpicker-tooltip
|
||||||
[:div.colorpicker-tooltip
|
|
||||||
{:style (clj->js style)}
|
{:style (clj->js style)}
|
||||||
[:& colorpicker {:value (or value default)
|
[:& colorpicker {:value (or value default)
|
||||||
:opacity (or opacity 1)
|
:opacity (or opacity 1)
|
||||||
:on-change on-change
|
:on-change on-change
|
||||||
:on-accept on-accept
|
:on-accept on-accept
|
||||||
:disable-opacity disable-opacity}]]]))
|
:disable-opacity disable-opacity}]]))
|
||||||
|
|
||||||
|
|
|
@ -33,49 +33,50 @@
|
||||||
|
|
||||||
(defn draw-rule!
|
(defn draw-rule!
|
||||||
[dctx {:keys [zoom size start count type] :or {count 200}}]
|
[dctx {:keys [zoom size start count type] :or {count 200}}]
|
||||||
(let [txfm (- (* (- 0 start) zoom) 20)
|
(when start
|
||||||
minv (mth/round start)
|
(let [txfm (- (* (- 0 start) zoom) 20)
|
||||||
maxv (mth/round (+ start (/ size zoom)))
|
minv (max (mth/round start) -10000)
|
||||||
step (calculate-step-size zoom)]
|
maxv (min (mth/round (+ start (/ size zoom))) 10000)
|
||||||
|
step (calculate-step-size zoom)]
|
||||||
|
|
||||||
(if (= type :horizontal)
|
(if (= type :horizontal)
|
||||||
(.translate dctx txfm 0)
|
(.translate dctx txfm 0)
|
||||||
(.translate dctx 0 txfm))
|
(.translate dctx 0 txfm))
|
||||||
|
|
||||||
(obj/set! dctx "font" "12px sourcesanspro")
|
(obj/set! dctx "font" "12px sourcesanspro")
|
||||||
(obj/set! dctx "fillStyle" "#7B7D85")
|
(obj/set! dctx "fillStyle" "#7B7D85")
|
||||||
(obj/set! dctx "strokeStyle" "#7B7D85")
|
(obj/set! dctx "strokeStyle" "#7B7D85")
|
||||||
(obj/set! dctx "textAlign" "center")
|
(obj/set! dctx "textAlign" "center")
|
||||||
|
|
||||||
(loop [i minv]
|
(loop [i minv]
|
||||||
(when (< i maxv)
|
(when (< i maxv)
|
||||||
(let [pos (+ (* i zoom) 0)]
|
(let [pos (+ (* i zoom) 0)]
|
||||||
(when (= (mod i step) 0)
|
(when (= (mod i step) 0)
|
||||||
(.save dctx)
|
(.save dctx)
|
||||||
(if (= type :horizontal)
|
(if (= type :horizontal)
|
||||||
(do
|
(do
|
||||||
(.fillText dctx (str i) pos 13))
|
(.fillText dctx (str i) pos 13))
|
||||||
(do
|
(do
|
||||||
(.translate dctx 12 pos)
|
(.translate dctx 12 pos)
|
||||||
(.rotate dctx (/ (* 270 js/Math.PI) 180))
|
(.rotate dctx (/ (* 270 js/Math.PI) 180))
|
||||||
(.fillText dctx (str i) 0 0)))
|
(.fillText dctx (str i) 0 0)))
|
||||||
(.restore dctx))
|
(.restore dctx))
|
||||||
(recur (inc i)))))
|
(recur (inc i)))))
|
||||||
|
|
||||||
(let [path (js/Path2D.)]
|
(let [path (js/Path2D.)]
|
||||||
(loop [i minv]
|
(loop [i minv]
|
||||||
(if (> i maxv)
|
(if (> i maxv)
|
||||||
(.stroke dctx path)
|
(.stroke dctx path)
|
||||||
(let [pos (+ (* i zoom) 0)]
|
(let [pos (+ (* i zoom) 0)]
|
||||||
(when (= (mod i step) 0)
|
(when (= (mod i step) 0)
|
||||||
(if (= type :horizontal)
|
(if (= type :horizontal)
|
||||||
(do
|
(do
|
||||||
(.moveTo path pos 17)
|
(.moveTo path pos 17)
|
||||||
(.lineTo path pos 20))
|
(.lineTo path pos 20))
|
||||||
(do
|
(do
|
||||||
(.moveTo path 17 pos)
|
(.moveTo path 17 pos)
|
||||||
(.lineTo path 20 pos))))
|
(.lineTo path 20 pos))))
|
||||||
(recur (inc i))))))))
|
(recur (inc i)))))))))
|
||||||
|
|
||||||
|
|
||||||
(mf/defc horizontal-rule
|
(mf/defc horizontal-rule
|
||||||
|
|
|
@ -119,7 +119,8 @@
|
||||||
base #js {:textDecoration text-decoration
|
base #js {:textDecoration text-decoration
|
||||||
:color fill
|
:color fill
|
||||||
:opacity opacity
|
:opacity opacity
|
||||||
:textTransform text-transform}]
|
:textTransform text-transform
|
||||||
|
:lineHeight "inherit"}]
|
||||||
|
|
||||||
(when (and (string? letter-spacing)
|
(when (and (string? letter-spacing)
|
||||||
(pos? (alength letter-spacing)))
|
(pos? (alength letter-spacing)))
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
(if (= value :multiple) "transparent" value))
|
(if (= value :multiple) "transparent" value))
|
||||||
|
|
||||||
(defn remove-hash [value]
|
(defn remove-hash [value]
|
||||||
(if (= value :multiple) "" (subs value 1)))
|
(if (or (nil? value) (= value :multiple)) "" (subs value 1)))
|
||||||
|
|
||||||
(defn append-hash [value]
|
(defn append-hash [value]
|
||||||
(str "#" value))
|
(str "#" value))
|
||||||
|
|
|
@ -15,12 +15,15 @@
|
||||||
[goog.events :as events]
|
[goog.events :as events]
|
||||||
[potok.core :as ptk]
|
[potok.core :as ptk]
|
||||||
[rumext.alpha :as mf]
|
[rumext.alpha :as mf]
|
||||||
|
[promesa.core :as p]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.main.ui.cursors :as cur]
|
[app.main.ui.cursors :as cur]
|
||||||
|
[app.main.ui.modal :as modal]
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.main.constants :as c]
|
[app.main.constants :as c]
|
||||||
[app.main.data.workspace :as dw]
|
[app.main.data.workspace :as dw]
|
||||||
[app.main.data.workspace.drawing :as dd]
|
[app.main.data.workspace.drawing :as dd]
|
||||||
|
[app.main.data.colors :as dwc]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.streams :as ms]
|
[app.main.streams :as ms]
|
||||||
|
@ -168,15 +171,20 @@
|
||||||
edition
|
edition
|
||||||
tooltip
|
tooltip
|
||||||
selected
|
selected
|
||||||
panning]} local
|
panning
|
||||||
|
picking-color?]} local
|
||||||
|
|
||||||
file (mf/deref refs/workspace-file)
|
file (mf/deref refs/workspace-file)
|
||||||
viewport-ref (mf/use-ref nil)
|
viewport-ref (mf/use-ref nil)
|
||||||
|
canvas-ref (mf/use-ref nil)
|
||||||
|
zoom-view-ref (mf/use-ref nil)
|
||||||
last-position (mf/use-var nil)
|
last-position (mf/use-var nil)
|
||||||
drawing (mf/deref refs/workspace-drawing)
|
drawing (mf/deref refs/workspace-drawing)
|
||||||
drawing-tool (:tool drawing)
|
drawing-tool (:tool drawing)
|
||||||
drawing-obj (:object drawing)
|
drawing-obj (:object drawing)
|
||||||
|
|
||||||
|
pick-color (mf/use-state [255 255 255 255])
|
||||||
|
|
||||||
zoom (or zoom 1)
|
zoom (or zoom 1)
|
||||||
|
|
||||||
on-mouse-down
|
on-mouse-down
|
||||||
|
@ -410,7 +418,47 @@
|
||||||
prnt (dom/get-parent node)]
|
prnt (dom/get-parent node)]
|
||||||
(st/emit! (dw/update-viewport-size (dom/get-client-size prnt)))))
|
(st/emit! (dw/update-viewport-size (dom/get-client-size prnt)))))
|
||||||
|
|
||||||
options (mf/deref refs/workspace-page-options)]
|
options (mf/deref refs/workspace-page-options)
|
||||||
|
|
||||||
|
on-mouse-move-picker
|
||||||
|
(fn [event]
|
||||||
|
(when-let [zoom-view-node (.getElementById js/document "picker-detail")]
|
||||||
|
(let [{brx :left bry :top} (dom/get-bounding-rect (mf/ref-val viewport-ref))
|
||||||
|
x (- (.-clientX event) brx)
|
||||||
|
y (- (.-clientY event) bry)
|
||||||
|
|
||||||
|
zoom-context (.getContext zoom-view-node "2d")
|
||||||
|
canvas-node (mf/ref-val canvas-ref)
|
||||||
|
canvas-context (.getContext canvas-node "2d")
|
||||||
|
pixel-data (.getImageData canvas-context x y 1 1)
|
||||||
|
rgba (.-data pixel-data)
|
||||||
|
r (obj/get rgba 0)
|
||||||
|
g (obj/get rgba 1)
|
||||||
|
b (obj/get rgba 2)
|
||||||
|
a (obj/get rgba 3)
|
||||||
|
|
||||||
|
area-data (.getImageData canvas-context (- x 25) (- y 20) 50 40)]
|
||||||
|
|
||||||
|
(-> (js/createImageBitmap area-data)
|
||||||
|
(p/then (fn [image]
|
||||||
|
;; Draw area
|
||||||
|
(obj/set! zoom-context "imageSmoothingEnabled" false)
|
||||||
|
(.drawImage zoom-context image 0 0 200 160))))
|
||||||
|
(st/emit! (dwc/pick-color [r g b a])))))
|
||||||
|
|
||||||
|
on-mouse-down-picker
|
||||||
|
(fn [event]
|
||||||
|
(dom/prevent-default event)
|
||||||
|
(dom/stop-propagation event)
|
||||||
|
(st/emit! (dwc/pick-color-select true)))
|
||||||
|
|
||||||
|
on-mouse-up-picker
|
||||||
|
(fn [event]
|
||||||
|
(dom/prevent-default event)
|
||||||
|
(dom/stop-propagation event)
|
||||||
|
(st/emit! (dwc/pick-color-select false)
|
||||||
|
(dwc/stop-picker))
|
||||||
|
(modal/disallow-click-outside!))]
|
||||||
|
|
||||||
(mf/use-layout-effect
|
(mf/use-layout-effect
|
||||||
(fn []
|
(fn []
|
||||||
|
@ -434,73 +482,103 @@
|
||||||
|
|
||||||
(mf/use-layout-effect (mf/deps layout) on-resize)
|
(mf/use-layout-effect (mf/deps layout) on-resize)
|
||||||
|
|
||||||
[:svg.viewport
|
(mf/use-effect
|
||||||
{:preserveAspectRatio "xMidYMid meet"
|
(mf/deps props)
|
||||||
:width (:width vport 0)
|
(fn []
|
||||||
:height (:height vport 0)
|
(when picking-color?
|
||||||
:view-box (str/join " " [(+ (:x vbox 0) (:left-offset vbox 0))
|
(try
|
||||||
(:y vbox 0)
|
(let [svg-node (mf/ref-val viewport-ref)
|
||||||
(:width vbox 0)
|
canvas-node (mf/ref-val canvas-ref)
|
||||||
(:height vbox 0)])
|
canvas-context (.getContext canvas-node "2d")
|
||||||
:ref viewport-ref
|
xml (.serializeToString (js/XMLSerializer.) svg-node)
|
||||||
:class (when drawing-tool "drawing")
|
content (str "data:image/svg+xml;base64," (js/btoa xml))
|
||||||
:style {:cursor (cond
|
img (js/Image.)]
|
||||||
panning cur/hand
|
(obj/set! img "onload"
|
||||||
(= drawing-tool :frame) cur/create-artboard
|
(fn []
|
||||||
(= drawing-tool :rect) cur/create-rectangle
|
(.drawImage canvas-context img 0 0)))
|
||||||
(= drawing-tool :circle) cur/create-ellipse
|
(obj/set! img "src" content))
|
||||||
(= drawing-tool :path) cur/pen
|
(catch :default e (.error js/console e))))))
|
||||||
(= drawing-tool :curve)cur/pencil
|
|
||||||
drawing-tool cur/create-shape
|
|
||||||
:else cur/pointer-inner)
|
|
||||||
:background-color (get options :background "#E8E9EA")}
|
|
||||||
:on-context-menu on-context-menu
|
|
||||||
:on-click on-click
|
|
||||||
:on-double-click on-double-click
|
|
||||||
:on-mouse-down on-mouse-down
|
|
||||||
:on-mouse-up on-mouse-up
|
|
||||||
:on-pointer-down on-pointer-down
|
|
||||||
:on-pointer-up on-pointer-up
|
|
||||||
:on-drag-enter on-drag-enter
|
|
||||||
:on-drag-over on-drag-over
|
|
||||||
:on-drop on-drop}
|
|
||||||
|
|
||||||
[:g
|
[:*
|
||||||
[:& frames {:key page-id
|
|
||||||
:hover (:hover local)
|
|
||||||
:selected (:selected selected)}]
|
|
||||||
|
|
||||||
(when (seq selected)
|
(when picking-color?
|
||||||
[:& selection-handlers {:selected selected
|
[:canvas {:ref canvas-ref
|
||||||
:zoom zoom
|
:width (:width vport 0)
|
||||||
:edition edition}])
|
:height (:height vport 0)
|
||||||
|
:on-mouse-down on-mouse-down-picker
|
||||||
|
:on-mouse-up on-mouse-up-picker
|
||||||
|
:on-mouse-move on-mouse-move-picker
|
||||||
|
:style {:position "absolute"
|
||||||
|
:top 0
|
||||||
|
:left 0
|
||||||
|
:cursor cur/picker}}])
|
||||||
|
[:svg.viewport
|
||||||
|
{:preserveAspectRatio "xMidYMid meet"
|
||||||
|
:width (:width vport 0)
|
||||||
|
:height (:height vport 0)
|
||||||
|
:view-box (str/join " " [(+ (:x vbox 0) (:left-offset vbox 0))
|
||||||
|
(:y vbox 0)
|
||||||
|
(:width vbox 0)
|
||||||
|
(:height vbox 0)])
|
||||||
|
:ref viewport-ref
|
||||||
|
:class (when drawing-tool "drawing")
|
||||||
|
:style {:cursor (cond
|
||||||
|
panning cur/hand
|
||||||
|
(= drawing-tool :frame) cur/create-artboard
|
||||||
|
(= drawing-tool :rect) cur/create-rectangle
|
||||||
|
(= drawing-tool :circle) cur/create-ellipse
|
||||||
|
(= drawing-tool :path) cur/pen
|
||||||
|
(= drawing-tool :curve)cur/pencil
|
||||||
|
drawing-tool cur/create-shape
|
||||||
|
:else cur/pointer-inner)
|
||||||
|
:background-color (get options :background "#E8E9EA")}
|
||||||
|
:on-context-menu on-context-menu
|
||||||
|
:on-click on-click
|
||||||
|
:on-double-click on-double-click
|
||||||
|
:on-mouse-down on-mouse-down
|
||||||
|
:on-mouse-up on-mouse-up
|
||||||
|
:on-pointer-down on-pointer-down
|
||||||
|
:on-pointer-up on-pointer-up
|
||||||
|
:on-drag-enter on-drag-enter
|
||||||
|
:on-drag-over on-drag-over
|
||||||
|
:on-drop on-drop}
|
||||||
|
|
||||||
(when drawing-obj
|
[:g
|
||||||
[:& draw-area {:shape drawing-obj
|
[:& frames {:key page-id
|
||||||
:zoom zoom
|
:hover (:hover local)
|
||||||
:modifiers (:modifiers local)}])
|
:selected (:selected selected)}]
|
||||||
|
|
||||||
(when (contains? layout :display-grid)
|
(when (seq selected)
|
||||||
[:& frame-grid {:zoom zoom}])
|
[:& selection-handlers {:selected selected
|
||||||
|
:zoom zoom
|
||||||
|
:edition edition}])
|
||||||
|
|
||||||
[:& snap-points {:layout layout
|
(when drawing-obj
|
||||||
:transform (:transform local)
|
[:& draw-area {:shape drawing-obj
|
||||||
:drawing drawing-obj
|
:zoom zoom
|
||||||
:zoom zoom
|
:modifiers (:modifiers local)}])
|
||||||
:page-id page-id
|
|
||||||
:selected selected}]
|
|
||||||
|
|
||||||
[:& snap-distances {:layout layout
|
(when (contains? layout :display-grid)
|
||||||
:zoom zoom
|
[:& frame-grid {:zoom zoom}])
|
||||||
:transform (:transform local)
|
|
||||||
:selected selected
|
|
||||||
:page-id page-id}]
|
|
||||||
|
|
||||||
(when tooltip
|
[:& snap-points {:layout layout
|
||||||
[:& cursor-tooltip {:zoom zoom :tooltip tooltip}])]
|
:transform (:transform local)
|
||||||
|
:drawing drawing-obj
|
||||||
|
:zoom zoom
|
||||||
|
:page-id page-id
|
||||||
|
:selected selected}]
|
||||||
|
|
||||||
[:& presence/active-cursors {:page-id page-id}]
|
[:& snap-distances {:layout layout
|
||||||
[:& selection-rect {:data (:selrect local)}]
|
:zoom zoom
|
||||||
(when (= options-mode :prototype)
|
:transform (:transform local)
|
||||||
[:& interactions {:selected selected}])]))
|
:selected selected
|
||||||
|
:page-id page-id}]
|
||||||
|
|
||||||
|
(when tooltip
|
||||||
|
[:& cursor-tooltip {:zoom zoom :tooltip tooltip}])]
|
||||||
|
|
||||||
|
[:& presence/active-cursors {:page-id page-id}]
|
||||||
|
[:& selection-rect {:data (:selrect local)}]
|
||||||
|
(when (= options-mode :prototype)
|
||||||
|
[:& interactions {:selected selected}])]]))
|
||||||
|
|
||||||
|
|
|
@ -51,9 +51,7 @@
|
||||||
(defn hex->hsl [hex]
|
(defn hex->hsl [hex]
|
||||||
(try
|
(try
|
||||||
(into [] (gcolor/hexToHsl hex))
|
(into [] (gcolor/hexToHsl hex))
|
||||||
(catch :default e (do
|
(catch :default e [0 0 0])))
|
||||||
(.log js/console e)
|
|
||||||
[0 0 0]))))
|
|
||||||
|
|
||||||
(defn hsl->rgb
|
(defn hsl->rgb
|
||||||
[[h s l]]
|
[[h s l]]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue