mirror of
https://github.com/penpot/penpot.git
synced 2025-03-26 14:41:36 -05:00
Merge remote-tracking branch 'origin/staging' into develop
This commit is contained in:
commit
69f2e7c43f
17 changed files with 215 additions and 120 deletions
12
CHANGES.md
12
CHANGES.md
|
@ -12,6 +12,18 @@
|
||||||
|
|
||||||
### :heart: Community contributions by (Thank you!)
|
### :heart: Community contributions by (Thank you!)
|
||||||
|
|
||||||
|
## 1.19.3
|
||||||
|
|
||||||
|
### :sparkles: New features
|
||||||
|
|
||||||
|
- Remember last color mode in colorpicker [Taiga #5508](https://tree.taiga.io/project/penpot/issue/5508)
|
||||||
|
- Improve layers multiselection behaviour [Github #5741](https://github.com/penpot/penpot/issues/5741)
|
||||||
|
|
||||||
|
### :bug: Bugs fixed
|
||||||
|
|
||||||
|
- List view is discarded on tab change on Workspace Assets Sidebar tab [Github #3547](https://github.com/penpot/penpot/issues/3547)
|
||||||
|
- Fix message popup remains open when exiting workspace with browser back button [Taiga #5747](https://tree.taiga.io/project/penpot/issue/5747)
|
||||||
|
- When editing text if font is changed, the proportions of the rendered shape are wrong [Taiga #5786](https://tree.taiga.io/project/penpot/issue/5786)
|
||||||
|
|
||||||
## 1.19.2
|
## 1.19.2
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
<Logger name="app.rpc.commands.binfile" level="debug" />
|
<Logger name="app.rpc.commands.binfile" level="debug" />
|
||||||
<Logger name="app.storage.tmp" level="debug" />
|
<Logger name="app.storage.tmp" level="debug" />
|
||||||
<Logger name="app.worker" level="info" />
|
<Logger name="app.worker" level="trace" />
|
||||||
<Logger name="app.msgbus" level="info" />
|
<Logger name="app.msgbus" level="info" />
|
||||||
<Logger name="app.http.websocket" level="info" />
|
<Logger name="app.http.websocket" level="info" />
|
||||||
<Logger name="app.util.websocket" level="info" />
|
<Logger name="app.util.websocket" level="info" />
|
||||||
|
|
|
@ -773,7 +773,7 @@
|
||||||
(defn- lookup-index
|
(defn- lookup-index
|
||||||
[id]
|
[id]
|
||||||
(let [val (get-in @*state* [:index id])]
|
(let [val (get-in @*state* [:index id])]
|
||||||
(l/debug :fn "lookup-index" :id id :val val ::l/sync? true)
|
(l/trc :fn "lookup-index" :id id :val val ::l/sync? true)
|
||||||
(when (and (not (::ignore-index-errors? *options*)) (not val))
|
(when (and (not (::ignore-index-errors? *options*)) (not val))
|
||||||
(ex/raise :type :validation
|
(ex/raise :type :validation
|
||||||
:code :incomplete-index
|
:code :incomplete-index
|
||||||
|
|
|
@ -38,7 +38,6 @@
|
||||||
[promesa.exec.csp :as sp]))
|
[promesa.exec.csp :as sp]))
|
||||||
|
|
||||||
(def ^:dynamic *conn* nil)
|
(def ^:dynamic *conn* nil)
|
||||||
(def ^:dynamic *pool* nil)
|
|
||||||
|
|
||||||
(defn println!
|
(defn println!
|
||||||
[& params]
|
[& params]
|
||||||
|
|
|
@ -251,53 +251,59 @@
|
||||||
|
|
||||||
(defmethod ig/init-key ::gc-deleted-task
|
(defmethod ig/init-key ::gc-deleted-task
|
||||||
[_ {:keys [::db/pool ::storage ::min-age]}]
|
[_ {:keys [::db/pool ::storage ::min-age]}]
|
||||||
(letfn [(retrieve-deleted-objects-chunk [conn min-age cursor]
|
(letfn [(get-to-delete-chunk [cursor]
|
||||||
(let [min-age (db/interval min-age)
|
(let [sql (str "select s.* "
|
||||||
rows (db/exec! conn [sql:retrieve-deleted-objects-chunk min-age cursor])]
|
" from storage_object as s "
|
||||||
[(some-> rows peek :created-at)
|
" where s.deleted_at is not null "
|
||||||
|
" and s.deleted_at < ? "
|
||||||
|
" order by s.deleted_at desc "
|
||||||
|
" limit 25")
|
||||||
|
rows (db/exec! pool [sql cursor])]
|
||||||
|
[(some-> rows peek :deleted-at)
|
||||||
(some->> (seq rows) (d/group-by #(-> % :backend keyword) :id #{}) seq)]))
|
(some->> (seq rows) (d/group-by #(-> % :backend keyword) :id #{}) seq)]))
|
||||||
|
|
||||||
(retrieve-deleted-objects [conn min-age]
|
(get-to-delete-chunks [min-age]
|
||||||
(d/iteration (partial retrieve-deleted-objects-chunk conn min-age)
|
(d/iteration get-to-delete-chunk
|
||||||
:initk (dt/now)
|
:initk (dt/minus (dt/now) min-age)
|
||||||
:vf second
|
:vf second
|
||||||
:kf first))
|
:kf first))
|
||||||
|
|
||||||
(delete-in-bulk [backend-id ids]
|
(delete-in-bulk! [backend-id ids]
|
||||||
(let [backend (impl/resolve-backend storage backend-id)]
|
(try
|
||||||
|
(db/with-atomic [conn pool]
|
||||||
|
(let [sql "delete from storage_object where id = ANY(?)"
|
||||||
|
ids' (db/create-array conn "uuid" ids)
|
||||||
|
|
||||||
(doseq [id ids]
|
total (-> (db/exec-one! conn [sql ids'])
|
||||||
(l/debug :hint "gc-deleted: permanently delete storage object" :backend backend-id :id id))
|
(db/get-update-count))]
|
||||||
|
|
||||||
(impl/del-objects-in-bulk backend ids)))]
|
(-> (impl/resolve-backend storage backend-id)
|
||||||
|
(impl/del-objects-in-bulk ids))
|
||||||
|
|
||||||
|
(doseq [id ids]
|
||||||
|
(l/dbg :hint "gc-deleted: permanently delete storage object" :backend backend-id :id id))
|
||||||
|
|
||||||
|
total))
|
||||||
|
|
||||||
|
(catch Throwable cause
|
||||||
|
(l/err :hint "gc-deleted: unexpected error on bulk deletion"
|
||||||
|
:ids (vec ids)
|
||||||
|
:cause cause)
|
||||||
|
0)))]
|
||||||
|
|
||||||
(fn [params]
|
(fn [params]
|
||||||
(let [min-age (or (:min-age params) min-age)]
|
(let [min-age (or (some-> params :min-age dt/duration) min-age)]
|
||||||
(db/with-atomic [conn pool]
|
(loop [total 0
|
||||||
(loop [total 0
|
chunks (get-to-delete-chunks min-age)]
|
||||||
groups (retrieve-deleted-objects conn min-age)]
|
(if-let [[backend-id ids] (first chunks)]
|
||||||
(if-let [[backend-id ids] (first groups)]
|
(let [deleted (delete-in-bulk! backend-id ids)]
|
||||||
(do
|
(recur (+ total deleted)
|
||||||
(delete-in-bulk backend-id ids)
|
(rest chunks)))
|
||||||
(recur (+ total (count ids))
|
(do
|
||||||
(rest groups)))
|
(l/inf :hint "gc-deleted: task finished"
|
||||||
(do
|
:min-age (dt/format-duration min-age)
|
||||||
(l/info :hint "gc-deleted: task finished" :min-age (dt/format-duration min-age) :total total)
|
:total total)
|
||||||
{:deleted total}))))))))
|
{:deleted total})))))))
|
||||||
|
|
||||||
(def sql:retrieve-deleted-objects-chunk
|
|
||||||
"with items_part as (
|
|
||||||
select s.id
|
|
||||||
from storage_object as s
|
|
||||||
where s.deleted_at is not null
|
|
||||||
and s.deleted_at < (now() - ?::interval)
|
|
||||||
and s.created_at < ?
|
|
||||||
order by s.created_at desc
|
|
||||||
limit 25
|
|
||||||
)
|
|
||||||
delete from storage_object
|
|
||||||
where id in (select id from items_part)
|
|
||||||
returning *;")
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; Garbage Collection: Analyze touched objects
|
;; Garbage Collection: Analyze touched objects
|
||||||
|
|
|
@ -207,10 +207,10 @@
|
||||||
(db/create-array conn "uuid" ids)]]
|
(db/create-array conn "uuid" ids)]]
|
||||||
|
|
||||||
(db/exec-one! conn sql)
|
(db/exec-one! conn sql)
|
||||||
(l/debug :hist "dispatcher: queue tasks"
|
(l/dbg :hist "dispatcher: queue tasks"
|
||||||
:queue queue
|
:queue queue
|
||||||
:tasks (count ids)
|
:tasks (count ids)
|
||||||
:queued res)))
|
:queued res)))
|
||||||
|
|
||||||
(run-batch! [rconn]
|
(run-batch! [rconn]
|
||||||
(try
|
(try
|
||||||
|
@ -433,12 +433,12 @@
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(try
|
(try
|
||||||
(l/debug :hint "worker: executing task"
|
(l/dbg :hint "worker: executing task"
|
||||||
:name (:name task)
|
:name (:name task)
|
||||||
:id (:id task)
|
:id (str (:id task))
|
||||||
:queue queue
|
:queue queue
|
||||||
:worker-id worker-id
|
:worker-id worker-id
|
||||||
:retry (:retry-num task))
|
:retry (:retry-num task))
|
||||||
(handle-task task)
|
(handle-task task)
|
||||||
(catch InterruptedException cause
|
(catch InterruptedException cause
|
||||||
(throw cause))
|
(throw cause))
|
||||||
|
@ -678,13 +678,13 @@
|
||||||
(-> (db/exec-one! conn [sql:remove-not-started-tasks task queue label])
|
(-> (db/exec-one! conn [sql:remove-not-started-tasks task queue label])
|
||||||
:next.jdbc/update-count))]
|
:next.jdbc/update-count))]
|
||||||
|
|
||||||
(l/debug :hint "submit task"
|
(l/trc :hint "submit task"
|
||||||
:name task
|
:name task
|
||||||
:queue queue
|
:queue queue
|
||||||
:label label
|
:label label
|
||||||
:dedupe (boolean dedupe)
|
:dedupe (boolean dedupe)
|
||||||
:deleted (or deleted 0)
|
:deleted (or deleted 0)
|
||||||
:in (dt/format-duration duration))
|
:in (dt/format-duration duration))
|
||||||
|
|
||||||
(db/exec-one! conn [sql:insert-new-task id task props queue
|
(db/exec-one! conn [sql:insert-new-task id task props queue
|
||||||
label priority max-retries interval])
|
label priority max-retries interval])
|
||||||
|
|
|
@ -100,6 +100,7 @@
|
||||||
(configure-storage-backend))
|
(configure-storage-backend))
|
||||||
content1 (sto/content "content1")
|
content1 (sto/content "content1")
|
||||||
content2 (sto/content "content2")
|
content2 (sto/content "content2")
|
||||||
|
content3 (sto/content "content3")
|
||||||
object1 (sto/put-object! storage {::sto/content content1
|
object1 (sto/put-object! storage {::sto/content content1
|
||||||
::sto/expired-at (dt/now)
|
::sto/expired-at (dt/now)
|
||||||
:content-type "text/plain"
|
:content-type "text/plain"
|
||||||
|
@ -107,16 +108,20 @@
|
||||||
object2 (sto/put-object! storage {::sto/content content2
|
object2 (sto/put-object! storage {::sto/content content2
|
||||||
::sto/expired-at (dt/in-past {:hours 2})
|
::sto/expired-at (dt/in-past {:hours 2})
|
||||||
:content-type "text/plain"
|
:content-type "text/plain"
|
||||||
|
})
|
||||||
|
object3 (sto/put-object! storage {::sto/content content3
|
||||||
|
::sto/expired-at (dt/in-past {:hours 1})
|
||||||
|
:content-type "text/plain"
|
||||||
})]
|
})]
|
||||||
|
|
||||||
|
|
||||||
(th/sleep 200)
|
(th/sleep 200)
|
||||||
|
|
||||||
(let [task (:app.storage/gc-deleted-task th/*system*)
|
(let [res (th/run-task! :storage-gc-deleted {})]
|
||||||
res (task {})]
|
|
||||||
(t/is (= 1 (:deleted res))))
|
(t/is (= 1 (:deleted res))))
|
||||||
|
|
||||||
(let [res (db/exec-one! th/*pool* ["select count(*) from storage_object;"])]
|
(let [res (db/exec-one! th/*pool* ["select count(*) from storage_object;"])]
|
||||||
(t/is (= 1 (:count res))))))
|
(t/is (= 2 (:count res))))))
|
||||||
|
|
||||||
(t/deftest test-touched-gc-task-1
|
(t/deftest test-touched-gc-task-1
|
||||||
(let [storage (-> (:app.storage/storage th/*system*)
|
(let [storage (-> (:app.storage/storage th/*system*)
|
||||||
|
|
|
@ -279,8 +279,9 @@
|
||||||
(assoc-in (conj path :position) (:position comment-thread))
|
(assoc-in (conj path :position) (:position comment-thread))
|
||||||
(assoc-in (conj path :frame-id) (:frame-id comment-thread))))))
|
(assoc-in (conj path :frame-id) (:frame-id comment-thread))))))
|
||||||
(fetched [[users comments] state]
|
(fetched [[users comments] state]
|
||||||
(let [pages (get-in state [:workspace-data :pages-index])
|
(let [pages (-> (get-in state [:workspace-data :pages])
|
||||||
comments (filter #(some? (get pages (:page-id %))) comments)
|
set)
|
||||||
|
comments (filter #(contains? pages (:page-id %)) comments)
|
||||||
state (-> state
|
state (-> state
|
||||||
(assoc :comment-threads (d/index-by :id comments))
|
(assoc :comment-threads (d/index-by :id comments))
|
||||||
(update :current-file-comments-users merge (d/index-by :id users)))]
|
(update :current-file-comments-users merge (d/index-by :id users)))]
|
||||||
|
|
28
frontend/src/app/main/data/workspace/assets.cljs
Normal file
28
frontend/src/app/main/data/workspace/assets.cljs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
;; 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/.
|
||||||
|
;;
|
||||||
|
;; Copyright (c) KALEIDOS INC
|
||||||
|
|
||||||
|
(ns app.main.data.workspace.assets
|
||||||
|
"Workspace assets management events and helpers."
|
||||||
|
(:require
|
||||||
|
[app.util.storage :refer [storage]]))
|
||||||
|
|
||||||
|
(defn get-current-assets-ordering
|
||||||
|
[]
|
||||||
|
(let [ordering (::ordering @storage)]
|
||||||
|
(or ordering :asc)))
|
||||||
|
|
||||||
|
(defn set-current-assets-ordering!
|
||||||
|
[ordering]
|
||||||
|
(swap! storage assoc ::ordering ordering))
|
||||||
|
|
||||||
|
(defn get-current-assets-list-style
|
||||||
|
[]
|
||||||
|
(let [list-style (::list-style @storage)]
|
||||||
|
(or list-style :thumbs)))
|
||||||
|
|
||||||
|
(defn set-current-assets-list-style!
|
||||||
|
[list-style]
|
||||||
|
(swap! storage assoc ::list-style list-style))
|
|
@ -22,6 +22,7 @@
|
||||||
[app.main.data.workspace.texts :as dwt]
|
[app.main.data.workspace.texts :as dwt]
|
||||||
[app.main.data.workspace.undo :as dwu]
|
[app.main.data.workspace.undo :as dwu]
|
||||||
[app.util.color :as uc]
|
[app.util.color :as uc]
|
||||||
|
[app.util.storage :refer [storage]]
|
||||||
[beicon.core :as rx]
|
[beicon.core :as rx]
|
||||||
[potok.core :as ptk]))
|
[potok.core :as ptk]))
|
||||||
|
|
||||||
|
@ -647,3 +648,12 @@
|
||||||
:position :right})
|
:position :right})
|
||||||
(ptk/event ::ev/event {::ev/name "add-asset-to-library"
|
(ptk/event ::ev/event {::ev/name "add-asset-to-library"
|
||||||
:asset-type "color"}))))))
|
:asset-type "color"}))))))
|
||||||
|
|
||||||
|
(defn get-active-color-tab
|
||||||
|
[]
|
||||||
|
(let [tab (::tab @storage)]
|
||||||
|
(or tab :ramp)))
|
||||||
|
|
||||||
|
(defn set-active-color-tab!
|
||||||
|
[tab]
|
||||||
|
(swap! storage assoc ::tab tab))
|
||||||
|
|
|
@ -121,7 +121,9 @@
|
||||||
(ptk/reify ::select-shape
|
(ptk/reify ::select-shape
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(update-in state [:workspace-local :selected] d/toggle-selection id toggle?))
|
(-> state
|
||||||
|
(update-in [:workspace-local :selected] d/toggle-selection id toggle?)
|
||||||
|
(assoc-in [:workspace-local :last-selected] id)))
|
||||||
|
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state _]
|
(watch [_ state _]
|
||||||
|
@ -184,7 +186,9 @@
|
||||||
(ptk/reify ::deselect-shape
|
(ptk/reify ::deselect-shape
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(update-in state [:workspace-local :selected] disj id))))
|
(-> state
|
||||||
|
(update-in [:workspace-local :selected] disj id)
|
||||||
|
(update :workspace-local dissoc :last-selected)))))
|
||||||
|
|
||||||
(defn shift-select-shapes
|
(defn shift-select-shapes
|
||||||
([id]
|
([id]
|
||||||
|
@ -194,13 +198,15 @@
|
||||||
(ptk/reify ::shift-select-shapes
|
(ptk/reify ::shift-select-shapes
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(let [objects (or objects (wsh/lookup-page-objects state))
|
(let [objects (or objects (wsh/lookup-page-objects state))
|
||||||
|
append-to-selection (cph/expand-region-selection objects (into #{} [(get-in state [:workspace-local :last-selected]) id]))
|
||||||
selection (-> state
|
selection (-> state
|
||||||
wsh/lookup-selected
|
wsh/lookup-selected
|
||||||
(conj id))]
|
(conj id))]
|
||||||
(-> state
|
(-> state
|
||||||
(assoc-in [:workspace-local :selected]
|
(assoc-in [:workspace-local :selected]
|
||||||
(cph/expand-region-selection objects selection))))))))
|
(set/union selection append-to-selection))
|
||||||
|
(update :workspace-local assoc :last-selected id)))))))
|
||||||
|
|
||||||
(defn select-shapes
|
(defn select-shapes
|
||||||
[ids]
|
[ids]
|
||||||
|
|
|
@ -8,8 +8,10 @@
|
||||||
(:require-macros [app.main.style :refer [css]])
|
(:require-macros [app.main.style :refer [css]])
|
||||||
(:require
|
(:require
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
|
[app.main.data.messages :as msg]
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
[app.main.data.workspace :as dw]
|
[app.main.data.workspace :as dw]
|
||||||
|
[app.main.data.workspace.colors :as dc]
|
||||||
[app.main.data.workspace.persistence :as dwp]
|
[app.main.data.workspace.persistence :as dwp]
|
||||||
[app.main.features :as features]
|
[app.main.features :as features]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
|
@ -192,6 +194,9 @@
|
||||||
(st/emit! (dw/initialize-file project-id file-id))
|
(st/emit! (dw/initialize-file project-id file-id))
|
||||||
(fn []
|
(fn []
|
||||||
(st/emit! ::dwp/force-persist
|
(st/emit! ::dwp/force-persist
|
||||||
|
(dc/stop-picker)
|
||||||
|
(modal/hide)
|
||||||
|
msg/hide
|
||||||
(dw/finalize-file project-id file-id))))
|
(dw/finalize-file project-id file-id))))
|
||||||
|
|
||||||
[:& (mf/provider ctx/current-file-id) {:value file-id}
|
[:& (mf/provider ctx/current-file-id) {:value file-id}
|
||||||
|
|
|
@ -56,12 +56,17 @@
|
||||||
|
|
||||||
current-color (:current-color state)
|
current-color (:current-color state)
|
||||||
|
|
||||||
active-tab (mf/use-state :ramp #_:harmony #_:hsva)
|
active-tab (mf/use-state (dc/get-active-color-tab))
|
||||||
set-ramp-tab! (mf/use-fn #(reset! active-tab :ramp))
|
|
||||||
set-harmony-tab! (mf/use-fn #(reset! active-tab :harmony))
|
|
||||||
set-hsva-tab! (mf/use-fn #(reset! active-tab :hsva))
|
|
||||||
|
|
||||||
drag? (mf/use-state false)
|
drag? (mf/use-state false)
|
||||||
|
|
||||||
|
set-tab!
|
||||||
|
(mf/use-fn
|
||||||
|
(fn [event]
|
||||||
|
(let [tab (-> (dom/get-current-target event)
|
||||||
|
(dom/get-data "tab")
|
||||||
|
(keyword))]
|
||||||
|
(reset! active-tab tab)
|
||||||
|
(dc/set-active-color-tab! tab))))
|
||||||
|
|
||||||
handle-change-color
|
handle-change-color
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
|
@ -81,9 +86,9 @@
|
||||||
(fn []
|
(fn []
|
||||||
(if picking-color?
|
(if picking-color?
|
||||||
(do (modal/disallow-click-outside!)
|
(do (modal/disallow-click-outside!)
|
||||||
(st/emit! (dc/stop-picker)))
|
(st/emit! (dc/stop-picker)))
|
||||||
(do (modal/allow-click-outside!)
|
(do (modal/allow-click-outside!)
|
||||||
(st/emit! (dc/start-picker))))))
|
(st/emit! (dc/start-picker))))))
|
||||||
|
|
||||||
handle-change-stop
|
handle-change-stop
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
|
@ -225,15 +230,18 @@
|
||||||
[:div.colorpicker-tab.tooltip.tooltip-bottom.tooltip-expand
|
[:div.colorpicker-tab.tooltip.tooltip-bottom.tooltip-expand
|
||||||
{:class (when (= @active-tab :ramp) "active")
|
{:class (when (= @active-tab :ramp) "active")
|
||||||
:alt (tr "workspace.libraries.colors.rgba")
|
:alt (tr "workspace.libraries.colors.rgba")
|
||||||
:on-click set-ramp-tab!} i/picker-ramp]
|
:on-click set-tab!
|
||||||
|
:data-tab "ramp"} i/picker-ramp]
|
||||||
[:div.colorpicker-tab.tooltip.tooltip-bottom.tooltip-expand
|
[:div.colorpicker-tab.tooltip.tooltip-bottom.tooltip-expand
|
||||||
{:class (when (= @active-tab :harmony) "active")
|
{:class (when (= @active-tab :harmony) "active")
|
||||||
:alt (tr "workspace.libraries.colors.rgb-complementary")
|
:alt (tr "workspace.libraries.colors.rgb-complementary")
|
||||||
:on-click set-harmony-tab!} i/picker-harmony]
|
:on-click set-tab!
|
||||||
|
:data-tab "harmony"} i/picker-harmony]
|
||||||
[:div.colorpicker-tab.tooltip.tooltip-bottom.tooltip-expand
|
[:div.colorpicker-tab.tooltip.tooltip-bottom.tooltip-expand
|
||||||
{:class (when (= @active-tab :hsva) "active")
|
{:class (when (= @active-tab :hsva) "active")
|
||||||
:alt (tr "workspace.libraries.colors.hsv")
|
:alt (tr "workspace.libraries.colors.hsv")
|
||||||
:on-click set-hsva-tab!} i/picker-hsv]]
|
:on-click set-tab!
|
||||||
|
:data-tab "hsva"} i/picker-hsv]]
|
||||||
|
|
||||||
(if picking-color?
|
(if picking-color?
|
||||||
[:div.picker-detail-wrapper
|
[:div.picker-detail-wrapper
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
[app.main.data.exports :as de]
|
[app.main.data.exports :as de]
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
[app.main.data.workspace :as dw]
|
[app.main.data.workspace :as dw]
|
||||||
[app.main.data.workspace.colors :as dc]
|
|
||||||
[app.main.data.workspace.common :as dwc]
|
[app.main.data.workspace.common :as dwc]
|
||||||
[app.main.data.workspace.libraries :as dwl]
|
[app.main.data.workspace.libraries :as dwl]
|
||||||
[app.main.data.workspace.shortcuts :as sc]
|
[app.main.data.workspace.shortcuts :as sc]
|
||||||
|
@ -168,9 +167,7 @@
|
||||||
(st/emit! (ptk/event ::ev/event {::ev/name "show-release-notes" :version version}))
|
(st/emit! (ptk/event ::ev/event {::ev/name "show-release-notes" :version version}))
|
||||||
(if (and (kbd/alt? event) (kbd/mod? event))
|
(if (and (kbd/alt? event) (kbd/mod? event))
|
||||||
(st/emit! (modal/show {:type :onboarding}))
|
(st/emit! (modal/show {:type :onboarding}))
|
||||||
(st/emit! (modal/show {:type :release-notes :version version}))))))
|
(st/emit! (modal/show {:type :release-notes :version version}))))))]
|
||||||
|
|
||||||
]
|
|
||||||
|
|
||||||
[:& dropdown {:show true :on-close on-close}
|
[:& dropdown {:show true :on-close on-close}
|
||||||
[:ul.sub-menu.help-info
|
[:ul.sub-menu.help-info
|
||||||
|
@ -603,16 +600,10 @@
|
||||||
(dom/prevent-default event)
|
(dom/prevent-default event)
|
||||||
(reset! editing* true)))
|
(reset! editing* true)))
|
||||||
|
|
||||||
close-modals
|
|
||||||
(mf/use-fn
|
|
||||||
#(st/emit! (dc/stop-picker)
|
|
||||||
(modal/hide)))
|
|
||||||
|
|
||||||
go-back
|
go-back
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps project)
|
(mf/deps project)
|
||||||
(fn []
|
(fn []
|
||||||
(close-modals)
|
|
||||||
(st/emit! (dw/go-to-dashboard project))))
|
(st/emit! (dw/go-to-dashboard project))))
|
||||||
|
|
||||||
nav-to-viewer
|
nav-to-viewer
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
[app.util.object :as obj]
|
[app.util.object :as obj]
|
||||||
[app.util.text-editor :as ted]
|
[app.util.text-editor :as ted]
|
||||||
[app.util.text-svg-position :as tsp]
|
[app.util.text-svg-position :as tsp]
|
||||||
|
[app.util.timers :as ts]
|
||||||
[promesa.core :as p]
|
[promesa.core :as p]
|
||||||
[rumext.v2 :as mf]))
|
[rumext.v2 :as mf]))
|
||||||
|
|
||||||
|
@ -79,25 +80,29 @@
|
||||||
|
|
||||||
(defn- update-text-modifier
|
(defn- update-text-modifier
|
||||||
[{:keys [grow-type id] :as shape} node]
|
[{:keys [grow-type id] :as shape} node]
|
||||||
|
(->> (tsp/calc-position-data id)
|
||||||
|
(p/fmap (fn [position-data]
|
||||||
|
(let [props {:position-data position-data}]
|
||||||
|
(if (contains? #{:auto-height :auto-width} grow-type)
|
||||||
|
(let [{:keys [width height]} (-> (dom/query node ".paragraph-set") (dom/get-client-size))
|
||||||
|
width (mth/ceil width)
|
||||||
|
height (mth/ceil height)]
|
||||||
|
(if (and (not (mth/almost-zero? width)) (not (mth/almost-zero? height)))
|
||||||
|
(cond-> props
|
||||||
|
(= grow-type :auto-width)
|
||||||
|
(assoc :width width)
|
||||||
|
|
||||||
(p/let [position-data (tsp/calc-position-data id)
|
(or (= grow-type :auto-height) (= grow-type :auto-width))
|
||||||
props {:position-data position-data}
|
(assoc :height height))
|
||||||
|
props))
|
||||||
props
|
props))))
|
||||||
(if (contains? #{:auto-height :auto-width} grow-type)
|
(p/fmap (fn [props]
|
||||||
(let [{:keys [width height]} (-> (dom/query node ".paragraph-set") (dom/get-client-size))
|
;; We need to wait for the text modifier to be updated before
|
||||||
width (mth/ceil width)
|
;; we can update the position data. Otherwise the position data
|
||||||
height (mth/ceil height)]
|
;; will be wrong.
|
||||||
(if (and (not (mth/almost-zero? width)) (not (mth/almost-zero? height)))
|
;; TODO: This is a hack. We need to find a better way to do this.
|
||||||
(cond-> props
|
(st/emit! (dwt/update-text-modifier id props))
|
||||||
(= grow-type :auto-width)
|
(ts/schedule 30 #(update-text-shape shape node))))))
|
||||||
(assoc :width width)
|
|
||||||
|
|
||||||
(or (= grow-type :auto-height) (= grow-type :auto-width))
|
|
||||||
(assoc :height height))
|
|
||||||
props))
|
|
||||||
props)]
|
|
||||||
(st/emit! (dwt/update-text-modifier id props))))
|
|
||||||
|
|
||||||
(mf/defc text-container
|
(mf/defc text-container
|
||||||
{::mf/wrap-props false
|
{::mf/wrap-props false
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
(:require
|
(:require
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
|
[app.main.data.workspace.assets :as dwa]
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.ui.components.context-menu-a11y :refer [context-menu-a11y]]
|
[app.main.ui.components.context-menu-a11y :refer [context-menu-a11y]]
|
||||||
[app.main.ui.components.search-bar :refer [search-bar]]
|
[app.main.ui.components.search-bar :refer [search-bar]]
|
||||||
|
@ -68,27 +69,39 @@
|
||||||
{::mf/wrap [mf/memo]
|
{::mf/wrap [mf/memo]
|
||||||
::mf/wrap-props false}
|
::mf/wrap-props false}
|
||||||
[]
|
[]
|
||||||
(let [components-v2 (mf/use-ctx ctx/components-v2)
|
(let [components-v2 (mf/use-ctx ctx/components-v2)
|
||||||
read-only? (mf/use-ctx ctx/workspace-read-only?)
|
read-only? (mf/use-ctx ctx/workspace-read-only?)
|
||||||
new-css-system (mf/use-ctx ctx/new-css-system)
|
new-css-system (mf/use-ctx ctx/new-css-system)
|
||||||
filters* (mf/use-state
|
filters* (mf/use-state
|
||||||
{:term ""
|
{:term ""
|
||||||
:section "all"
|
:section "all"
|
||||||
:ordering :asc
|
:ordering (dwa/get-current-assets-ordering)
|
||||||
:list-style :thumbs
|
:list-style (dwa/get-current-assets-list-style)
|
||||||
:open-menu false})
|
:open-menu false})
|
||||||
filters (deref filters*)
|
filters (deref filters*)
|
||||||
term (:term filters)
|
term (:term filters)
|
||||||
menu-open? (:open-menu filters)
|
ordering (:ordering filters)
|
||||||
section (:section filters)
|
list-style (:list-style filters)
|
||||||
ordering (:ordering filters)
|
menu-open? (:open-menu filters)
|
||||||
reverse-sort? (= :desc ordering)
|
section (:section filters)
|
||||||
|
ordering (:ordering filters)
|
||||||
|
reverse-sort? (= :desc ordering)
|
||||||
|
|
||||||
toggle-ordering
|
toggle-ordering
|
||||||
(mf/use-fn #(swap! filters* update :ordering toggle-values [:asc :desc]))
|
(mf/use-fn
|
||||||
|
(mf/deps ordering)
|
||||||
|
(fn []
|
||||||
|
(let [new-value (toggle-values ordering [:asc :desc])]
|
||||||
|
(swap! filters* assoc :ordering new-value)
|
||||||
|
(dwa/set-current-assets-ordering! new-value))))
|
||||||
|
|
||||||
toggle-list-style
|
toggle-list-style
|
||||||
(mf/use-fn #(swap! filters* update :list-style toggle-values [:thumbs :list]))
|
(mf/use-fn
|
||||||
|
(mf/deps list-style)
|
||||||
|
(fn []
|
||||||
|
(let [new-value (toggle-values list-style [:thumbs :list])]
|
||||||
|
(swap! filters* assoc :list-style new-value)
|
||||||
|
(dwa/set-current-assets-list-style! new-value))))
|
||||||
|
|
||||||
on-search-term-change
|
on-search-term-change
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
|
|
|
@ -368,10 +368,16 @@
|
||||||
|
|
||||||
[:div.element-actions {:class (when ^boolean has-shapes? "is-parent")}
|
[:div.element-actions {:class (when ^boolean has-shapes? "is-parent")}
|
||||||
[:div.toggle-element {:class (when ^boolean hidden? "selected")
|
[:div.toggle-element {:class (when ^boolean hidden? "selected")
|
||||||
|
:title (if (:hidden item)
|
||||||
|
(tr "workspace.shape.menu.show")
|
||||||
|
(tr "workspace.shape.menu.hide"))
|
||||||
:on-click toggle-visibility}
|
:on-click toggle-visibility}
|
||||||
(if ^boolean hidden? i/eye-closed i/eye)]
|
(if ^boolean hidden? i/eye-closed i/eye)]
|
||||||
[:div.block-element {:class (when ^boolean blocked? "selected")
|
[:div.block-element {:class (when ^boolean blocked? "selected")
|
||||||
:on-click toggle-blocking}
|
:on-click toggle-blocking
|
||||||
|
:title (if (:blocked item)
|
||||||
|
(tr "workspace.shape.menu.unlock")
|
||||||
|
(tr "workspace.shape.menu.lock"))}
|
||||||
(if ^boolean blocked? i/lock i/unlock)]]
|
(if ^boolean blocked? i/lock i/unlock)]]
|
||||||
|
|
||||||
(when ^boolean has-shapes?
|
(when ^boolean has-shapes?
|
||||||
|
|
Loading…
Add table
Reference in a new issue