Adds typography to libraries

This commit is contained in:
alonso.torres 2020-09-29 16:17:45 +02:00 committed by Hirunatan
parent 4a4cff74e8
commit 718a676fa8
22 changed files with 831 additions and 642 deletions

View file

@ -25,29 +25,6 @@
[app.main.data.modal :as md]
[app.common.pages-helpers :as cph]))
(declare create-color-result)
(defn create-color
[file-id color]
(s/assert (s/nilable uuid?) file-id)
(ptk/reify ::create-color
ptk/WatchEvent
(watch [_ state s]
(->> (rp/mutation! :create-color {:file-id file-id
:content color
:name color})
(rx/map (partial create-color-result file-id))))))
(defn create-color-result
[file-id color]
(ptk/reify ::create-color-result
ptk/UpdateEvent
(update [_ state]
(-> state
(update-in [:workspace-file :colors] #(conj % color))
(assoc-in [:workspace-local :color-for-rename] (:id color))))))
(def clear-color-for-rename
(ptk/reify ::clear-color-for-rename
ptk/UpdateEvent
@ -73,44 +50,6 @@
(-> state
(update-in [:workspace-file :colors] #(d/replace-by-id % color))))))
(declare update-color-result)
(defn update-color
[file-id color-id content]
(ptk/reify ::update-color
ptk/WatchEvent
(watch [_ state stream]
(->> (rp/mutation! :update-color {:id color-id
:content content})
(rx/map (partial update-color-result file-id))))))
(defn update-color-result
[file-id color]
(ptk/reify ::update-color-result
ptk/UpdateEvent
(update [_ state]
(-> state
(update-in [:workspace-file :colors] #(d/replace-by-id % color))))))
(declare delete-color-result)
(defn delete-color
[file-id color-id]
(ptk/reify ::delete-color
ptk/WatchEvent
(watch [_ state stream]
(->> (rp/mutation! :delete-color {:id color-id})
(rx/map #(delete-color-result file-id color-id))))))
(defn delete-color-result
[file-id color-id]
(ptk/reify ::delete-color-result
ptk/UpdateEvent
(update [_ state]
(-> state
(update-in [:workspace-file :colors]
(fn [colors] (filter #(not= (:id %) color-id) colors)))))))
(defn change-palette-size [size]
(s/assert #{:big :small} size)
(ptk/reify ::change-palette-size

View file

@ -73,9 +73,10 @@
(s/def ::layout-flags (s/coll-of ::layout-flag))
(def default-layout
#{:sitemap
:sitemap-pages
:layers
#{;; :sitemap
;; :sitemap-pages
;; :layers
:assets
:element-options
:rules
:display-grid

View file

@ -519,3 +519,56 @@
:callback do-dismiss}]
:sync-dialog))))))
(def default-typography
{:name "Source Sans Pro Regular"
:font-id "sourcesanspro"
:font-family "sourcesanspro"
:font-variant-id "regular"
:font-size "14"
:font-weight "400"
:font-style "normal"
:line-height "1.2"
:letter-spacing "0"
:text-transform "none"})
(defn add-typography
[typography]
(let [typography (update typography :id #(or % (uuid/next)))]
(us/assert ::cp/typography typography)
(ptk/reify ::add-typography
ptk/WatchEvent
(watch [_ state s]
(let [rchg {:type :add-typography
:typography typography}
uchg {:type :del-typography
:id (:id typography)}]
(rx/of (dwc/commit-changes [rchg] [uchg] {:commit-local? true})))))))
(defn update-typography
[typography]
(us/assert ::cp/typography typography)
(ptk/reify ::update-typography
ptk/WatchEvent
(watch [_ state stream]
(let [prev (get-in state [:workspace-data :typography (:id typography)])
rchg {:type :mod-typography
:typography typography}
uchg {:type :mod-typography
:typography prev}]
(rx/of (dwc/commit-changes [rchg] [uchg] {:commit-local? true})
(sync-file nil))))))
(defn delete-typography
[id]
(us/assert ::us/uuid id)
(ptk/reify ::delete-typography
ptk/WatchEvent
(watch [_ state stream]
(let [prev (get-in state [:workspace-data :typography id])
rchg {:type :del-typography
:id id}
uchg {:type :add-typography
:typography prev}]
(rx/of (dwc/commit-changes [rchg] [uchg] {:commit-local? true}))))))

View file

@ -300,8 +300,7 @@
(rx/mapcat
#(rx/zip (rp/query :file-library {:file-id library-id})
(rp/query :media-objects {:file-id library-id
:is-local false})
(rp/query :colors {:file-id library-id}))))
:is-local false}))))
(rx/map file-linked))))))
(defn file-linked

View file

@ -96,6 +96,9 @@
(register! :builtin local-fonts)
(register! :google google-fonts)
(defn get-font-data [id]
(get @fontsdb id))
(defn resolve-variants
[id]
(get-in @fontsdb [id :variants]))
@ -164,3 +167,8 @@
(defn ready [cb]
(-> (obj/get-in js/document ["fonts" "ready"])
(p/then cb)))
(defn get-default-variant [{:keys [variants]}]
(or
(d/seek #(or (= (:id %) "regular") (= (:name %) "regular")) variants)
(first variants)))

View file

@ -97,6 +97,12 @@
(get-in state [:workspace-data :recent-colors] []))
st/state))
(def workspace-file-typography
(l/derived (fn [state]
(when-let [file (:workspace-file state)]
(get-in file [:data :typography])))
st/state))
(def workspace-project
(l/derived :workspace-project st/state))

View file

@ -28,6 +28,7 @@
(def auto-width (icon-xref :auto-width))
(def box (icon-xref :box))
(def chain (icon-xref :chain))
(def unchain (icon-xref :unchain))
(def chat (icon-xref :chat))
(def circle (icon-xref :circle))
(def close (icon-xref :close))

View file

@ -27,7 +27,8 @@
[library]
(let [components-count (count (get-in library [:data :components] []))
graphics-count (count (get-in library [:data :media] []))
colors-count (count (get-in library [:data :colors] []))]
colors-count (count (get-in library [:data :colors] []))
typography-count (count (get-in library [:data :typography] []))]
;; Include a   so this block has always some content
(str
(str/join " · "
@ -39,7 +40,10 @@
(conj (tr "workspace.libraries.graphics" graphics-count))
(< 0 colors-count)
(conj (tr "workspace.libraries.colors" colors-count))))
(conj (tr "workspace.libraries.colors" colors-count))
(< 0 typography-count)
(conj (tr "workspace.libraries.typography" typography-count))))
"\u00A0")))
(mf/defc libraries-tab

View file

@ -289,12 +289,15 @@
(dom/prevent-default event)
(dom/stop-propagation event)
(let [sidebar (dom/get-element "settings-bar")
assets (dom/get-element-by-class "assets-bar")
cpicker (dom/get-element-by-class "colorpicker-tooltip")
self (mf/ref-val self-ref)
target (dom/get-target event)
selecting? (mf/ref-val selecting-ref)]
(when-not (or (.contains sidebar target)
(.contains assets target)
(.contains self target)
(and cpicker (.contains cpicker target)))
(if selecting?
@ -340,7 +343,8 @@
(when (not read-only?)
(let [content (js->clj val :keywordize-keys true)
content (first content)]
(st/emit! (dw/update-shape id {:content content}))
;; Append timestamp so we can react to cursor change events
(st/emit! (dw/update-shape id {:content (assoc content :ts (js->clj (.now js/Date)))}))
(reset! state val)
(reset! content-var content)))))]

View file

@ -19,6 +19,7 @@
[app.config :as cfg]
[app.main.data.workspace :as dw]
[app.main.data.workspace.libraries :as dwl]
[app.main.data.workspace.texts :as dwt]
[app.main.data.colors :as dc]
[app.main.refs :as refs]
[app.main.store :as st]
@ -26,6 +27,7 @@
[app.main.ui.components.context-menu :refer [context-menu]]
[app.main.ui.components.file-uploader :refer [file-uploader]]
[app.main.ui.components.tab-container :refer [tab-container tab-element]]
[app.main.ui.workspace.sidebar.options.typography :refer [typography-entry]]
[app.main.ui.icons :as i]
[app.main.ui.keyboard :as kbd]
[app.main.ui.modal :as modal]
@ -41,7 +43,7 @@
[rumext.alpha :as mf]))
(mf/defc components-box
[{:keys [file-id local? components] :as props}]
[{:keys [file-id local? components open? on-open on-close] :as props}]
(let [state (mf/use-state {:menu-open false
:top nil
:left nil
@ -75,27 +77,28 @@
(dnd/set-allowed-effect! event "move")))]
[:div.asset-group
[:div.group-title
(tr "workspace.assets.components")
[:div.group-title {:class (when (not open?) "closed")}
[:span {:on-click #(if open? (on-close) (on-open))} i/arrow-slide (tr "workspace.assets.components")]
[:span (str "\u00A0(") (count components) ")"]] ;; Unicode 00A0 is non-breaking space
[:div.group-grid.big
(for [component components]
[:div.grid-cell {:key (:id component)
:draggable true
:on-context-menu (on-context-menu (:id component))
:on-drag-start (partial on-drag-start component)}
[:& exports/component-svg {:group (get-in component [:objects (:id component)])
:objects (:objects component)}]
[:div.cell-name (:name component)]])
(when open?
[:div.group-grid.big
(for [component components]
[:div.grid-cell {:key (:id component)
:draggable true
:on-context-menu (on-context-menu (:id component))
:on-drag-start (partial on-drag-start component)}
[:& exports/component-svg {:group (get-in component [:objects (:id component)])
:objects (:objects component)}]
[:div.cell-name (:name component)]])])
(when local?
[:& context-menu
{:selectable false
:show (:menu-open @state)
:on-close #(swap! state assoc :menu-open false)
:top (:top @state)
:left (:left @state)
:options [[(tr "workspace.assets.delete") on-delete]]}])]]))
(when local?
[:& context-menu
{:selectable false
:show (:menu-open @state)
:on-close #(swap! state assoc :menu-open false)
:top (:top @state)
:left (:left @state)
:options [[(tr "workspace.assets.delete") on-delete]]}])]))
(mf/defc graphics-box
[{:keys [file-id local? objects open? on-open on-close] :as props}]
@ -326,6 +329,88 @@
:local? local?
:locale locale}])])]))
(mf/defc typography-box
[{:keys [file-id local? typographies locale open? on-open on-close] :as props}]
(let [state (mf/use-state {:detail-open? false
:menu-open? false
:top nil
:left nil})
selected (mf/deref refs/selected-shapes)
add-typography
(mf/use-callback
(mf/deps file-id)
(fn [value opacity]
(st/emit! (dwl/add-typography dwl/default-typography))))
handle-change
(mf/use-callback
(mf/deps file-id)
(fn [typography changes]
(st/emit! (dwl/update-typography (merge typography changes)))))
handle-typography-selection
(fn [typography]
(let [attrs (merge
{:typography-ref-file (when-not local? file-id)
:typography-ref-id (:id typography)}
(d/without-keys typography [:id :name]))]
(run! #(st/emit! (dwt/update-text-attrs {:id % :editor nil :attrs attrs}))
selected)))
on-context-menu
(fn [id event]
(when local?
(let [pos (dom/get-client-position event)
top (:y pos)
left (- (:x pos) 20)]
(dom/prevent-default event)
(swap! state assoc
:menu-open? true
:top top
:left left
:id id))))
closed-typography-edit
(mf/use-callback
(mf/deps file-id)
(fn [event] ))
handle-rename-typography-clicked (fn [])
handle-edit-typography-clicked (fn [] )
handle-delete-typography (fn []
(st/emit! (dwl/delete-typography (:id @state))))]
[:div.asset-group
[:div.group-title {:class (when (not open?) "closed")}
[:span {:on-click #(if open? (on-close) (on-open))} i/arrow-slide "Typography" #_(t locale "workspace.assets.typography")]
[:span.num-assets (str "\u00A0(") (count typographies) ")"] ;; Unicode 00A0 is non-breaking space
(when local?
[:div.group-button {:on-click add-typography} i/plus])]
[:& context-menu
{:selectable false
:show (:menu-open? @state)
:on-close #(swap! state assoc :menu-open? false)
:top (:top @state)
:left (:left @state)
:options [[(t locale "workspace.assets.rename") handle-rename-typography-clicked]
[(t locale "workspace.assets.edit") handle-edit-typography-clicked]
[(t locale "workspace.assets.delete") handle-delete-typography]]}]
(when open?
[:div.group-list
(for [typography (sort-by (comp - :ts) typographies)]
[:& typography-entry
{:key (:id typography)
:typography typography
:read-only? (not local?)
:on-context-menu #(on-context-menu (:id typography) %)
:on-change #(handle-change typography %)
:on-select #(handle-typography-selection typography)}])])]))
(defn file-colors-ref
[id]
(l/derived (fn [state]
@ -354,6 +439,15 @@
(vals (get-in state [:workspace-libraries id :data :components])))))
st/state =))
(defn file-typography-ref
[id]
(l/derived (fn [state]
(let [wfile (:workspace-file state)]
(if (= (:id wfile) id)
(vals (get-in wfile [:data :typography]))
(vals (get-in state [:workspace-libraries id :data :typography])))))
st/state =))
(defn apply-filters
[coll filters]
(->> coll
@ -369,7 +463,10 @@
router (mf/deref refs/router)
toggle-open #(swap! open? not)
toggles (mf/use-state #{:graphics :colors})
toggles (mf/use-state #{:components
:graphics
:colors
:typography})
url (rt/resolve router :workspace
{:project-id (:project-id file)
@ -379,6 +476,9 @@
colors-ref (mf/use-memo (mf/deps (:id file)) #(file-colors-ref (:id file)))
colors (apply-filters (mf/deref colors-ref) filters)
typography-ref (mf/use-memo (mf/deps (:id file)) #(file-typography-ref (:id file)))
typographies (apply-filters (mf/deref typography-ref) filters)
media-ref (mf/use-memo (mf/deps (:id file)) #(file-media-ref (:id file)))
media (apply-filters (mf/deref media-ref) filters)
@ -413,13 +513,20 @@
(str/empty? (:term filters))))
show-colors? (and (or (= (:box filters) :all)
(= (:box filters) :colors))
(or (> (count colors) 0)
(str/empty? (:term filters))))
show-typography? (and (or (= (:box filters) :all)
(= (:box filters) :typography))
(or (> (count colors) 0)
(str/empty? (:term filters))))]
[:div.tool-window-content
(when show-components?
[:& components-box {:file-id (:id file)
:local? local?
:components components}])
:components components
:open? (contains? @toggles :components)
:on-open #(swap! toggles conj :components)
:on-close #(swap! toggles disj :components)}])
(when show-graphics?
[:& graphics-box {:file-id (:id file)
:local? local?
@ -436,6 +543,15 @@
:on-open #(swap! toggles conj :colors)
:on-close #(swap! toggles disj :colors)}])
(when show-typography?
[:& typography-box {:file-id (:id file)
:local? local?
:locale locale
:typographies typographies
:open? (contains? @toggles :typography)
:on-open #(swap! toggles conj :typography)
:on-close #(swap! toggles disj :typography)}])
(when (and (not show-components?) (not show-graphics?) (not show-colors?))
[:div.asset-group
[:div.group-title (t locale "workspace.assets.not-found")]])]))]))
@ -495,8 +611,10 @@
[:select.input-select {:value (:box @filters)
:on-change on-box-filter-change}
[:option {:value ":all"} (t locale "workspace.assets.box-filter-all")]
[:option {:value ":graphics"} (t locale "workspace.assets.box-filter-graphics")]
[:option {:value ":colors"} (t locale "workspace.assets.box-filter-colors")]]]]
[:option {:value ":components"} (t locale "workspace.assets.components")]
[:option {:value ":graphics"} (t locale "workspace.assets.graphics")]
[:option {:value ":colors"} (t locale "workspace.assets.colors")]
[:option {:value ":typography"} (t locale "workspace.assets.typography")]]]]
[:div.libraries-wrapper
[:& file-library

View file

@ -144,11 +144,11 @@
[:& text-menu {:ids text-ids
:type :multiple
:editor nil
:font-values font-values
:align-values align-values
:spacing-values spacing-values
:valign-values valign-values
:decoration-values decoration-values
:transform-values transform-values
:values (merge font-values
align-values
spacing-values
valign-values
decoration-values
transform-values)
:shapes shapes}])]))

View file

@ -14,20 +14,23 @@
[okulary.core :as l]
[app.main.ui.icons :as i]
[app.common.data :as d]
[app.common.uuid :as uuid]
[app.main.data.workspace :as dw]
[app.main.data.workspace.common :as dwc]
[app.main.data.workspace.texts :as dwt]
[app.main.data.workspace.libraries :as dwl]
[app.main.store :as st]
[app.main.refs :as refs]
[app.main.ui.workspace.sidebar.options.measures :refer [measure-attrs measures-menu]]
[app.main.ui.workspace.sidebar.options.fill :refer [fill-menu]]
[app.main.ui.workspace.sidebar.options.shadow :refer [shadow-menu]]
[app.main.ui.components.editable-select :refer [editable-select]]
[app.main.ui.workspace.sidebar.options.typography :refer [typography-entry typography-options]]
[app.util.dom :as dom]
[app.main.fonts :as fonts]
[app.util.i18n :as i18n :refer [tr t]]
["slate" :refer [Transforms]]))
(def text-typography-attrs [:typography-ref-id :typography-ref-file])
(def text-fill-attrs [:fill :opacity])
(def text-font-attrs [:font-id :font-family :font-variant-id :font-size :font-weight :font-style])
(def text-align-attrs [:text-align])
@ -36,205 +39,52 @@
(def text-decoration-attrs [:text-decoration])
(def text-transform-attrs [:text-transform])
(defn- attr->string [value]
(if (= value :multiple)
""
(str value)))
(def ^:private editor-ref
(l/derived :editor refs/workspace-local))
(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)])]])
(mf/defc font-options
[{:keys [editor ids values locale] :as props}]
(let [{:keys [font-id
font-size
font-variant-id]} values
font-id (or font-id "sourcesanspro")
font-size (or font-size "14")
font-variant-id (or font-variant-id "regular")
fonts (mf/deref fonts/fontsdb)
font (get fonts font-id)
change-font
(fn [new-font-id]
(run! #(st/emit! (dwt/update-text-attrs
{:id %
:editor editor
:attrs {:font-id new-font-id
:font-family (:family (get fonts new-font-id))
:font-variant-id nil
:font-weight nil
:font-style nil}}))
ids))
on-font-family-change
(fn [event]
(let [new-font-id (-> (dom/get-target event)
(dom/get-value))]
(when-not (str/empty? new-font-id)
(let [font (get fonts new-font-id)]
(fonts/ensure-loaded! new-font-id (partial change-font new-font-id))))))
on-font-size-change
(fn [new-font-size]
(when-not (str/empty? new-font-size)
(run! #(st/emit! (dwt/update-text-attrs
{:id %
:editor editor
:attrs {:font-size (str new-font-size)}}))
ids)))
on-font-variant-change
(fn [event]
(let [new-variant-id (-> (dom/get-target event)
(dom/get-value))
variant (d/seek #(= new-variant-id (:id %)) (:variants font))]
(run! #(st/emit! (dwt/update-text-attrs
{:id %
:editor editor
:attrs {:font-id (:id font)
:font-family (:family font)
:font-variant-id new-variant-id
:font-weight (:weight variant)
:font-style (:style variant)}}))
ids)))]
[:*
[:div.row-flex
[:select.input-select {:value (attr->string font-id)
:on-change on-font-family-change}
(when (= font-id :multiple)
[:option {:value ""} (t locale "settings.multiple")])
[:& font-select-optgroups]]]
[:div.row-flex
(let [size-options [8 9 10 11 12 14 18 24 36 48 72]
size-options (if (= font-size :multiple) (concat [{:value "" :label "--"}] size-options) size-options)]
[:& editable-select
{:value (attr->string font-size)
:class "input-option"
:options size-options
:type "number"
:placeholder "--"
:on-change on-font-size-change}])
[:select.input-select {:value (attr->string font-variant-id)
:on-change on-font-variant-change}
(when (= font-size :multiple)
[:option {:value ""} "--"])
(for [variant (:variants font)]
[:option {:value (:id variant)
:key (pr-str variant)}
(:name variant)])]]]))
(def root-attrs (d/concat text-valign-attrs
text-align-attrs))
(def paragraph-attrs text-align-attrs)
(def text-attrs (d/concat text-typography-attrs
text-font-attrs
text-align-attrs
text-spacing-attrs
text-decoration-attrs
text-transform-attrs))
(mf/defc text-align-options
[{:keys [editor ids values locale] :as props}]
[{:keys [editor ids values locale on-change] :as props}]
(let [{:keys [text-align]} values
text-align (or text-align "left")
on-change
handle-change
(fn [event new-align]
(run! #(st/emit!
(dwt/update-root-attrs
{:id %
:editor editor
:attrs {:text-align new-align}})
(dwt/update-paragraph-attrs
{:id %
:editor editor
:attrs {:text-align new-align}}))
ids))]
(on-change {:text-align new-align}))]
;; --- Align
[:div.row-flex.align-icons
[:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.text-options.align-left")
:class (dom/classnames :current (= "left" text-align))
:on-click #(on-change % "left")}
:on-click #(handle-change % "left")}
i/text-align-left]
[:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.text-options.align-center")
:class (dom/classnames :current (= "center" text-align))
:on-click #(on-change % "center")}
:on-click #(handle-change % "center")}
i/text-align-center]
[:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.text-options.align-right")
:class (dom/classnames :current (= "right" text-align))
:on-click #(on-change % "right")}
:on-click #(handle-change % "right")}
i/text-align-right]
[:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.text-options.align-justify")
:class (dom/classnames :current (= "justify" text-align))
:on-click #(on-change % "justify")}
:on-click #(handle-change % "justify")}
i/text-align-justify]]))
(mf/defc spacing-options
[{:keys [editor ids values locale] :as props}]
(let [{:keys [line-height
letter-spacing]} values
line-height (or line-height "1.2")
letter-spacing (or letter-spacing "0")
on-change
(fn [event attr]
(let [new-spacing (-> (dom/get-target event)
(dom/get-value))]
(run! #(st/emit! (dwt/update-text-attrs
{:id %
:editor editor
:attrs {attr new-spacing}}))
ids)))]
[:div.row-flex
[:div.input-icon
[:span.icon-before.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.text-options.line-height")}
i/line-height]
[:input.input-text
{:type "number"
:step "0.1"
:min "0"
:max "200"
:value (attr->string line-height)
:placeholder (t locale "settings.multiple")
:on-change #(on-change % :line-height)}]]
[:div.input-icon
[:span.icon-before.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.text-options.letter-spacing")}
i/letter-spacing]
[:input.input-text
{:type "number"
:step "0.1"
:min "0"
:max "200"
:value (attr->string letter-spacing)
:placeholder (t locale "settings.multiple")
:on-change #(on-change % :letter-spacing)}]]]))
(mf/defc additional-options
[{:keys [shapes editor ids values locale] :as props}]
[{:keys [shapes editor ids values locale on-change] :as props}]
(let [{:keys [vertical-align]} values
to-single-value (fn [coll] (if (> (count coll) 1) nil (first coll)))
@ -243,150 +93,171 @@
vertical-align (or vertical-align "top")
on-change-grow
handle-change-grow
(fn [event grow-type]
(st/emit! (dwc/update-shapes ids #(assoc % :grow-type grow-type))))
on-change
handle-change
(fn [event new-align]
(run! #(st/emit! (dwt/update-root-attrs
{:id %
:editor editor
:attrs {:vertical-align new-align}}))
ids))]
(on-change {:vertical-align new-align}))]
[:div.row-flex
[:div.align-icons
[:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.text-options.align-top")
:class (dom/classnames :current (= "top" vertical-align))
:on-click #(on-change % "top")}
:on-click #(handle-change % "top")}
i/align-top]
[:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.text-options.align-middle")
:class (dom/classnames :current (= "center" vertical-align))
:on-click #(on-change % "center")}
:on-click #(handle-change % "center")}
i/align-middle]
[:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.text-options.align-bottom")
:class (dom/classnames :current (= "bottom" vertical-align))
:on-click #(on-change % "bottom")}
:on-click #(handle-change % "bottom")}
i/align-bottom]]
[:div.align-icons
[:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.text-options.grow-fixed")
:class (dom/classnames :current (= :fixed grow-type))
:on-click #(on-change-grow % :fixed)}
:on-click #(handle-change-grow % :fixed)}
i/auto-fix]
[:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.text-options.grow-auto-width")
:class (dom/classnames :current (= :auto-width grow-type))
:on-click #(on-change-grow % :auto-width)}
:on-click #(handle-change-grow % :auto-width)}
i/auto-width]
[:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.text-options.grow-auto-height")
:class (dom/classnames :current (= :auto-height grow-type))
:on-click #(on-change-grow % :auto-height)}
:on-click #(handle-change-grow % :auto-height)}
i/auto-height]]]))
(mf/defc text-decoration-options
[{:keys [editor ids values locale] :as props}]
[{:keys [editor ids values locale on-change] :as props}]
(let [{:keys [text-decoration]} values
text-decoration (or text-decoration "none")
on-change
handle-change
(fn [event type]
(run! #(st/emit! (dwt/update-text-attrs
{:id %
:editor editor
:attrs {:text-decoration type}}))
ids))]
(on-change {:text-decoration type}))]
[:div.row-flex
[:span.element-set-subtitle (t locale "workspace.options.text-options.decoration")]
[:div.align-icons
[:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.text-options.none")
:class (dom/classnames :current (= "none" text-decoration))
:on-click #(on-change % "none")}
:on-click #(handle-change % "none")}
i/minus]
[:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.text-options.underline")
:class (dom/classnames :current (= "underline" text-decoration))
:on-click #(on-change % "underline")}
:on-click #(handle-change % "underline")}
i/underline]
[:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.text-options.strikethrough")
:class (dom/classnames :current (= "line-through" text-decoration))
:on-click #(on-change % "line-through")}
:on-click #(handle-change % "line-through")}
i/strikethrough]]]))
(mf/defc text-transform-options
[{:keys [editor ids values locale] :as props}]
(let [{:keys [text-transform]} values
text-transform (or text-transform "none")
on-change
(fn [event type]
(run! #(st/emit! (dwt/update-text-attrs
{:id %
:editor editor
:attrs {:text-transform type}}))
ids))]
[:div.row-flex
[:span.element-set-subtitle (t locale "workspace.options.text-options.text-case")]
[:div.align-icons
[:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.text-options.none")
:class (dom/classnames :current (= "none" text-transform))
:on-click #(on-change % "none")}
i/minus]
[:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.text-options.uppercase")
:class (dom/classnames :current (= "uppercase" text-transform))
:on-click #(on-change % "uppercase")}
i/uppercase]
[:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.text-options.lowercase")
:class (dom/classnames :current (= "lowercase" text-transform))
:on-click #(on-change % "lowercase")}
i/lowercase]
[:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.text-options.titlecase")
:class (dom/classnames :current (= "capitalize" text-transform))
:on-click #(on-change % "capitalize")}
i/titlecase]]]))
(defn generate-typography-name [{:keys [font-id font-variant-id] :as typography}]
(let [{:keys [name]} (fonts/get-font-data font-id)]
(-> typography
(assoc :name (str name " " (str/title font-variant-id))))) )
(mf/defc text-menu
{::mf/wrap [mf/memo]}
[{:keys [ids
type
editor
font-values
align-values
spacing-values
valign-values
decoration-values
transform-values
values
shapes] :as props}]
(let [locale (mf/deref i18n/locale)
typographies (mf/deref refs/workspace-file-typography)
shared-libs (mf/deref refs/workspace-libraries)
label (case type
:multiple (t locale "workspace.options.text-options.title-selection")
:group (t locale "workspace.options.text-options.title-group")
(t locale "workspace.options.text-options.title"))]
[:div.element-set
[:div.element-set-title label]
[:div.element-set-content
[:& font-options {:editor editor :ids ids :values font-values :locale locale}]
[:& text-align-options {:editor editor :ids ids :values align-values :locale locale}]
[:& spacing-options {:editor editor :ids ids :values spacing-values :locale locale}]
[:& additional-options {:shapes shapes :editor editor :ids ids :values valign-values :locale locale}]
[:& text-decoration-options {:editor editor :ids ids :values decoration-values :locale locale}]
[:& text-transform-options {:editor editor :ids ids :values transform-values :locale locale}]]]))
(t locale "workspace.options.text-options.title"))
emit-update!
(fn [id attrs]
(let [attrs (select-keys attrs root-attrs)]
(when-not (empty? attrs)
(st/emit! (dwt/update-root-attrs {:id id :editor editor :attrs attrs}))))
(let [attrs (select-keys attrs paragraph-attrs)]
(when-not (empty? attrs)
(st/emit! (dwt/update-paragraph-attrs {:id id :editor editor :attrs attrs}))))
(let [attrs (select-keys attrs text-attrs)]
(when-not (empty? attrs)
(st/emit! (dwt/update-text-attrs {:id id :editor editor :attrs attrs})))))
typography (cond
(and (:typography-ref-id values)
(:typography-ref-file values))
(-> shared-libs
(get-in [(:typography-ref-file values) :data :typography (:typography-ref-id values)])
(assoc :file-id (:typography-ref-file values)))
(:typography-ref-id values)
(get typographies (:typography-ref-id values)))
handle-click
(mf/use-callback
(mf/deps values)
(fn [event]
(let [setted-values (-> (d/without-nils values)
(select-keys
(d/concat text-font-attrs
text-spacing-attrs
text-transform-attrs)))
typography (merge dwl/default-typography setted-values)
typography (generate-typography-name typography)]
(let [id (uuid/next)]
(st/emit! (dwl/add-typography (assoc typography :id id)))
(run! #(emit-update! % {:typography-ref-id id}) ids)))))
handle-deattach-typography
(fn []
(run! #(emit-update! % {:typography-ref-file nil
:typography-ref-id nil})
ids))
handle-change-typography
(fn [changes]
(st/emit! (dwl/update-typography (merge typography changes))))
opts #js {:editor editor
:ids ids
:values values
:on-change (fn [attrs]
(run! #(emit-update! % attrs) ids))
:locale locale}]
[:div.element-set
[:div.element-set-title
[:span label]
[:div.add-page {:on-click handle-click} i/close]]
(if typography
[:& typography-entry {:typography typography
:on-deattach handle-deattach-typography
:on-change handle-change-typography}]
[:> typography-options opts])
[:div.element-set-content
[:> text-align-options opts]
[:> additional-options opts]
[:> text-decoration-options opts]]]))
(mf/defc options
[{:keys [shape] :as props}]
@ -399,42 +270,25 @@
measure-values (select-keys shape measure-attrs)
fill-values (dwt/current-text-values
{:editor editor
:shape shape
:attrs text-fill-attrs})
{:editor editor
:shape shape
:attrs text-fill-attrs})
converted-fill-values {:fill-color (:fill fill-values)
:fill-opacity (:opacity fill-values)}
font-values (dwt/current-text-values
{:editor editor
:shape shape
:attrs text-font-attrs})
align-values (dwt/current-paragraph-values
{:editor editor
:shape shape
:attrs text-align-attrs})
text-values (merge
(dwt/current-root-values
{:editor editor :shape shape
:attrs root-attrs})
(dwt/current-text-values
{:editor editor :shape shape
:attrs paragraph-attrs})
(dwt/current-text-values
{:editor editor :shape shape
:attrs text-attrs}))]
spacing-values (dwt/current-text-values
{:editor editor
:shape shape
:attrs text-spacing-attrs})
valign-values (dwt/current-root-values
{:editor editor
:shape shape
:attrs text-valign-attrs})
decoration-values (dwt/current-text-values
{:editor editor
:shape shape
:attrs text-decoration-attrs})
transform-values (dwt/current-text-values
{:editor editor
:shape shape
:attrs text-transform-attrs})]
[:*
[:& measures-menu {:ids ids
:type type
@ -448,11 +302,5 @@
:values (select-keys shape [:shadow])}]
[:& text-menu {:ids ids
:type type
:editor editor
:font-values font-values
:align-values align-values
:spacing-values spacing-values
:valign-values valign-values
:decoration-values decoration-values
:transform-values transform-values
:values text-values
:shapes [shape]}]]))

