mirror of
https://github.com/penpot/penpot.git
synced 2025-01-08 07:50:43 -05:00
🎉 Add new text shape.
This commit is contained in:
parent
beed68166e
commit
aca1959dd7
11 changed files with 22141 additions and 468 deletions
|
@ -41,7 +41,7 @@
|
|||
;; Page Data related
|
||||
(s/def ::blocked boolean?)
|
||||
(s/def ::collapsed boolean?)
|
||||
(s/def ::content string?)
|
||||
(s/def ::content any?)
|
||||
(s/def ::fill-color string?)
|
||||
(s/def ::fill-opacity number?)
|
||||
(s/def ::font-family string?)
|
||||
|
|
|
@ -21,7 +21,8 @@
|
|||
}
|
||||
:aliases
|
||||
{:dev
|
||||
{:extra-deps
|
||||
{:extra-paths ["test" "dev"]
|
||||
:extra-deps
|
||||
{com.bhauman/rebel-readline-cljs {:mvn/version "0.1.4"}
|
||||
com.bhauman/rebel-readline {:mvn/version "0.1.4"}
|
||||
org.clojure/tools.namespace {:mvn/version "0.3.1"}
|
||||
|
@ -34,8 +35,7 @@
|
|||
|
||||
;; i18n parsing
|
||||
carocad/parcera {:mvn/version "0.11.0"}
|
||||
org.antlr/antlr4-runtime {:mvn/version "4.7"}}
|
||||
:extra-paths ["test"]}
|
||||
org.antlr/antlr4-runtime {:mvn/version "4.7"}}}
|
||||
|
||||
:repl
|
||||
{:main-opts ["-m" "rebel-readline.main"]}
|
||||
|
|
114
frontend/package-lock.json
generated
114
frontend/package-lock.json
generated
|
@ -18,6 +18,21 @@
|
|||
"resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz",
|
||||
"integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw=="
|
||||
},
|
||||
"@types/debounce": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/debounce/-/debounce-1.2.0.tgz",
|
||||
"integrity": "sha512-bWG5wapaWgbss9E238T0R6bfo5Fh3OkeoSt245CM7JJwVwpw6MEBCbIxLq5z8KzsE3uJhzcIuQkyiZmzV3M/Dw=="
|
||||
},
|
||||
"@types/esrever": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/esrever/-/esrever-0.2.0.tgz",
|
||||
"integrity": "sha512-5NI6TeGzVEy/iBcuYtcPzzIC6EqlfQ2+UZ54vT0ulq8bPNGAy8UJD+XcsAyEOcnYFUjOVWuUV+k4/rVkxt9/XQ=="
|
||||
},
|
||||
"@types/is-hotkey": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/is-hotkey/-/is-hotkey-0.1.1.tgz",
|
||||
"integrity": "sha512-QzVKww91fJv/KzARJBS/Im5GS2A8iE64E1HxOed72EmYOvPLG4PBw77QCIUjFl7VwWB3G/SVrxsHedJD/wtn1A=="
|
||||
},
|
||||
"@types/q": {
|
||||
"version": "1.5.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz",
|
||||
|
@ -947,6 +962,11 @@
|
|||
"integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
|
||||
"dev": true
|
||||
},
|
||||
"compute-scroll-into-view": {
|
||||
"version": "1.0.13",
|
||||
"resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.13.tgz",
|
||||
"integrity": "sha512-o+w9w7A98aAFi/GjK8cxSV+CdASuPa2rR5UWs3+yHkJzWqaKoBEufFNWYaXInCSmUfDCVhesG+v9MTWqOjsxFg=="
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
|
@ -1191,6 +1211,11 @@
|
|||
"integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==",
|
||||
"dev": true
|
||||
},
|
||||
"debounce": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.0.tgz",
|
||||
"integrity": "sha512-mYtLl1xfZLi1m4RtQYlZgJUNQjl4ZxVnHzIR8nLLgi4q1YT8o/WM+MK/f8yfcc9s5Ir5zRaPZyZU6xs1Syoocg=="
|
||||
},
|
||||
"debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
|
@ -1335,6 +1360,11 @@
|
|||
"randombytes": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"direction": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/direction/-/direction-1.0.4.tgz",
|
||||
"integrity": "sha512-GYqKi1aH7PJXxdhTeZBFrg8vUBeKXi+cNprXsC1kpJcbcVnV9wBsrOu1cQEdG0WeQwlfHiy3XvnKfIrJ2R0NzQ=="
|
||||
},
|
||||
"dom-serializer": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
|
||||
|
@ -1559,6 +1589,11 @@
|
|||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
|
||||
"dev": true
|
||||
},
|
||||
"esrever": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/esrever/-/esrever-0.2.0.tgz",
|
||||
"integrity": "sha1-lunSj08bGnZ4TNXUkOquAQ50B7g="
|
||||
},
|
||||
"events": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/events/-/events-3.1.0.tgz",
|
||||
|
@ -2977,6 +3012,11 @@
|
|||
"integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==",
|
||||
"dev": true
|
||||
},
|
||||
"immer": {
|
||||
"version": "5.3.6",
|
||||
"resolved": "https://registry.npmjs.org/immer/-/immer-5.3.6.tgz",
|
||||
"integrity": "sha512-pqWQ6ozVfNOUDjrLfm4Pt7q4Q12cGw2HUZgry4Q5+Myxu9nmHRkWBpI0J4+MK0AxbdFtdMTwEGVl7Vd+vEiK+A=="
|
||||
},
|
||||
"inflight": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||
|
@ -3143,6 +3183,11 @@
|
|||
"is-extglob": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"is-hotkey": {
|
||||
"version": "0.1.6",
|
||||
"resolved": "https://registry.npmjs.org/is-hotkey/-/is-hotkey-0.1.6.tgz",
|
||||
"integrity": "sha512-1+hMr0GLPM0M49UDRt9RgE8i+SM29UY4AGRP6sGz6fThOVXqSrEvTMakolhHMcVizJnPNAoMpEmE+Oi1k2NrZQ=="
|
||||
},
|
||||
"is-negated-glob": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz",
|
||||
|
@ -5015,6 +5060,14 @@
|
|||
"object-assign": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"scroll-into-view-if-needed": {
|
||||
"version": "2.2.24",
|
||||
"resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.24.tgz",
|
||||
"integrity": "sha512-vsC6SzyIZUyJG8o4nbUDCiIwsPdH6W/FVmjT2avR2hp/yzS53JjGmg/bKD20TkoNajbu5dAQN4xR7yes4qhwtQ==",
|
||||
"requires": {
|
||||
"compute-scroll-into-view": "^1.0.13"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||
|
@ -5204,6 +5257,62 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"slate": {
|
||||
"version": "0.57.1",
|
||||
"resolved": "https://registry.npmjs.org/slate/-/slate-0.57.1.tgz",
|
||||
"integrity": "sha512-av95C0zbsi0+khfOuyQlpZy0Q3Pqqh0loCusGGi0Wlb/J8OUBAyK/a5EgTfE0zK4pmjtEBnPksfBuVilg5jrNg==",
|
||||
"requires": {
|
||||
"@types/esrever": "^0.2.0",
|
||||
"esrever": "^0.2.0",
|
||||
"immer": "^5.0.0",
|
||||
"is-plain-object": "^3.0.0",
|
||||
"tiny-warning": "^1.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"is-plain-object": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.0.tgz",
|
||||
"integrity": "sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg==",
|
||||
"requires": {
|
||||
"isobject": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"isobject": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz",
|
||||
"integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"slate-react": {
|
||||
"version": "0.57.1",
|
||||
"resolved": "https://registry.npmjs.org/slate-react/-/slate-react-0.57.1.tgz",
|
||||
"integrity": "sha512-W+M+YEcqBvuJD2xoU1gKgGbvhv6shwYJ5OOjPF8ZPEokUvGJh81Egxf65ZnnKxJejodsERdlwc2rRjpRphx2LQ==",
|
||||
"requires": {
|
||||
"@types/debounce": "^1.2.0",
|
||||
"@types/is-hotkey": "^0.1.1",
|
||||
"debounce": "^1.2.0",
|
||||
"direction": "^1.0.3",
|
||||
"is-hotkey": "^0.1.6",
|
||||
"is-plain-object": "^3.0.0",
|
||||
"scroll-into-view-if-needed": "^2.2.20"
|
||||
},
|
||||
"dependencies": {
|
||||
"is-plain-object": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.0.tgz",
|
||||
"integrity": "sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg==",
|
||||
"requires": {
|
||||
"isobject": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"isobject": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz",
|
||||
"integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"snapdragon": {
|
||||
"version": "0.8.2",
|
||||
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
|
||||
|
@ -5934,6 +6043,11 @@
|
|||
"setimmediate": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"tiny-warning": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
|
||||
"integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="
|
||||
},
|
||||
"tinycolor2": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.1.tgz",
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
"react-color": "^2.18.0",
|
||||
"react-dom": "^16.13.1",
|
||||
"rxjs": "^7.0.0-beta.0",
|
||||
"slate": "^0.57.1",
|
||||
"slate-react": "^0.57.1",
|
||||
"source-map-support": "^0.5.16",
|
||||
"tdigest": "^0.1.1",
|
||||
"xregexp": "^4.3.0"
|
||||
|
|
21066
frontend/resources/fonts/gfonts.2020.04.23.json
Normal file
21066
frontend/resources/fonts/gfonts.2020.04.23.json
Normal file
File diff suppressed because it is too large
Load diff
4
frontend/resources/styles/main/partials/texts.scss
Normal file
4
frontend/resources/styles/main/partials/texts.scss
Normal file
|
@ -0,0 +1,4 @@
|
|||
foreignObject .rich-text {
|
||||
color: $color-black;
|
||||
height: 100%;
|
||||
}
|
218
frontend/src/uxbox/main/data/workspace/texts.cljs
Normal file
218
frontend/src/uxbox/main/data/workspace/texts.cljs
Normal file
|
@ -0,0 +1,218 @@
|
|||
;; 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 uxbox.main.data.workspace.texts
|
||||
(:require
|
||||
[beicon.core :as rx]
|
||||
[cljs.spec.alpha :as s]
|
||||
[clojure.set :as set]
|
||||
[goog.events :as events]
|
||||
[goog.object :as gobj]
|
||||
[potok.core :as ptk]
|
||||
[uxbox.main.fonts :as fonts]
|
||||
["slate" :as slate :refer [Editor Transforms Text]]))
|
||||
|
||||
(declare set-nodes!)
|
||||
(declare is-text?)
|
||||
|
||||
(defn assign-editor
|
||||
[editor]
|
||||
(ptk/reify ::assign-editor
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(assoc-in [:workspace-local :editor] editor)
|
||||
(update-in [:workspace-local :editor-n] (fnil inc 0))))))
|
||||
|
||||
;; --- Helpers
|
||||
|
||||
(defn set-nodes!
|
||||
([editor props]
|
||||
(set-nodes! editor props #js {}))
|
||||
([editor props options]
|
||||
(.setNodes Transforms editor props options)
|
||||
editor))
|
||||
|
||||
(defn is-text?
|
||||
[v]
|
||||
(.isText Text v))
|
||||
|
||||
(defn is-paragraph?
|
||||
[v]
|
||||
(= (.-type v) "paragraph"))
|
||||
|
||||
;; --- Predicates
|
||||
|
||||
(defn enabled?
|
||||
[editor universal? pred]
|
||||
(when editor
|
||||
(let [result (.nodes Editor editor #js {:match pred :universal universal?})
|
||||
match (first (es6-iterator-seq result))]
|
||||
(array? match))))
|
||||
|
||||
(defn text-decoration-enabled?
|
||||
[editor type]
|
||||
(enabled? editor true
|
||||
(fn [v]
|
||||
(let [val (unchecked-get v "textDecoration")]
|
||||
(identical? type val)))))
|
||||
|
||||
(defn text-transform-enabled?
|
||||
[editor type]
|
||||
(enabled? editor true
|
||||
(fn [v]
|
||||
(let [val (unchecked-get v "textTransform")]
|
||||
(identical? type val)))))
|
||||
|
||||
(defn text-align-enabled?
|
||||
[editor type]
|
||||
(enabled? editor false
|
||||
(fn [v]
|
||||
(let [val (unchecked-get v "textAlign")]
|
||||
(identical? type val)))))
|
||||
|
||||
(defn vertical-align-enabled?
|
||||
[editor type]
|
||||
(enabled? editor false
|
||||
(fn [v]
|
||||
(let [val (unchecked-get v "verticalAlign")]
|
||||
(identical? type val)))))
|
||||
|
||||
;; --- Getters
|
||||
|
||||
(defn current-value
|
||||
[editor {:keys [universal?
|
||||
attr
|
||||
pred
|
||||
at]
|
||||
:as opts}]
|
||||
(when editor
|
||||
(let [options #js {:match pred
|
||||
:universal universal?}
|
||||
_ (when at (unchecked-set options "at" at))
|
||||
|
||||
result (.nodes Editor editor options)
|
||||
match (ffirst (es6-iterator-seq result))]
|
||||
(when (object? match)
|
||||
(unchecked-get match attr)))))
|
||||
|
||||
(defn current-line-height
|
||||
[editor {:keys [at default]}]
|
||||
(or (current-value editor {:at at
|
||||
:pred is-paragraph?
|
||||
:attr "lineHeight"
|
||||
:universal? false})
|
||||
default))
|
||||
|
||||
(defn current-letter-spacing
|
||||
[editor {:keys [at default]}]
|
||||
(or (current-value editor {:at at
|
||||
:pred is-text?
|
||||
:attr "letterSpacing"
|
||||
:universal? true})
|
||||
default))
|
||||
|
||||
|
||||
(defn current-font-family
|
||||
[editor {:keys [at default]}]
|
||||
(or (current-value editor {:at at
|
||||
:pred is-text?
|
||||
:attr "fontId"
|
||||
:universal? true})
|
||||
default))
|
||||
|
||||
(defn current-font-size
|
||||
[editor {:keys [at default]}]
|
||||
(or (current-value editor {:at at
|
||||
:pred is-text?
|
||||
:attr "fontSize"
|
||||
:universal? true})
|
||||
default))
|
||||
|
||||
|
||||
(defn current-font-variant
|
||||
[editor {:keys [at default]}]
|
||||
(or (current-value editor {:at at
|
||||
:pred is-text?
|
||||
:attr "fontVariantId"
|
||||
:universal? true})
|
||||
default))
|
||||
|
||||
|
||||
;; --- Setters
|
||||
|
||||
|
||||
(defn set-text-decoration!
|
||||
[editor type]
|
||||
(set-nodes! editor
|
||||
#js {:textDecoration type}
|
||||
#js {:match is-text?
|
||||
:split true}))
|
||||
|
||||
(defn set-text-align!
|
||||
[editor type]
|
||||
(set-nodes! editor
|
||||
#js {:textAlign type}
|
||||
#js {:match is-paragraph?}))
|
||||
|
||||
(defn set-text-transform!
|
||||
[editor type]
|
||||
(set-nodes! editor
|
||||
#js {:textTransform type}
|
||||
#js {:match is-text?
|
||||
:split true}))
|
||||
|
||||
(defn set-vertical-align!
|
||||
[editor type]
|
||||
(set-nodes! editor
|
||||
#js {:verticalAlign type}
|
||||
#js {:match (fn [item]
|
||||
(= "text-box" (unchecked-get item "type")))}))
|
||||
|
||||
(defn set-line-height!
|
||||
[editor val at]
|
||||
(set-nodes! editor
|
||||
#js {:lineHeight val}
|
||||
#js {:at at
|
||||
:match is-paragraph?}))
|
||||
|
||||
(defn set-letter-spacing!
|
||||
[editor val at]
|
||||
(set-nodes! editor
|
||||
#js {:letterSpacing val}
|
||||
#js {:at at
|
||||
:match is-text?
|
||||
:split true}))
|
||||
|
||||
(defn set-font!
|
||||
[editor id family]
|
||||
(set-nodes! editor
|
||||
#js {:fontId id
|
||||
:fontFamily family}
|
||||
#js {:match is-text?
|
||||
:split true}))
|
||||
|
||||
(defn set-font-size!
|
||||
[editor val]
|
||||
(set-nodes! editor
|
||||
#js {:fontSize val}
|
||||
#js {:match is-text?
|
||||
:split true}))
|
||||
|
||||
(defn set-font-variant!
|
||||
[editor id weight style]
|
||||
(set-nodes! editor
|
||||
#js {:fontVariantId id
|
||||
:fontWeight weight
|
||||
:fontStyle style}
|
||||
#js {:match is-text?
|
||||
:split true}))
|
||||
|
||||
|
||||
|
178
frontend/src/uxbox/main/fonts.cljs
Normal file
178
frontend/src/uxbox/main/fonts.cljs
Normal file
|
@ -0,0 +1,178 @@
|
|||
;; 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 uxbox.main.fonts
|
||||
"Fonts management and loading logic."
|
||||
(:require
|
||||
[beicon.core :as rx]
|
||||
[okulary.core :as l]
|
||||
[cuerdas.core :as str]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.util.http :as http]
|
||||
[uxbox.util.transit :as t]
|
||||
[uxbox.util.timers :as ts]
|
||||
[uxbox.common.data :as d]
|
||||
[clojure.set :as set]))
|
||||
|
||||
(def local-fonts
|
||||
[{:id "sourcesanspro"
|
||||
:name "Source Sans Pro"
|
||||
:family "sourcesanspro"
|
||||
:variants [{:name "100" :weight "100" :style "normal"}
|
||||
{:name "100italic" :weight "100" :style "italic"}
|
||||
{:name "200" :weight "200" :style "normal"}
|
||||
{:name "200italic" :weight "200" :style "italic"}
|
||||
{:name "300" :weight "300" :style "normal"}
|
||||
{:name "300italic" :weight "300" :style "italic"}
|
||||
{:name "regular" :weight "400" :style "normal"}
|
||||
{:name "italic" :weight "400" :style "italic"}
|
||||
{:name "500" :weight "500" :style "normal"}
|
||||
{:name "500italic" :weight "500" :style "italic"}
|
||||
{:name "bold" :weight "bold" :style "normal"}
|
||||
{:name "bolditalic" :weight "bold" :style "italic"}
|
||||
{:name "black" :weight "900" :style "normal"}
|
||||
{:name "blackitalic" :weight "900" :style "italic"}]}
|
||||
{:id "roboto"
|
||||
:family "roboto"
|
||||
:name "Roboto"
|
||||
:variants [{:name "100" :weight "100" :style "normal"}
|
||||
{:name "100italic" :weight "100" :style "italic"}
|
||||
{:name "200" :weight "200" :style "normal"}
|
||||
{:name "200italic" :weight "200" :style "italic"}
|
||||
{:name "regular" :weight "400" :style "normal"}
|
||||
{:name "italic" :weight "400" :style "italic"}
|
||||
{:name "500" :weight "500" :style "normal"}
|
||||
{:name "500italic" :weight "500" :style "italic"}
|
||||
{:name "bold" :weight "bold" :style "normal"}
|
||||
{:name "bolditalic" :weight "bold" :style "italic"}
|
||||
{:name "black" :weight "900" :style "normal"}
|
||||
{:name "blackitalic" :weight "900" :style "italic"}]}
|
||||
{:id "robotocondensed"
|
||||
:family "robotocondensed"
|
||||
:name "Roboto Condensed"
|
||||
:variants [{:name "100" :weight "100" :style "normal"}
|
||||
{:name "100italic" :weight "100" :style "italic"}
|
||||
{:name "200" :weight "200" :style "normal"}
|
||||
{:name "200italic" :weight "200" :style "italic"}
|
||||
{:name "regular" :weight "400" :style "normal"}
|
||||
{:name "italic" :weight "400" :style "italic"}
|
||||
{:name "500" :weight "500" :style "normal"}
|
||||
{:name "500italic" :weight "500" :style "italic"}
|
||||
{:name "bold" :weight "bold" :style "normal"}
|
||||
{:name "bolditalic" :weight "bold" :style "italic"}
|
||||
{:name "black" :weight "900" :style "normal"}
|
||||
{:name "blackitalic" :weight "900" :style "italic"}]}])
|
||||
|
||||
(defonce fontsdb (l/atom {}))
|
||||
(defonce fontsview (l/atom {}))
|
||||
|
||||
(defn- materialize-fontsview
|
||||
[db]
|
||||
(reset! fontsview (reduce-kv (fn [acc k v]
|
||||
(assoc acc k (sort-by :name v)))
|
||||
{}
|
||||
(group-by :backend (vals db)))))
|
||||
(add-watch fontsdb "main"
|
||||
(fn [_ _ _ db]
|
||||
(ts/schedule-on-idle #(materialize-fontsview db))))
|
||||
|
||||
(defn register!
|
||||
[backend fonts]
|
||||
(let [fonts (map #(assoc % :backend backend) fonts)]
|
||||
(swap! fontsdb #(merge % (d/index-by :id fonts)))))
|
||||
|
||||
(register! :builtin local-fonts)
|
||||
|
||||
(defn resolve-variants
|
||||
[id]
|
||||
(get-in @fontsdb [id :variants]))
|
||||
|
||||
(defn resolve-fonts
|
||||
[backend]
|
||||
(get @fontsview backend))
|
||||
|
||||
;; --- Google Fonts Fetcher
|
||||
|
||||
(def ^:private gfonts-uri "/fonts/gfonts.2020.04.23.json")
|
||||
|
||||
(defn- parse-gfont-variant
|
||||
[variant]
|
||||
(cond
|
||||
(= "regular" variant)
|
||||
{:name "regular" :width "400" :style "normal"}
|
||||
|
||||
(= "italic" variant)
|
||||
{:name "italic" :width "400" :style "italic"}
|
||||
|
||||
:else
|
||||
(when-let [[a b c] (re-find #"^(\d+)(.*)$" variant)]
|
||||
(if (str/empty? c)
|
||||
{:name a :width b :style "normal"}
|
||||
{:name a :width b :style c}))))
|
||||
|
||||
(defn- parse-gfont
|
||||
[font]
|
||||
(let [family (get font "family")
|
||||
variants (get font "variants")]
|
||||
{:id (str "gfont-" (str/slug family))
|
||||
:family family
|
||||
:name family
|
||||
:variants (into [] (comp (map parse-gfont-variant)
|
||||
(filter identity))
|
||||
variants)}))
|
||||
|
||||
(let [url (unchecked-get js/location "origin")
|
||||
url (str url gfonts-uri)
|
||||
stm (->> (http/send! {:method :get :url url})
|
||||
(rx/map :body)
|
||||
(rx/map t/decode)
|
||||
(rx/mapcat #(get % "items"))
|
||||
(rx/map parse-gfont)
|
||||
(rx/reduce conj []))]
|
||||
(rx/subscribe stm #(register! :google %)))
|
||||
|
||||
;; --- Fonts Loader
|
||||
|
||||
(defonce loaded (l/atom #{}))
|
||||
|
||||
(defn- create-link-node
|
||||
[uri]
|
||||
(let [node (.createElement js/document "link")]
|
||||
(unchecked-set node "href" uri)
|
||||
(unchecked-set node "rel" "stylesheet")
|
||||
(unchecked-set node "type" "text/css")
|
||||
node))
|
||||
|
||||
(defmulti ^:private load-font :backend)
|
||||
|
||||
(defmethod load-font :builtin
|
||||
[{:keys [id] :as font}]
|
||||
(js/console.log "[debug:fonts]: loading builtin font" id))
|
||||
|
||||
(defmethod load-font :google
|
||||
[{:keys [id family variants] :as font}]
|
||||
(js/console.log "[debug:fonts]: loading google font" id)
|
||||
(let [base (str "https://fonts.googleapis.com/css?family=" family)
|
||||
variants (str/join "," (map :name variants))
|
||||
uri (str base ":" variants)
|
||||
node (create-link-node uri)]
|
||||
(.append (.-head js/document) node)
|
||||
nil))
|
||||
|
||||
(defmethod load-font :default
|
||||
[{:keys [backend] :as font}]
|
||||
(js/console.warn "no implementation found for" backend))
|
||||
|
||||
(defn ensure-loaded!
|
||||
[id]
|
||||
(when-not (contains? @loaded id)
|
||||
(when-let [font (get @fontsdb id)]
|
||||
(load-font font)
|
||||
(swap! loaded conj id))))
|
||||
|
|
@ -11,14 +11,22 @@
|
|||
[goog.object :as gobj]
|
||||
[lentes.core :as l]
|
||||
[rumext.alpha :as mf]
|
||||
[uxbox.common.data :as d]
|
||||
[uxbox.main.data.workspace :as dw]
|
||||
[uxbox.util.geom.shapes :as geom]
|
||||
[uxbox.main.data.workspace.texts :as dwt]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.ui.shapes.common :as common]
|
||||
[uxbox.main.ui.keyboard :as kbd]
|
||||
[uxbox.main.fonts :as fonts]
|
||||
[uxbox.util.color :as color]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.util.geom.matrix :as gmt]))
|
||||
[uxbox.util.geom.shapes :as geom]
|
||||
[uxbox.util.geom.matrix :as gmt]
|
||||
["slate" :as slate]
|
||||
["slate-react" :as rslate])
|
||||
(:import goog.events.EventType
|
||||
goog.events.KeyCodes))
|
||||
|
||||
;; --- Events
|
||||
|
||||
|
@ -54,111 +62,267 @@
|
|||
(dom/prevent-default event)
|
||||
(when selected?
|
||||
(st/emit! (dw/start-edition-mode (:id shape)))))]
|
||||
|
||||
[:g.shape {:on-double-click on-double-click
|
||||
:on-mouse-down on-mouse-down
|
||||
:on-context-menu on-context-menu}
|
||||
(if edition?
|
||||
[:& text-shape-edit {:shape (geom/transform-shape frame shape)}]
|
||||
[:& text-shape {:shape (geom/transform-shape frame shape)}])]))
|
||||
[:& text-shape {:shape (geom/transform-shape frame shape)
|
||||
:selected? selected?}])]))
|
||||
|
||||
;; --- Text Styles Helpers
|
||||
;; --- Text Rendering
|
||||
|
||||
(defn- make-style
|
||||
[{:keys [fill-color
|
||||
fill-opacity
|
||||
font-family
|
||||
font-weight
|
||||
font-style
|
||||
font-size
|
||||
text-align
|
||||
line-height
|
||||
letter-spacing
|
||||
user-select
|
||||
width
|
||||
height]
|
||||
:or {fill-color "#000000"
|
||||
fill-opacity 1
|
||||
font-family "sourcesanspro"
|
||||
font-weight "normal"
|
||||
font-style "normal"
|
||||
font-size 18
|
||||
line-height 1.4
|
||||
letter-spacing 1
|
||||
text-align "left"
|
||||
user-select false}
|
||||
:as shape}]
|
||||
(let [color (-> fill-color
|
||||
(color/hex->rgba fill-opacity)
|
||||
(color/rgb->str))]
|
||||
(rumext.util/map->obj
|
||||
(merge
|
||||
{:fontSize (str font-size "px")
|
||||
:color color
|
||||
:width width
|
||||
:height height
|
||||
:whiteSpace "pre-wrap"
|
||||
:textAlign text-align
|
||||
:fontFamily font-family
|
||||
:fontWeight font-weight
|
||||
:fontStyle font-style
|
||||
:margin "0px"
|
||||
:padding "0px"
|
||||
:border "0px"
|
||||
:resize "none"
|
||||
:background "transparent"}
|
||||
(when user-select {:userSelect "auto"})
|
||||
(when line-height {:lineHeight line-height})
|
||||
(when letter-spacing {:letterSpacing letter-spacing})))))
|
||||
(defn obj-assoc!
|
||||
[obj attr value]
|
||||
(unchecked-set obj attr value)
|
||||
obj)
|
||||
|
||||
(defn- generate-text-box-styles
|
||||
[data]
|
||||
(let [valign (unchecked-get data "verticalAlign")
|
||||
base #js {:height "100%"
|
||||
:width "100%"
|
||||
:display "flex"}]
|
||||
(cond-> base
|
||||
(= valign "top") (obj-assoc! "alignItems" "flex-start")
|
||||
(= valign "center") (obj-assoc! "alignItems" "center")
|
||||
(= valign "bottom") (obj-assoc! "alignItems" "flex-end"))))
|
||||
|
||||
(mf/defc rt-text-box
|
||||
{::mf/wrap-props false
|
||||
::mf/wrap [mf/memo]}
|
||||
[props]
|
||||
(let [attrs (unchecked-get props "attributes")
|
||||
childs (unchecked-get props "children")
|
||||
data (unchecked-get props "element")
|
||||
type (unchecked-get data "type")
|
||||
style (generate-text-box-styles data)
|
||||
attrs (obj-assoc! attrs "style" style)
|
||||
attrs (obj-assoc! attrs "className" type)]
|
||||
[:> :div attrs childs]))
|
||||
|
||||
(defn- generate-text-styles
|
||||
[data]
|
||||
(let [valign (unchecked-get data "verticalAlign")
|
||||
base #js {:display "inline-block"
|
||||
:width "100%"}]
|
||||
base))
|
||||
|
||||
(mf/defc rt-text
|
||||
{::mf/wrap-props false
|
||||
::mf/wrap [mf/memo]}
|
||||
[props]
|
||||
(let [attrs (unchecked-get props "attributes")
|
||||
childs (unchecked-get props "children")
|
||||
data (unchecked-get props "element")
|
||||
type (unchecked-get data "type")
|
||||
style (generate-text-styles data)
|
||||
attrs (obj-assoc! attrs "style" style)
|
||||
attrs (obj-assoc! attrs "className" type)]
|
||||
[:> :div attrs childs]))
|
||||
|
||||
(defn- generate-paragraph-styles
|
||||
[data]
|
||||
(let [base #js {:fontSize "14px"
|
||||
:margin "inherit"
|
||||
:lineHeight "1.2"}
|
||||
lh (unchecked-get data "lineHeight")
|
||||
ta (unchecked-get data "textAlign")]
|
||||
(cond-> base
|
||||
ta (obj-assoc! "textAlign" ta)
|
||||
lh (obj-assoc! "lineHeight" lh))))
|
||||
|
||||
(mf/defc rt-pharagraph
|
||||
{::mf/wrap-props false
|
||||
::mf/wrap [mf/memo]}
|
||||
[props]
|
||||
(let [attrs (unchecked-get props "attributes")
|
||||
childs (unchecked-get props "children")
|
||||
data (unchecked-get props "element")
|
||||
style (generate-paragraph-styles data)
|
||||
attrs (obj-assoc! attrs "style" style)]
|
||||
[:> :p attrs childs]))
|
||||
|
||||
(defn- generate-leaf-styles
|
||||
[data]
|
||||
(let [letter-spacing (unchecked-get data "letterSpacing")
|
||||
text-decoration (unchecked-get data "textDecoration")
|
||||
text-transform (unchecked-get data "textTransform")
|
||||
|
||||
font-id (unchecked-get data "fontId")
|
||||
font-variant-id (unchecked-get data "fontVariantId")
|
||||
|
||||
font-family (unchecked-get data "fontFamily")
|
||||
font-size (unchecked-get data "fontSize")
|
||||
|
||||
fontsdb (mf/deref fonts/fontsdb)
|
||||
|
||||
base #js {:textDecoration text-decoration
|
||||
:textTransform text-transform}]
|
||||
|
||||
(when (and (string? letter-spacing)
|
||||
(pos? (alength letter-spacing)))
|
||||
(obj-assoc! base "letterSpacing" (str letter-spacing "px")))
|
||||
|
||||
(when (and (string? font-size)
|
||||
(pos? (alength font-size)))
|
||||
(obj-assoc! base "fontSize" (str font-size "px")))
|
||||
|
||||
(when (and (string? font-id)
|
||||
(pos? (alength font-id)))
|
||||
(let [font (get fontsdb font-id)]
|
||||
(fonts/ensure-loaded! font-id)
|
||||
(let [font-family (or (:family font)
|
||||
(unchecked-get data "fontFamily"))
|
||||
font-variant (d/seek #(= font-variant-id (:name %))
|
||||
(:variants font))
|
||||
font-style (or (:style font-variant)
|
||||
(unchecked-get data "fontStyle"))
|
||||
font-weight (or (:weight font-variant)
|
||||
(unchecked-get data "fontWeight"))]
|
||||
(obj-assoc! base "fontFamily" font-family)
|
||||
(obj-assoc! base "fontStyle" font-style)
|
||||
(obj-assoc! base "fontWeight" font-weight))))
|
||||
|
||||
base))
|
||||
|
||||
(mf/defc rt-leaf
|
||||
{::mf/wrap-props false
|
||||
::mf/wrap [mf/memo]}
|
||||
[props]
|
||||
(let [attrs (unchecked-get props "attributes")
|
||||
childs (unchecked-get props "children")
|
||||
data (unchecked-get props "leaf")
|
||||
style (generate-leaf-styles data)
|
||||
attrs (obj-assoc! attrs "style" style)]
|
||||
[:> :span attrs childs]))
|
||||
|
||||
(defn- render-element
|
||||
[props]
|
||||
(mf/html
|
||||
(let [element (unchecked-get props "element")]
|
||||
(case (unchecked-get element "type")
|
||||
"text-box" [:> rt-text-box props]
|
||||
"text" [:> rt-text props]
|
||||
"paragraph" [:> rt-pharagraph props]
|
||||
nil))))
|
||||
|
||||
(defn- render-leaf
|
||||
[props]
|
||||
(mf/html
|
||||
[:> rt-leaf props]))
|
||||
|
||||
;; --- Text Shape Edit
|
||||
|
||||
(defn- initial-text
|
||||
([] (initial-text ""))
|
||||
([text]
|
||||
#js [#js {:type "text-box"
|
||||
:children #js [#js {:type "text"
|
||||
:children #js [#js {:type "paragraph"
|
||||
:children #js [#js {:text text}]}]}]}]))
|
||||
(defn- parse-content
|
||||
[content]
|
||||
(cond
|
||||
(string? content) (initial-text content)
|
||||
(vector? content) (clj->js content)
|
||||
(object? content) content
|
||||
:else (initial-text)))
|
||||
|
||||
(mf/defc text-shape-edit
|
||||
{::mf/wrap [mf/memo]}
|
||||
[{:keys [shape] :as props}]
|
||||
(let [ref (mf/use-ref)
|
||||
{:keys [id x y width height content]} shape
|
||||
(let [{:keys [id x y width height content]} shape
|
||||
|
||||
on-unmount
|
||||
state (mf/use-state #(parse-content content))
|
||||
value (mf/use-var @state)
|
||||
|
||||
editor (mf/use-memo #(rslate/withReact (slate/createEditor)))
|
||||
self-ref (mf/use-ref)
|
||||
|
||||
on-close
|
||||
(fn []
|
||||
(let [content (-> (mf/ref-val ref)
|
||||
(dom/get-value))]
|
||||
(st/emit! (dw/update-shape id {:content content}))))
|
||||
|
||||
|
||||
on-blur
|
||||
(fn [event]
|
||||
(st/emit! dw/clear-edition-mode
|
||||
dw/deselect-all))]
|
||||
(mf/use-effect
|
||||
#(let [dom (mf/ref-val ref)
|
||||
val (dom/get-value dom)]
|
||||
(.focus dom)
|
||||
(gobj/set dom "selectionStart" (count val))
|
||||
(gobj/set dom "selectionEnd" (count val))
|
||||
dw/deselect-all))
|
||||
|
||||
on-click
|
||||
(fn [event]
|
||||
(dom/prevent-default event)
|
||||
(dom/stop-propagation event)
|
||||
(let [sidebar (dom/get-element "settings-bar")
|
||||
self (mf/ref-val self-ref)
|
||||
target (dom/get-target event)]
|
||||
(when-not (or (.contains sidebar target)
|
||||
(.contains self target))
|
||||
(on-close))))
|
||||
|
||||
on-keyup
|
||||
(fn [event]
|
||||
(when (= (.-keyCode event) 27) ; ESC
|
||||
(on-close)))
|
||||
|
||||
on-mount
|
||||
(fn []
|
||||
(let [content (-> (mf/ref-val ref)
|
||||
(dom/get-value))]
|
||||
(st/emit! (dw/update-shape id {:content content}))))))
|
||||
(let [
|
||||
lkey1 (events/listen js/document EventType.CLICK on-click)
|
||||
lkey2 (events/listen js/document EventType.KEYUP on-keyup)]
|
||||
(st/emit! (dwt/assign-editor editor))
|
||||
#(let [content (js->clj @value)]
|
||||
(st/emit! (dwt/assign-editor nil)
|
||||
(dw/update-shape id {:content content}))
|
||||
(events/unlistenByKey lkey1)
|
||||
(events/unlistenByKey lkey2))))
|
||||
|
||||
on-change
|
||||
(mf/use-callback
|
||||
(fn [val]
|
||||
(st/emit! (dwt/assign-editor editor))
|
||||
(reset! state val)
|
||||
(reset! value val)))]
|
||||
|
||||
(mf/use-effect on-mount)
|
||||
|
||||
[:foreignObject {:x x :y y :width width :height height}
|
||||
[:textarea {:style (make-style shape)
|
||||
:on-blur on-blur
|
||||
:default-value content
|
||||
:ref ref}]]))
|
||||
[:foreignObject {:x x :y y :width width :height height :ref self-ref}
|
||||
[:> rslate/Slate {:editor editor
|
||||
:value @state
|
||||
:on-change on-change}
|
||||
[:> rslate/Editable
|
||||
{:auto-focus "true"
|
||||
:spell-check "false"
|
||||
:class "rich-text"
|
||||
:render-element render-element
|
||||
:render-leaf render-leaf
|
||||
:on-blur (fn [event]
|
||||
(dom/prevent-default event)
|
||||
(dom/stop-propagation event)
|
||||
;; WARN: monky patch
|
||||
(unchecked-set slate/Transforms "deselect" (constantly nil)))
|
||||
:placeholder "Type some text here..."}]]]))
|
||||
|
||||
;; --- Text Shape Wrapper
|
||||
|
||||
(mf/defc text-shape
|
||||
[{:keys [shape] :as props}]
|
||||
[{:keys [shape selected?] :as props}]
|
||||
(let [{:keys [id x y width height rotation content]} shape
|
||||
|
||||
transform (when (and rotation (pos? rotation))
|
||||
(str/format "rotate(%s %s %s)"
|
||||
rotation
|
||||
(+ x (/ width 2))
|
||||
(+ y (/ height 2))))]
|
||||
(+ y (/ height 2))))
|
||||
|
||||
content (parse-content content)
|
||||
editor (mf/use-memo #(rslate/withReact (slate/createEditor)))
|
||||
|
||||
on-mount
|
||||
(fn []
|
||||
(when selected?
|
||||
(st/emit! (dwt/assign-editor editor))
|
||||
#(st/emit! (dwt/assign-editor nil))))
|
||||
|
||||
render-element (mf/use-callback render-element)
|
||||
render-leaf (mf/use-callback render-leaf)]
|
||||
|
||||
(mf/use-effect (mf/deps id selected?) on-mount)
|
||||
|
||||
[:foreignObject {:x x
|
||||
:y y
|
||||
|
@ -166,4 +330,12 @@
|
|||
:id (str id)
|
||||
:width width
|
||||
:height height}
|
||||
[:div {:style (make-style shape)} content]]))
|
||||
|
||||
[:> rslate/Slate {:editor editor
|
||||
:value content}
|
||||
[:> rslate/Editable {:auto-focus "false"
|
||||
:read-only "true"
|
||||
:class "rich-text"
|
||||
:render-element render-element
|
||||
:render-leaf render-leaf
|
||||
:placeholder "Type some text here..."}]]]))
|
||||
|
|
|
@ -64,7 +64,7 @@
|
|||
:segments []}
|
||||
{:type :text
|
||||
:name "Text"
|
||||
:content "Type your text here"}])
|
||||
:content nil}])
|
||||
|
||||
(defn start-drawing
|
||||
[type]
|
||||
|
|
|
@ -10,415 +10,334 @@
|
|||
(ns uxbox.main.ui.workspace.sidebar.options.text
|
||||
(:require
|
||||
[rumext.alpha :as mf]
|
||||
[okulary.core :as l]
|
||||
[uxbox.builtins.icons :as i]
|
||||
[uxbox.common.data :as d]
|
||||
[uxbox.main.data.workspace :as dw]
|
||||
[uxbox.main.data.workspace.texts :as dwt]
|
||||
[uxbox.main.store :as st]
|
||||
[uxbox.main.refs :as refs]
|
||||
[uxbox.main.ui.workspace.sidebar.options.measures :refer [measures-menu]]
|
||||
[uxbox.util.dom :as dom]
|
||||
[uxbox.main.fonts :as fonts]
|
||||
[uxbox.util.math :as math]
|
||||
[uxbox.util.i18n :refer [tr]]))
|
||||
[uxbox.util.i18n :as i18n :refer [tr t]]
|
||||
["slate" :refer [Transforms]]))
|
||||
|
||||
(declare +fonts+)
|
||||
(def ^:private editor-ref
|
||||
(l/derived :editor refs/workspace-local))
|
||||
|
||||
(mf/defc fonts-menu
|
||||
[{:keys [shape] :as props}]
|
||||
(let [id (:id shape)
|
||||
font-family (:font-family shape "sourcesanspro")
|
||||
font-style (:font-style shape "normal")
|
||||
font-weight (:font-weight shape "normal")
|
||||
font-size (:font-size shape 16)
|
||||
text-align (:text-align shape "left")
|
||||
line-height (:line-height shape 1.4)
|
||||
letter-spacing (:letter-spacing shape 1)
|
||||
(mf/defc font-select-optgroups
|
||||
{::mf/wrap [mf/memo]}
|
||||
[]
|
||||
[:*
|
||||
[:optgroup {:label "Local"}
|
||||
(for [font fonts/local-fonts]
|
||||
[:option {:value (:id font)
|
||||
:key (:id font)}
|
||||
(:name font)])]
|
||||
[:optgroup {:label "Google"}
|
||||
(for [font (fonts/resolve-fonts :google)]
|
||||
[:option {:value (:id font)
|
||||
:key (:id font)}
|
||||
(:name font)])]])
|
||||
|
||||
styles (:styles (d/seek #(= (:id %) font-family) +fonts+))
|
||||
(mf/defc font-options
|
||||
[{:keys [editor shape] :as props}]
|
||||
(let [selection (mf/use-ref)
|
||||
font-id (dwt/current-font-family editor {:default "sourcesanspro"})
|
||||
font-size (dwt/current-font-size editor {:default "14"})
|
||||
font-var (dwt/current-font-variant editor {:default "regular"})
|
||||
|
||||
fonts (mf/deref fonts/fontsdb)
|
||||
font (get fonts font-id)
|
||||
|
||||
on-font-family-change
|
||||
(fn [event]
|
||||
(let [value (-> (dom/get-target event)
|
||||
(dom/get-value))
|
||||
attrs {:font-family value
|
||||
:font-weight "normal"
|
||||
:font-style "normal"}]
|
||||
(st/emit! (dw/update-shape id attrs))))
|
||||
(let [id (-> (dom/get-target event)
|
||||
(dom/get-value))
|
||||
font (get fonts id)]
|
||||
(dwt/set-font! editor id (:family font))
|
||||
(when (not= id font-id)
|
||||
(dwt/set-font-variant! editor nil nil nil))))
|
||||
|
||||
on-font-size-change
|
||||
(fn [event]
|
||||
(let [value (-> (dom/get-target event)
|
||||
(dom/get-value)
|
||||
(d/parse-integer 0))
|
||||
attrs {:font-size value}]
|
||||
(st/emit! (dw/update-shape id attrs))))
|
||||
(let [val (-> (dom/get-target event)
|
||||
(dom/get-value))]
|
||||
(dwt/set-font-size! editor val)))
|
||||
|
||||
on-font-letter-spacing-change
|
||||
on-font-variant-change
|
||||
(fn [event]
|
||||
(let [value (-> (dom/get-target event)
|
||||
(dom/get-value)
|
||||
(d/parse-double 0))
|
||||
attrs {:letter-spacing value}]
|
||||
(st/emit! (dw/update-shape id attrs))))
|
||||
|
||||
on-font-line-height-change
|
||||
(fn [event]
|
||||
(let [value (-> (dom/get-target event)
|
||||
(dom/get-value)
|
||||
(d/parse-double 0))
|
||||
attrs {:line-height value}]
|
||||
(st/emit! (dw/update-shape id attrs))))
|
||||
|
||||
on-font-align-change
|
||||
(fn [event value]
|
||||
(let [attrs {:text-align value}]
|
||||
(st/emit! (dw/update-shape id attrs))))
|
||||
|
||||
on-font-style-change
|
||||
(fn [event]
|
||||
(let [[weight style] (-> (dom/get-target event)
|
||||
(dom/get-value)
|
||||
(d/read-string))
|
||||
attrs {:font-style style
|
||||
:font-weight weight}]
|
||||
(st/emit! (dw/update-shape id attrs))))
|
||||
(let [id (-> (dom/get-target event)
|
||||
(dom/get-value))
|
||||
variant (d/seek #(= id (:name %)) (:variants font))]
|
||||
(dwt/set-font! editor (:id font) (:family font))
|
||||
(dwt/set-font-variant! editor id (:weight variant) (:style variant))))
|
||||
]
|
||||
[:*
|
||||
[:div.row-flex
|
||||
[:select.input-select {:value font-id
|
||||
:on-change on-font-family-change}
|
||||
[:& font-select-optgroups]]]
|
||||
|
||||
[:div.row-flex
|
||||
[:div.editable-select
|
||||
[:select.input-select {:value font-size
|
||||
:on-change on-font-size-change}
|
||||
[:option {:value "8"} "8"]
|
||||
[:option {:value "9"} "9"]
|
||||
[:option {:value "10"} "10"]
|
||||
[:option {:value "11"} "11"]
|
||||
[:option {:value "12"} "12"]
|
||||
[:option {:value "14"} "14"]
|
||||
[:option {:value "18"} "18"]
|
||||
[:option {:value "24"} "24"]
|
||||
[:option {:value "36"} "36"]
|
||||
[:option {:value "48"} "48"]
|
||||
[:option {:value "72"} "72"]]
|
||||
[:input.input-text {:type "number"
|
||||
:min "0"
|
||||
:max "200"
|
||||
:value font-size
|
||||
:on-change on-font-size-change
|
||||
}]]
|
||||
|
||||
[:select.input-select {:value font-var
|
||||
:on-change on-font-variant-change}
|
||||
(for [variant (:variants font)]
|
||||
[:option {:value (:name variant)
|
||||
:key (pr-str variant)}
|
||||
(:name variant)])]]]))
|
||||
|
||||
|
||||
(mf/defc text-align-options
|
||||
[{:keys [editor] :as props}]
|
||||
(let [on-text-align-change
|
||||
(fn [event type]
|
||||
(js/console.log (dwt/set-text-align! editor type)))]
|
||||
;; --- Align
|
||||
|
||||
[:div.row-flex.align-icons
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "Align left"
|
||||
:class (dom/classnames
|
||||
:current (dwt/text-align-enabled? editor "left"))
|
||||
:on-click #(on-text-align-change % "left")}
|
||||
i/text-align-left]
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "Align center"
|
||||
:class (dom/classnames
|
||||
:current (dwt/text-align-enabled? editor "center"))
|
||||
:on-click #(on-text-align-change % "center")}
|
||||
i/text-align-center]
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "Align right"
|
||||
:class (dom/classnames
|
||||
:current (dwt/text-align-enabled? editor "right"))
|
||||
:on-click #(on-text-align-change % "right")}
|
||||
i/text-align-right]
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "Justify"
|
||||
:class (dom/classnames
|
||||
:current (dwt/text-align-enabled? editor "justify"))
|
||||
:on-click #(on-text-align-change % "justify")}
|
||||
i/text-align-justify]]))
|
||||
|
||||
(mf/defc spacing-options
|
||||
[{:keys [editor] :as props}]
|
||||
(let [selection (mf/use-ref)
|
||||
lh (dwt/current-line-height editor {:default "1.2"
|
||||
:at (mf/ref-val selection)})
|
||||
ls (dwt/current-letter-spacing editor {:default "0"
|
||||
:at (mf/ref-val selection)})]
|
||||
[:div.row-flex
|
||||
[:div.input-icon
|
||||
[:span.icon-before.tooltip.tooltip-bottom
|
||||
{:alt "Line height"}
|
||||
i/line-height]
|
||||
[:input.input-text
|
||||
{:type "number"
|
||||
:step "0.1"
|
||||
:min "0"
|
||||
:max "200"
|
||||
:value lh
|
||||
:on-focus (fn [event]
|
||||
(js/console.log "line-height on-focus")
|
||||
;; (mf/set-ref-val! selection (.-selection editor))
|
||||
(dom/prevent-default event)
|
||||
(dom/stop-propagation event))
|
||||
:on-blur (fn [event]
|
||||
;; (js/console.log "line-height on-blur")
|
||||
(mf/set-ref-val! selection nil)
|
||||
(dom/prevent-default event)
|
||||
(dom/stop-propagation event))
|
||||
:on-change (fn [event]
|
||||
(let [val (-> (dom/get-target event)
|
||||
(dom/get-value))
|
||||
sel (mf/ref-val selection)]
|
||||
;; (js/console.log "line-height on-change" sel val)
|
||||
(dwt/set-line-height! editor val sel)))}]]
|
||||
[:div.input-icon
|
||||
[:span.icon-before.tooltip.tooltip-bottom
|
||||
{:alt "Letter spacing"}
|
||||
i/letter-spacing]
|
||||
[:input.input-text
|
||||
{:type "number"
|
||||
:step "0.1"
|
||||
:min "0"
|
||||
:max "200"
|
||||
:value ls
|
||||
:on-focus (fn [event]
|
||||
;; (js/console.log "letter-spacing on-focus")
|
||||
(mf/set-ref-val! selection (.-selection editor))
|
||||
(dom/prevent-default event)
|
||||
(dom/stop-propagation event))
|
||||
:on-blur (fn [event]
|
||||
;; (js/console.log "letter-spacing on-blur")
|
||||
(mf/set-ref-val! selection nil)
|
||||
(dom/prevent-default event)
|
||||
(dom/stop-propagation event))
|
||||
:on-change (fn [event]
|
||||
(let [val (-> (dom/get-target event)
|
||||
(dom/get-value))
|
||||
sel (mf/ref-val selection)]
|
||||
;; (js/console.log "letter-spacing on-change" sel val)
|
||||
(dwt/set-letter-spacing! editor val sel)))}]]]))
|
||||
|
||||
(mf/defc box-sizing-options
|
||||
[{:keys [editor] :as props}]
|
||||
[:div.align-icons
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "Auto height"}
|
||||
i/auto-height]
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "Auto width"}
|
||||
i/auto-width]
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "Fixed size"}
|
||||
i/auto-fix]])
|
||||
|
||||
(mf/defc vertical-align-options
|
||||
[{:keys [editor] :as props}]
|
||||
(let [on-vertical-align-change
|
||||
(fn [event type]
|
||||
(dwt/set-vertical-align! editor type))]
|
||||
[:div.align-icons
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "Align top"
|
||||
:class (dom/classnames
|
||||
:current (dwt/vertical-align-enabled? editor "top"))
|
||||
:on-click #(on-vertical-align-change % "top")}
|
||||
i/align-top]
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "Align middle"
|
||||
:class (dom/classnames
|
||||
:current (dwt/vertical-align-enabled? editor "center"))
|
||||
:on-click #(on-vertical-align-change % "center")}
|
||||
i/align-middle]
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "Align bottom"
|
||||
:class (dom/classnames
|
||||
:current (dwt/vertical-align-enabled? editor "bottom"))
|
||||
:on-click #(on-vertical-align-change % "bottom")}
|
||||
i/align-bottom]]))
|
||||
|
||||
(mf/defc text-decoration-options
|
||||
[{:keys [editor] :as props}]
|
||||
(let [on-decoration-change
|
||||
(fn [event type]
|
||||
(dom/prevent-default event)
|
||||
(dom/stop-propagation event)
|
||||
(if (dwt/text-decoration-enabled? editor type)
|
||||
(dwt/set-text-decoration! editor "none")
|
||||
(dwt/set-text-decoration! editor type)))]
|
||||
[:div.row-flex
|
||||
[:span.element-set-subtitle "Decoration"]
|
||||
[:div.align-icons
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "None"
|
||||
:on-click #(on-decoration-change % "none")}
|
||||
i/minus]
|
||||
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "Underline"
|
||||
:class (dom/classnames
|
||||
:current (dwt/text-decoration-enabled? editor "underline"))
|
||||
:on-click #(on-decoration-change % "underline")}
|
||||
i/underline]
|
||||
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "Strikethrough"
|
||||
:class (dom/classnames
|
||||
:current (dwt/text-decoration-enabled? editor "line-through"))
|
||||
:on-click #(on-decoration-change % "line-through")}
|
||||
i/strikethrough]]]))
|
||||
|
||||
|
||||
(mf/defc text-transform-options
|
||||
[{:keys [editor] :as props}]
|
||||
(let [on-text-transform-change
|
||||
(fn [event type]
|
||||
(dom/prevent-default event)
|
||||
(dom/stop-propagation event)
|
||||
(if (dwt/text-transform-enabled? editor type)
|
||||
(dwt/set-text-transform! editor "none")
|
||||
(dwt/set-text-transform! editor type)))]
|
||||
[:div.row-flex
|
||||
[:span.element-set-subtitle "Case"]
|
||||
[:div.align-icons
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "None"
|
||||
:class (dom/classnames
|
||||
:current (dwt/text-transform-enabled? editor "none"))
|
||||
:on-click #(on-text-transform-change % "none")}
|
||||
|
||||
i/minus]
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "Uppercase"
|
||||
:class (dom/classnames
|
||||
:current (dwt/text-transform-enabled? editor "uppercase"))
|
||||
:on-click #(on-text-transform-change % "uppercase")}
|
||||
|
||||
i/uppercase]
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "Lowercase"
|
||||
:class (dom/classnames
|
||||
:current (dwt/text-transform-enabled? editor "lowercase"))
|
||||
:on-click #(on-text-transform-change % "lowercase")}
|
||||
|
||||
i/lowercase]
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "Titlecase"
|
||||
:class (dom/classnames
|
||||
:current (dwt/text-transform-enabled? editor "capitalize"))
|
||||
:on-click #(on-text-transform-change % "capitalize")}
|
||||
i/titlecase]]]))
|
||||
|
||||
(mf/defc text-menu
|
||||
{::mf/wrap [mf/memo]}
|
||||
[{:keys [shape] :as props}]
|
||||
(let [id (:id shape)
|
||||
editor (:editor (mf/deref refs/workspace-local))
|
||||
locale (i18n/use-locale)]
|
||||
|
||||
[:div.element-set
|
||||
[:div.element-set-title (tr "workspace.options.font-options")]
|
||||
[:div.element-set-title (t locale "workspace.options.font-options")]
|
||||
[:div.element-set-content
|
||||
[:div.row-flex
|
||||
[:select.input-select {:value font-family
|
||||
:on-change on-font-family-change}
|
||||
(for [font +fonts+]
|
||||
[:option {:value (:id font)
|
||||
:key (:id font)}
|
||||
(:name font)])]]
|
||||
[:& font-options {:editor editor}]
|
||||
[:& text-align-options {:editor editor}]
|
||||
[:& spacing-options {:editor editor}]
|
||||
|
||||
[:div.row-flex
|
||||
[:div.editable-select
|
||||
[:select.input-select {:value font-size
|
||||
:on-change on-font-size-change}
|
||||
[:option {:value "8"} "8"]
|
||||
[:option {:value "9"} "9"]
|
||||
[:option {:value "10"} "10"]
|
||||
[:option {:value "11"} "11"]
|
||||
[:option {:value "12"} "12"]
|
||||
[:option {:value "14"} "14"]
|
||||
[:option {:value "18"} "18"]
|
||||
[:option {:value "24"} "24"]
|
||||
[:option {:value "36"} "36"]
|
||||
[:option {:value "48"} "48"]
|
||||
[:option {:value "72"} "72"]]
|
||||
[:input.input-text {:type "number"
|
||||
:min "0"
|
||||
:max "200"
|
||||
:value (-> font-size
|
||||
(math/precision 2)
|
||||
(d/coalesce-str "0"))
|
||||
:on-change on-font-size-change}]]
|
||||
[:& vertical-align-options {:editor editor}]
|
||||
[:& box-sizing-options {:editor editor}]]
|
||||
|
||||
[:select.input-select {:value (pr-str [font-weight font-style])
|
||||
:on-change on-font-style-change}
|
||||
(for [style styles
|
||||
:let [data (mapv #(get style %) [:weight :style])]]
|
||||
[:option {:value (pr-str data)
|
||||
:key (:name style)}
|
||||
(:name style)])]]
|
||||
|
||||
[:div.row-flex.align-icons
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "Align left"
|
||||
:class (when (= text-align "left") "current")
|
||||
:on-click #(on-font-align-change % "left")}
|
||||
i/text-align-left]
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "Align center"
|
||||
:class (when (= text-align "center") "current")
|
||||
:on-click #(on-font-align-change % "center")}
|
||||
i/text-align-center]
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "Align right"
|
||||
:class (when (= text-align "right") "current")
|
||||
:on-click #(on-font-align-change % "right")}
|
||||
i/text-align-right]
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "Justify"
|
||||
:class (when (= text-align "justify") "current")
|
||||
:on-click #(on-font-align-change % "justify")}
|
||||
i/text-align-justify]]
|
||||
|
||||
[:div.row-flex
|
||||
[:div.input-icon
|
||||
[:span.icon-before.tooltip.tooltip-bottom
|
||||
{:alt "Line height"}
|
||||
i/line-height]
|
||||
[:input.input-text {:type "number"
|
||||
:step "0.1"
|
||||
:min "0"
|
||||
:max "200"
|
||||
:value (-> line-height
|
||||
(math/precision 2)
|
||||
(d/coalesce-str "0"))
|
||||
:on-change on-font-line-height-change}]]
|
||||
[:div.input-icon
|
||||
[:span.icon-before.tooltip.tooltip-bottom
|
||||
{:alt "Letter spacing"}
|
||||
i/letter-spacing]
|
||||
[:input.input-text {:type "number"
|
||||
:step "0.1"
|
||||
:min "0"
|
||||
:max "200"
|
||||
:value (-> letter-spacing
|
||||
(math/precision 2)
|
||||
(d/coalesce-str "0"))
|
||||
:on-change on-font-letter-spacing-change}]]]
|
||||
|
||||
[:div.row-flex
|
||||
[:div.align-icons
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "Align top"}
|
||||
i/align-top]
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "Align middle"}
|
||||
i/align-middle]
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "Align bottom"}
|
||||
i/align-bottom]]
|
||||
|
||||
[:div.align-icons
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "Auto height"}
|
||||
i/auto-height]
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "Auto width"}
|
||||
i/auto-width]
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "Fixed size"}
|
||||
i/auto-fix]]]
|
||||
|
||||
[:div.row-flex
|
||||
[:span.element-set-subtitle "Decoration"]
|
||||
[:div.align-icons
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "None"}
|
||||
i/minus]
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "Underline"}
|
||||
i/underline]
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "Strikethrough"}
|
||||
i/strikethrough]]]
|
||||
|
||||
[:div.row-flex
|
||||
[:span.element-set-subtitle "Case"]
|
||||
[:div.align-icons
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "None"}
|
||||
i/minus]
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "Uppercase"}
|
||||
i/uppercase]
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "Lowercase"}
|
||||
i/lowercase]
|
||||
[:span.tooltip.tooltip-bottom
|
||||
{:alt "Titlecase"}
|
||||
i/titlecase]]]
|
||||
]]))
|
||||
|
||||
(def +fonts+
|
||||
[{:id "sourcesanspro"
|
||||
:name "Source Sans Pro"
|
||||
:styles [{:name "Extra-Light"
|
||||
:weight "100"
|
||||
:style "normal"}
|
||||
{:name "Extra-Light Italic"
|
||||
:weight "100"
|
||||
:style "italic"}
|
||||
{:name "Light"
|
||||
:weight "200"
|
||||
:style "normal"}
|
||||
{:name "Light Italic"
|
||||
:weight "200"
|
||||
:style "italic"}
|
||||
{:name "Regular"
|
||||
:weight "normal"
|
||||
:style "normal"}
|
||||
{:name "Italic"
|
||||
:weight "normal"
|
||||
:style "italic"}
|
||||
{:name "Semi-Bold"
|
||||
:weight "500"
|
||||
:style "normal"}
|
||||
{:name "Semi-Bold Italic"
|
||||
:weight "500"
|
||||
:style "italic"}
|
||||
{:name "Bold"
|
||||
:weight "bold"
|
||||
:style "normal"}
|
||||
{:name "Bold Italic"
|
||||
:weight "bold"
|
||||
:style "italic"}
|
||||
{:name "Black"
|
||||
:weight "900"
|
||||
:style "normal"}
|
||||
{:name "Black Italic"
|
||||
:weight "900"
|
||||
:style "italic"}]}
|
||||
{:id "opensans"
|
||||
:name "Open Sans"
|
||||
:styles [{:name "Extra-Light"
|
||||
:weight "100"
|
||||
:style "normal"}
|
||||
{:name "Extra-Light Italic"
|
||||
:weight "100"
|
||||
:style "italic"}
|
||||
{:name "Light"
|
||||
:weight "200"
|
||||
:style "normal"}
|
||||
{:name "Light Italic"
|
||||
:weight "200"
|
||||
:style "italic"}
|
||||
{:name "Regular"
|
||||
:weight "normal"
|
||||
:style "normal"}
|
||||
{:name "Italic"
|
||||
:weight "normal"
|
||||
:style "italic"}
|
||||
{:name "Semi-Bold"
|
||||
:weight "500"
|
||||
:style "normal"}
|
||||
{:name "Semi-Bold Italic"
|
||||
:weight "500"
|
||||
:style "italic"}
|
||||
{:name "Bold"
|
||||
:weight "bold"
|
||||
:style "normal"}
|
||||
{:name "Bold Italic"
|
||||
:weight "bold"
|
||||
:style "italic"}
|
||||
{:name "Black"
|
||||
:weight "900"
|
||||
:style "normal"}
|
||||
{:name "Black Italic"
|
||||
:weight "900"
|
||||
:style "italic"}]}
|
||||
{:id "bebas"
|
||||
:name "Bebas"
|
||||
:styles [{:name "Normal"
|
||||
:weight "normal"
|
||||
:style "normal"}]}
|
||||
{:id "gooddog"
|
||||
:name "Good Dog"
|
||||
:styles [{:name "Normal"
|
||||
:weight "normal"
|
||||
:style "normal"}]}
|
||||
{:id "caviardreams"
|
||||
:name "Caviar Dreams"
|
||||
:styles [{:name "Normal"
|
||||
:weight "normal"
|
||||
:style "normal"}
|
||||
{:name "Normal Italic"
|
||||
:weight "normal"
|
||||
:style "italic"}
|
||||
{:name "Bold"
|
||||
:weight "bold"
|
||||
:style "normal"}
|
||||
{:name "Bold Italic"
|
||||
:weight "bold"
|
||||
:style "italic"}]}
|
||||
{:id "ptsans"
|
||||
:name "PT Sans"
|
||||
:styles [{:name "Normal"
|
||||
:weight "normal"
|
||||
:style "normal"}
|
||||
{:name "Normal Italic"
|
||||
:weight "normal"
|
||||
:style "italic"}
|
||||
{:name "Bold"
|
||||
:weight "bold"
|
||||
:style "normal"}
|
||||
{:name "Bold Italic"
|
||||
:weight "bold"
|
||||
:style "italic"}]}
|
||||
{:id "roboto"
|
||||
:name "Roboto"
|
||||
:styles [{:name "Extra-Light"
|
||||
:weight "100"
|
||||
:style "normal"}
|
||||
{:name "Extra-Light Italic"
|
||||
:weight "100"
|
||||
:style "italic"}
|
||||
{:name "Light"
|
||||
:weight "200"
|
||||
:style "normal"}
|
||||
{:name "Light Italic"
|
||||
:weight "200"
|
||||
:style "italic"}
|
||||
{:name "Regular"
|
||||
:weight "normal"
|
||||
:style "normal"}
|
||||
{:name "Italic"
|
||||
:weight "normal"
|
||||
:style "italic"}
|
||||
{:name "Semi-Bold"
|
||||
:weight "500"
|
||||
:style "normal"}
|
||||
{:name "Semi-Bold Italic"
|
||||
:weight "500"
|
||||
:style "italic"}
|
||||
{:name "Bold"
|
||||
:weight "bold"
|
||||
:style "normal"}
|
||||
{:name "Bold Italic"
|
||||
:weight "bold"
|
||||
:style "italic"}
|
||||
{:name "Black"
|
||||
:weight "900"
|
||||
:style "normal"}
|
||||
{:name "Black Italic"
|
||||
:weight "900"
|
||||
:style "italic"}]}
|
||||
{:id "robotocondensed"
|
||||
:name "Roboto Condensed"
|
||||
:styles [{:name "Extra-Light"
|
||||
:weight "100"
|
||||
:style "normal"}
|
||||
{:name "Extra-Light Italic"
|
||||
:weight "100"
|
||||
:style "italic"}
|
||||
{:name "Light"
|
||||
:weight "200"
|
||||
:style "normal"}
|
||||
{:name "Light Italic"
|
||||
:weight "200"
|
||||
:style "italic"}
|
||||
{:name "Regular"
|
||||
:weight "normal"
|
||||
:style "normal"}
|
||||
{:name "Italic"
|
||||
:weight "normal"
|
||||
:style "italic"}
|
||||
{:name "Semi-Bold"
|
||||
:weight "500"
|
||||
:style "normal"}
|
||||
{:name "Semi-Bold Italic"
|
||||
:weight "500"
|
||||
:style "italic"}
|
||||
{:name "Bold"
|
||||
:weight "bold"
|
||||
:style "normal"}
|
||||
{:name "Bold Italic"
|
||||
:weight "bold"
|
||||
:style "italic"}
|
||||
{:name "Black"
|
||||
:weight "900"
|
||||
:style "normal"}
|
||||
{:name "Black Italic"
|
||||
:weight "900"
|
||||
:style "italic"}]}
|
||||
])
|
||||
[:& text-decoration-options {:editor editor}]
|
||||
[:& text-transform-options {:editor editor}]]]))
|
||||
|
||||
(mf/defc options
|
||||
[{:keys [shape] :as props}]
|
||||
[:div
|
||||
[:& measures-menu {:shape shape}]
|
||||
[:& fonts-menu {:shape shape}]])
|
||||
[:& text-menu {:shape shape}]])
|
||||
|
|
Loading…
Reference in a new issue