mirror of
https://github.com/penpot/penpot.git
synced 2025-01-24 15:39:50 -05:00
✨ Adds typography to libraries
This commit is contained in:
parent
4a4cff74e8
commit
718a676fa8
22 changed files with 831 additions and 642 deletions
|
@ -15,7 +15,6 @@
|
|||
(defn- load-query-services
|
||||
[]
|
||||
(require 'app.services.queries.media)
|
||||
(require 'app.services.queries.colors)
|
||||
(require 'app.services.queries.projects)
|
||||
(require 'app.services.queries.files)
|
||||
(require 'app.services.queries.profile)
|
||||
|
@ -26,7 +25,6 @@
|
|||
[]
|
||||
(require 'app.services.mutations.demo)
|
||||
(require 'app.services.mutations.media)
|
||||
(require 'app.services.mutations.colors)
|
||||
(require 'app.services.mutations.projects)
|
||||
(require 'app.services.mutations.files)
|
||||
(require 'app.services.mutations.profile)
|
||||
|
|
|
@ -1,150 +0,0 @@
|
|||
;; 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.services.mutations.colors
|
||||
(:require
|
||||
[clojure.spec.alpha :as s]
|
||||
[app.common.exceptions :as ex]
|
||||
[app.common.spec :as us]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.config :as cfg]
|
||||
[app.db :as db]
|
||||
[app.services.mutations :as sm]
|
||||
[app.services.queries.teams :as teams]
|
||||
[app.tasks :as tasks]
|
||||
[app.util.time :as dt]))
|
||||
|
||||
;; --- Helpers & Specs
|
||||
|
||||
(s/def ::id ::us/uuid)
|
||||
(s/def ::name ::us/string)
|
||||
(s/def ::profile-id ::us/uuid)
|
||||
(s/def ::team-id ::us/uuid)
|
||||
(s/def ::library-id ::us/uuid)
|
||||
(s/def ::content ::us/string)
|
||||
|
||||
;; --- Mutation: Create Color
|
||||
|
||||
(declare select-file-for-update)
|
||||
(declare create-color)
|
||||
|
||||
(s/def ::create-color
|
||||
(s/keys :req-un [::profile-id ::name ::content ::file-id]
|
||||
:opt-un [::id]))
|
||||
|
||||
(sm/defmutation ::create-color
|
||||
[{:keys [profile-id file-id] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(let [file (select-file-for-update conn file-id)]
|
||||
(teams/check-edition-permissions! conn profile-id (:team-id file))
|
||||
(create-color conn params))))
|
||||
|
||||
(def ^:private sql:create-color
|
||||
"insert into color (id, name, file_id, content)
|
||||
values ($1, $2, $3, $4) returning *")
|
||||
|
||||
(defn create-color
|
||||
[conn {:keys [id name file-id content]}]
|
||||
(let [id (or id (uuid/next))]
|
||||
(db/insert! conn :color {:id id
|
||||
:name name
|
||||
:file-id file-id
|
||||
:content content})))
|
||||
|
||||
(def ^:private sql:select-file-for-update
|
||||
"select file.*,
|
||||
project.team_id as team_id
|
||||
from file
|
||||
inner join project on (project.id = file.project_id)
|
||||
where file.id = ?
|
||||
for update of file")
|
||||
|
||||
(defn- select-file-for-update
|
||||
[conn id]
|
||||
(let [row (db/exec-one! conn [sql:select-file-for-update id])]
|
||||
(when-not row
|
||||
(ex/raise :type :not-found))
|
||||
row))
|
||||
|
||||
|
||||
;; --- Mutation: Rename Color
|
||||
|
||||
(declare select-color-for-update)
|
||||
|
||||
(s/def ::rename-color
|
||||
(s/keys :req-un [::id ::profile-id ::name]))
|
||||
|
||||
(sm/defmutation ::rename-color
|
||||
[{:keys [id profile-id name] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(let [clr (select-color-for-update conn id)]
|
||||
(teams/check-edition-permissions! conn profile-id (:team-id clr))
|
||||
(db/update! conn :color
|
||||
{:name name}
|
||||
{:id id}))))
|
||||
|
||||
(def ^:private sql:select-color-for-update
|
||||
"select c.*,
|
||||
p.team_id as team_id
|
||||
from color as c
|
||||
inner join file as f on f.id = c.file_id
|
||||
inner join project as p on p.id = f.project_id
|
||||
where c.id = ?
|
||||
for update of c")
|
||||
|
||||
(defn- select-color-for-update
|
||||
[conn id]
|
||||
(let [row (db/exec-one! conn [sql:select-color-for-update id])]
|
||||
(when-not row
|
||||
(ex/raise :type :not-found))
|
||||
row))
|
||||
|
||||
|
||||
;; --- Mutation: Update Color
|
||||
|
||||
(s/def ::update-color
|
||||
(s/keys :req-un [::profile-id ::id ::content]))
|
||||
|
||||
(sm/defmutation ::update-color
|
||||
[{:keys [profile-id id content] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(let [clr (select-color-for-update conn id)
|
||||
;; IMPORTANT: if the previous name was equal to the hex content,
|
||||
;; we must rename it in addition to changing the value.
|
||||
new-name (if (= (:name clr) (:content clr))
|
||||
content
|
||||
(:name clr))]
|
||||
(teams/check-edition-permissions! conn profile-id (:team-id clr))
|
||||
(db/update! conn :color
|
||||
{:name new-name
|
||||
:content content}
|
||||
{:id id}))))
|
||||
|
||||
;; --- Delete Color
|
||||
|
||||
(declare delete-color)
|
||||
|
||||
(s/def ::delete-color
|
||||
(s/keys :req-un [::id ::profile-id]))
|
||||
|
||||
(sm/defmutation ::delete-color
|
||||
[{:keys [profile-id id] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(let [clr (select-color-for-update conn id)]
|
||||
(teams/check-edition-permissions! conn profile-id (:team-id clr))
|
||||
|
||||
;; Schedule object deletion
|
||||
(tasks/submit! conn {:name "delete-object"
|
||||
:delay cfg/default-deletion-delay
|
||||
:props {:id id :type :color}})
|
||||
|
||||
(db/update! conn :color
|
||||
{:deleted-at (dt/now)}
|
||||
{:id id})
|
||||
nil)))
|
|
@ -245,7 +245,8 @@
|
|||
[change]
|
||||
(or (#{:add-color :mod-color :del-color
|
||||
:add-media :mod-media :del-media
|
||||
:add-component :mod-component :del-component} (:type change))
|
||||
:add-component :mod-component :del-component
|
||||
:add-typography :mod-typography :del-typography} (:type change))
|
||||
(and (= (:type change) :mod-obj)
|
||||
(some? (:component-id change)))))
|
||||
|
||||
|
|
|
@ -1,104 +0,0 @@
|
|||
;; 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) 2019 Andrey Antukh <niwi@niwi.nz>
|
||||
|
||||
(ns app.services.queries.colors
|
||||
(:require
|
||||
[clojure.spec.alpha :as s]
|
||||
[promesa.core :as p]
|
||||
[promesa.exec :as px]
|
||||
[app.common.exceptions :as ex]
|
||||
[app.common.spec :as us]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.db :as db]
|
||||
[app.services.queries :as sq]
|
||||
[app.services.queries.teams :as teams]
|
||||
[app.util.blob :as blob]
|
||||
[app.util.data :as data]))
|
||||
|
||||
;; --- Helpers & Specs
|
||||
|
||||
(s/def ::id ::us/uuid)
|
||||
(s/def ::profile-id ::us/uuid)
|
||||
(s/def ::team-id ::us/uuid)
|
||||
(s/def ::file-id ::us/uuid)
|
||||
|
||||
|
||||
;; --- Query: Colors (by file)
|
||||
|
||||
(declare retrieve-colors)
|
||||
(declare retrieve-file)
|
||||
|
||||
(s/def ::colors
|
||||
(s/keys :req-un [::profile-id ::file-id]))
|
||||
|
||||
(sq/defquery ::colors
|
||||
[{:keys [profile-id file-id] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(let [file (retrieve-file conn file-id)]
|
||||
(teams/check-read-permissions! conn profile-id (:team-id file))
|
||||
(retrieve-colors conn file-id))))
|
||||
|
||||
(def ^:private sql:colors
|
||||
"select *
|
||||
from color
|
||||
where color.deleted_at is null
|
||||
and color.file_id = ?
|
||||
order by created_at desc")
|
||||
|
||||
(defn- retrieve-colors
|
||||
[conn file-id]
|
||||
(db/exec! conn [sql:colors file-id]))
|
||||
|
||||
(def ^:private sql:retrieve-file
|
||||
"select file.*,
|
||||
project.team_id as team_id
|
||||
from file
|
||||
inner join project on (project.id = file.project_id)
|
||||
where file.id = ?")
|
||||
|
||||
(defn- retrieve-file
|
||||
[conn id]
|
||||
(let [row (db/exec-one! conn [sql:retrieve-file id])]
|
||||
(when-not row
|
||||
(ex/raise :type :not-found))
|
||||
row))
|
||||
|
||||
|
||||
;; --- Query: Color (by ID)
|
||||
|
||||
(declare retrieve-color)
|
||||
|
||||
(s/def ::id ::us/uuid)
|
||||
(s/def ::color
|
||||
(s/keys :req-un [::profile-id ::id]))
|
||||
|
||||
(sq/defquery ::color
|
||||
[{:keys [profile-id id] :as params}]
|
||||
(db/with-atomic [conn db/pool]
|
||||
(let [color (retrieve-color conn id)]
|
||||
(teams/check-read-permissions! conn profile-id (:team-id color))
|
||||
color)))
|
||||
|
||||
(def ^:private sql:single-color
|
||||
"select color.*,
|
||||
p.team_id as team_id
|
||||
from color as color
|
||||
inner join file as f on (color.file_id = f.id)
|
||||
inner join project as p on (p.id = f.project_id)
|
||||
where color.deleted_at is null
|
||||
and color.id = ?
|
||||
order by created_at desc")
|
||||
|
||||
(defn retrieve-color
|
||||
[conn id]
|
||||
(let [row (db/exec-one! conn [sql:single-color id])]
|
||||
(when-not row
|
||||
(ex/raise :type :not-found))
|
||||
row))
|
||||
|
|
@ -299,6 +299,31 @@
|
|||
(s/def :internal.file/recent-colors
|
||||
(s/coll-of ::string :kind vector?))
|
||||
|
||||
(s/def :internal.typography/id ::id)
|
||||
(s/def :internal.typography/name ::string)
|
||||
(s/def :internal.typography/font-id ::string)
|
||||
(s/def :internal.typography/font-family ::string)
|
||||
(s/def :internal.typography/font-variant-id ::string)
|
||||
(s/def :internal.typography/font-size ::string)
|
||||
(s/def :internal.typography/font-weight ::string)
|
||||
(s/def :internal.typography/font-style ::string)
|
||||
(s/def :internal.typography/line-height ::string)
|
||||
(s/def :internal.typography/letter-spacing ::string)
|
||||
(s/def :internal.typography/text-transform ::string)
|
||||
|
||||
(s/def ::typography
|
||||
(s/keys :req-un [:internal.typography/id
|
||||
:internal.typography/name
|
||||
:internal.typography/font-id
|
||||
:internal.typography/font-family
|
||||
:internal.typography/font-variant-id
|
||||
:internal.typography/font-size
|
||||
:internal.typography/font-weight
|
||||
:internal.typography/font-style
|
||||
:internal.typography/line-height
|
||||
:internal.typography/letter-spacing
|
||||
:internal.typography/text-transform]))
|
||||
|
||||
(s/def :internal.file/pages
|
||||
(s/coll-of ::uuid :kind vector?))
|
||||
|
||||
|
@ -412,6 +437,17 @@
|
|||
(defmethod change-spec :del-component [_]
|
||||
(s/keys :req-un [::id]))
|
||||
|
||||
(s/def :internal.changes.typography/typography ::typography)
|
||||
|
||||
(defmethod change-spec :add-typography [_]
|
||||
(s/keys :req-un [:internal.changes.typography/typography]))
|
||||
|
||||
(defmethod change-spec :mod-typography [_]
|
||||
(s/keys :req-un [:internal.changes.typography/typography]))
|
||||
|
||||
(defmethod change-spec :del-typography [_]
|
||||
(s/keys :req-un [:internal.typography/id]))
|
||||
|
||||
(s/def ::change (s/multi-spec change-spec :type))
|
||||
(s/def ::changes (s/coll-of ::change))
|
||||
|
||||
|
@ -803,6 +839,8 @@
|
|||
(subvec rc 1)
|
||||
rc)))))
|
||||
|
||||
;; -- Media
|
||||
|
||||
(defmethod process-change :add-media
|
||||
[data {:keys [object]}]
|
||||
(update data :media assoc (:id object) object))
|
||||
|
@ -815,6 +853,8 @@
|
|||
[data {:keys [id]}]
|
||||
(update data :media dissoc id))
|
||||
|
||||
;; -- Components
|
||||
|
||||
(defmethod process-change :add-component
|
||||
[data {:keys [id name shapes]}]
|
||||
(assoc-in data [:components id]
|
||||
|
@ -833,6 +873,22 @@
|
|||
[data {:keys [id]}]
|
||||
(d/dissoc-in data [:components id]))
|
||||
|
||||
;; -- Typography
|
||||
|
||||
(defmethod process-change :add-typography
|
||||
[data {:keys [typography]}]
|
||||
(update data :typography assoc (:id typography) typography))
|
||||
|
||||
(defmethod process-change :mod-typography
|
||||
[data {:keys [typography]}]
|
||||
(d/update-in-when data [:typography (:id typography)] merge typography))
|
||||
|
||||
(defmethod process-change :del-typography
|
||||
[data {:keys [id]}]
|
||||
(update data :typography dissoc id))
|
||||
|
||||
;; -- Operations
|
||||
|
||||
(defmethod process-operation :set
|
||||
[shape op]
|
||||
(let [attr (:attr op)
|
||||
|
|
7
frontend/resources/images/icons/unchain.svg
Normal file
7
frontend/resources/images/icons/unchain.svg
Normal file
|
@ -0,0 +1,7 @@
|
|||
<svg width="40" height="41" viewBox="0 0 40 41" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M27.3455 0.855913C24.5854 1.57398 22.3027 3.61844 21.0431 6.14402C20.1365 7.69681 19.033 9.20989 18.595 10.9747C18.5791 12.5077 20.6042 13.6713 21.8504 12.6729C22.6753 11.9726 23.1234 10.9544 23.7106 10.0663C24.635 8.50138 25.4362 6.73624 26.9321 5.62399C29.1019 4.25506 32.2456 4.42792 34.0446 6.34338C35.8577 8.1232 36.2905 11.1996 34.8418 13.3314C32.9321 16.6169 31.1617 19.9943 29.0399 23.1496C27.4127 25.0133 24.4999 25.5226 22.3148 24.3806C21.3889 23.9825 20.1292 23.8473 19.4164 24.7113C18.5786 25.6499 18.7897 27.3327 19.9352 27.9313C21.5038 28.8608 23.3602 29.3035 25.1804 29.2411C28.4779 29.143 31.7684 27.3471 33.3539 24.3955C35.2416 21.2163 37.1745 18.059 38.8823 14.7782C40.1672 12.4492 40.2813 9.54151 39.3961 7.06543C38.2811 3.73956 35.2239 1.14689 31.7426 0.612769C30.2794 0.366248 28.7587 0.444615 27.3455 0.855913Z"/>
|
||||
<path d="M21.5425 15.5518C18.5342 14.718 15.2111 15.4777 12.7177 17.3188C9.61691 19.2557 6.23319 20.7461 3.34262 23.0045C0.406478 25.6204 -0.667 30.0993 0.749192 33.7793C2.05062 37.3431 5.55324 39.9812 9.32072 40.1837C11.3238 40.3507 13.3742 39.8349 15.0901 38.8156C16.7842 37.9099 18.4823 36.9731 20.0268 35.832C21.0495 34.7451 20.3594 32.7262 18.9072 32.4378C17.9352 32.2308 17.0769 32.9029 16.2329 33.269C14.3839 34.2493 12.6424 35.605 10.5346 35.969C7.95596 36.1495 5.28979 34.4567 4.60879 31.9141C3.8766 29.5283 4.92467 26.6732 7.15855 25.4846C10.4996 23.5458 13.7869 21.5028 17.2426 19.7703C19.6534 18.9028 22.5372 20.0004 23.8578 22.1732C24.4664 22.9945 25.6092 23.6365 26.6126 23.1317C27.7622 22.6301 28.2785 21.0176 27.4862 19.9962C26.1927 17.801 23.9992 16.1919 21.5425 15.5518Z"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.06066 4.93934C5.64645 4.35355 6.59619 4.35355 7.18198 4.93934L11.0607 8.81802C11.6464 9.40381 11.6464 10.3536 11.0607 10.9393C10.4749 11.5251 9.52513 11.5251 8.93934 10.9393L5.06066 7.06066C4.47487 6.47487 4.47487 5.52513 5.06066 4.93934Z" fill="black"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.5 0C14.3284 3.62117e-08 15 0.671573 15 1.5V6.98528C15 7.81371 14.3284 8.48528 13.5 8.48528C12.6716 8.48528 12 7.81371 12 6.98528V1.5C12 0.671573 12.6716 -3.62117e-08 13.5 0Z"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M0 13.5C0 12.6716 0.671573 12 1.5 12H6.98528C7.81371 12 8.48528 12.6716 8.48528 13.5C8.48528 14.3284 7.81371 15 6.98528 15H1.5C0.671573 15 0 14.3284 0 13.5Z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 2.4 KiB |
|
@ -2801,5 +2801,8 @@
|
|||
"ru" : "Кликни чтобы закончить фигуру",
|
||||
"es" : "Pulsar para cerrar la ruta"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"workspace.assets.typography": "Typographies",
|
||||
"workspace.libraries.typography": "%s typographies"
|
||||
}
|
||||
|
|
|
@ -69,8 +69,8 @@
|
|||
font-size: $fs13;
|
||||
padding: $small $x-small;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.element-list {
|
||||
|
@ -768,7 +768,7 @@
|
|||
z-index: 10;
|
||||
}
|
||||
|
||||
.element-set-content .advanced-options {
|
||||
.advanced-options {
|
||||
background-color: #303236;
|
||||
border-radius: 4px;
|
||||
left: -8px;
|
||||
|
@ -876,3 +876,119 @@
|
|||
.element-set-options-group:hover .element-set-actions {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
|
||||
.typography-entry {
|
||||
margin: 0.5rem 0.3rem;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
.typography-selection-wrapper {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
|
||||
&.is-selectable {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.typography-sample {
|
||||
font-size: 17px;
|
||||
color: $color-white;
|
||||
margin: 0 0.5rem;
|
||||
|
||||
font-family: sourcesanspro;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.typography-name {
|
||||
flex-grow: 1;
|
||||
font-size: 11px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.element-set-actions-button svg {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.asset-group {
|
||||
.typography-entry {
|
||||
margin: 0.25rem 0;
|
||||
}
|
||||
|
||||
.element-set-content .font-option,
|
||||
.element-set-content .size-option {
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
.element-set-content .variant-option {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.row-flex input.adv-typography-name {
|
||||
font-size: 14px;
|
||||
color: $color-gray-10;
|
||||
width: 100%;
|
||||
max-width: none;
|
||||
margin: 0;
|
||||
background: #303236;
|
||||
border-top: none;
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.size-option .custom-select-dropdown {
|
||||
position: fixed;
|
||||
max-height: 15rem;
|
||||
min-width: 6rem;
|
||||
margin-top: 25px;
|
||||
left: initial;
|
||||
}
|
||||
|
||||
.typography-read-only-data {
|
||||
font-size: 12px;
|
||||
color: $color-white;
|
||||
|
||||
.typography-name {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.row-flex {
|
||||
padding: 0.5rem 0;
|
||||
}
|
||||
|
||||
.label {
|
||||
color: $color-gray-30;
|
||||
|
||||
&::after {
|
||||
content: ':';
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
.go-to-lib-button {
|
||||
transition: border 0.3s, color 0.3s;
|
||||
text-align: center;
|
||||
background: $color-gray-60;
|
||||
padding: 0.5rem;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
margin-top: 1rem;
|
||||
border: 1px solid $color-gray-60;
|
||||
|
||||
&:hover {
|
||||
border: 1px solid $color-primary;
|
||||
color: $color-primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}))))))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)))
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)))))]
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}])]))
|
||||
|
||||
|
|
|
@ -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]}]]))
|
||||
|
|
|
@ -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}]]
|
||||
)
|
||||
|
||||
]]))
|
|
@ -76,6 +76,8 @@
|
|||
[node]
|
||||
(.-value node))
|
||||
|
||||
(def get-target-val (comp get-value get-target))
|
||||
|
||||
(defn click
|
||||
"Click a node"
|
||||
[node]
|
||||
|
|
Loading…
Add table
Reference in a new issue