View file

@ -0,0 +1,279 @@
;; 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.ui.workspace.sidebar.options.typography
(:require
[rumext.alpha :as mf]
[cuerdas.core :as str]
[app.main.ui.icons :as i]
[app.main.refs :as refs]
[app.main.store :as st]
[app.common.data :as d]
[app.main.data.workspace.texts :as dwt]
[app.main.ui.components.editable-select :refer [editable-select]]
[app.main.ui.workspace.sidebar.options.common :refer [advanced-options]]
[app.util.dom :as dom]
[app.main.fonts :as fonts]
[app.util.i18n :as i18n :refer [t]]))
(defn- attr->string [value]
(if (= value :multiple)
""
(str value)))
(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)])]])
(mf/defc font-options
[{:keys [editor ids values locale on-change] :as props}]
(let [{:keys [font-id
font-size
font-variant-id]} values
font-id (or font-id "sourcesanspro")
font-size (or font-size "14")
font-variant-id (or font-variant-id "regular")
fonts (mf/deref fonts/fontsdb)
font (get fonts font-id)
change-font
(fn [new-font-id]
(let [{:keys [family] :as font} (get fonts new-font-id)
{:keys [id name weight style]} (fonts/get-default-variant font)]
(on-change {:font-id new-font-id
:font-family family
:font-variant-id (or id name)
:font-weight weight
:font-style style})))
on-font-family-change
(fn [event]
(let [new-font-id (dom/get-target-val event)]
(when-not (str/empty? new-font-id)
(let [font (get fonts new-font-id)]
(fonts/ensure-loaded! new-font-id (partial change-font new-font-id))))))
on-font-size-change
(fn [new-font-size]
(when-not (str/empty? new-font-size)
(on-change {:font-size (str new-font-size)})))
on-font-variant-change
(fn [event]
(let [new-variant-id (dom/get-target-val event)
variant (d/seek #(= new-variant-id (:id %)) (:variants font))]
(on-change {:font-id (:id font)
:font-family (:family font)
:font-variant-id new-variant-id
:font-weight (:weight variant)
:font-style (:style variant)})))]
[:*
[:div.row-flex
[:select.input-select.font-option
{:value (attr->string font-id)
:on-change on-font-family-change}
(when (= font-id :multiple)
[:option {:value ""} (t locale "settings.multiple")])
[:& font-select-optgroups]]]
[:div.row-flex
(let [size-options [8 9 10 11 12 14 18 24 36 48 72]
size-options (if (= font-size :multiple) (into [{:value "" :label "--"}] size-options) size-options)]
[:& editable-select
{:value (attr->string font-size)
:class "input-option size-option"
:options size-options
:type "number"
:placeholder "--"
:on-change on-font-size-change}])
[:select.input-select.variant-option
{:value (attr->string font-variant-id)
:on-change on-font-variant-change}
(when (= font-size :multiple)
[:option {:value ""} "--"])
(for [variant (:variants font)]
[:option {:value (:id variant)
:key (pr-str variant)}
(:name variant)])]]]))
(mf/defc spacing-options
[{:keys [editor ids values locale on-change] :as props}]
(let [{:keys [line-height
letter-spacing]} values
line-height (or line-height "1.2")
letter-spacing (or letter-spacing "0")
handle-change
(fn [event attr]
(let [new-spacing (dom/get-target-val event)]
(on-change {attr new-spacing})))]
[:div.row-flex
[:div.input-icon
[:span.icon-before.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.text-options.line-height")}
i/line-height]
[:input.input-text
{:type "number"
:step "0.1"
:min "0"
:max "200"
:value (attr->string line-height)
:placeholder (t locale "settings.multiple")
:on-change #(handle-change % :line-height)}]]
[:div.input-icon
[:span.icon-before.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.text-options.letter-spacing")}
i/letter-spacing]
[:input.input-text
{:type "number"
:step "0.1"
:min "0"
:max "200"
:value (attr->string letter-spacing)
:placeholder (t locale "settings.multiple")
:on-change #(handle-change % :letter-spacing)}]]]))
(mf/defc text-transform-options
[{:keys [editor ids values locale on-change] :as props}]
(let [{:keys [text-transform]} values
text-transform (or text-transform "none")
handle-change
(fn [event type]
(on-change {:text-transform type}))]
[:div.row-flex
[:span.element-set-subtitle (t locale "workspace.options.text-options.text-case")]
[:div.align-icons
[:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.text-options.none")
:class (dom/classnames :current (= "none" text-transform))
:on-click #(handle-change % "none")}
i/minus]
[:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.text-options.uppercase")
:class (dom/classnames :current (= "uppercase" text-transform))
:on-click #(handle-change % "uppercase")}
i/uppercase]
[:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.text-options.lowercase")
:class (dom/classnames :current (= "lowercase" text-transform))
:on-click #(handle-change % "lowercase")}
i/lowercase]
[:span.tooltip.tooltip-bottom
{:alt (t locale "workspace.options.text-options.titlecase")
:class (dom/classnames :current (= "capitalize" text-transform))
:on-click #(handle-change % "capitalize")}
i/titlecase]]]))
(mf/defc typography-options
[{:keys [ids editor values on-change]}]
(let [locale (mf/deref i18n/locale)
opts #js {:editor editor
:ids ids
:values values
:locale locale
:on-change on-change}]
[:div.element-set-content
[:> font-options opts]
[:> spacing-options opts]
[:> text-transform-options opts]]))
(mf/defc typography-entry
[{:keys [typography read-only? on-select on-change on-deattach on-context-menu]}]
(let [open? (mf/use-state false)
selected (mf/deref refs/selected-shapes)
hover-deattach (mf/use-state false)]
[:*
[:div.element-set-options-group.typography-entry
[:div.typography-selection-wrapper
{:class (when on-select "is-selectable")
:on-click on-select
:on-context-menu on-context-menu}
[:div.typography-sample
{:style {:font-family (:font-family typography)
:font-weight (:font-weight typography)
:font-style (:font-style typography)}}
"Ag"]
[:div.typography-name (:name typography)]]
[:div.element-set-actions
(when on-deattach
[:div.element-set-actions-button
{:on-mouse-enter #(reset! hover-deattach true)
:on-mouse-leave #(reset! hover-deattach false)
:on-click on-deattach}
(if @hover-deattach i/unchain i/chain)])
[:div.element-set-actions-button
{:on-click #(reset! open? true)}
i/actions]]]
[:& advanced-options {:visible? @open?
:on-close #(reset! open? false)}
(if read-only?
[:div.element-set-content.typography-read-only-data
[:div.row-flex.typography-name
[:spang (:name typography)]]
[:div.row-flex
[:span.label "Font"]
[:span (:font-id typography)]]
[:div.row-flex
[:span.label "Size"]
[:span (:font-size typography)]]
[:div.row-flex
[:span.label "Line Height"]
[:span (:line-height typography)]]
[:div.row-flex
[:span.label "Letter spacing"]
[:span (:letter-spacing typography)]]
[:div.row-flex
[:span.label "Text transform"]
[:span (:text-transform typography)]]
[:div.go-to-lib-button
"Go to style library file to edit"]]
[:*
[:div.element-set-content
[:div.row-flex
[:input.element-name.adv-typography-name
{:type "text"
:value (:name typography)
:on-change #(on-change {:name (dom/get-target-val %)})}]]]
[:& typography-options {:values typography
:on-change on-change}]]
)
]]))

View file

@ -76,6 +76,8 @@
[node]
(.-value node))
(def get-target-val (comp get-value get-target))
(defn click
"Click a node"
[node]