Merge remote-tracking branch 'origin/staging' into develop

This commit is contained in:
Alejandro Alonso 2023-04-03 12:21:12 +02:00
commit 68b26d5f41
73 changed files with 693 additions and 295 deletions

View file

@ -925,6 +925,13 @@
{:num-files (count ids)
:project-id project-id})
ptk/UpdateEvent
(update [_ state]
(let [origin-project (get-in state [:dashboard-files (first ids) :project-id])]
(-> state
(update-in [:dashboard-projects origin-project :count] #(- % (count ids)))
(update-in [:dashboard-projects project-id :count] #(+ % (count ids))))))
ptk/WatchEvent
(watch [_ _ _]
(let [{:keys [on-success on-error]

View file

@ -9,6 +9,12 @@
import Mousetrap from 'mousetrap'
if (Mousetrap.addKeycodes) {
Mousetrap.addKeycodes({
219: '219'
});
}
const target = Mousetrap.prototype || Mousetrap;
target.stopCallback = function(e, element, combo) {
// if the element has the class "mousetrap" then no need to stop
@ -20,7 +26,7 @@ target.stopCallback = function(e, element, combo) {
return element.tagName == 'INPUT' ||
element.tagName == 'SELECT' ||
element.tagName == 'TEXTAREA' ||
element.tagName == 'BUTTON' ||
(element.tagName == 'BUTTON' && combo.includes("tab")) ||
(element.contentEditable && element.contentEditable == 'true');
}

View file

@ -676,6 +676,10 @@
(cond-> (not (ctl/any-layout? objects parent-id))
(pcb/update-shapes ordered-indexes ctl/remove-layout-item-data))
;; Remove the hide in viewer flag
(cond-> (and (not= uuid/zero parent-id) (cph/frame-shape? objects parent-id))
(pcb/update-shapes ordered-indexes #(cond-> % (cph/frame-shape? %) (assoc :hide-in-viewer true))))
;; Move the shapes
(pcb/change-parent parent-id
shapes
@ -1311,8 +1315,8 @@
;; Prepare the shape object. Mainly needed for image shapes
;; for retrieve the image data and convert it to the
;; data-url.
(prepare-object [objects selected+children {:keys [type] :as obj}]
(let [obj (maybe-translate obj objects selected+children)]
(prepare-object [objects parent-frame-id {:keys [type] :as obj}]
(let [obj (maybe-translate obj objects parent-frame-id)]
(if (= type :image)
(let [url (cf/resolve-file-media (:metadata obj))]
(->> (http/send! {:method :get
@ -1335,15 +1339,11 @@
(update res :images conj img-part))
res)))
(maybe-translate [shape objects selected+children]
(let [root-frame-id (cph/get-shape-id-root-frame objects (:id shape))]
(if (and (not (cph/root-frame? shape))
(not (contains? selected+children root-frame-id)))
;; When the parent frame is not selected we change to relative
;; coordinates
(let [frame (get objects root-frame-id)]
(gsh/translate-to-frame shape frame))
shape)))
(maybe-translate [shape objects parent-frame-id]
(if (= parent-frame-id uuid/zero)
shape
(let [frame (get objects parent-frame-id)]
(gsh/translate-to-frame shape frame))))
(on-copy-error [error]
(js/console.error "Clipboard blocked:" error)
@ -1356,7 +1356,7 @@
selected (->> (wsh/lookup-selected state)
(cph/clean-loops objects))
selected+children (cph/selected-with-children objects selected)
parent-frame-id (cph/common-parent-frame objects selected)
pdata (reduce (partial collect-object-ids objects) {} selected)
initial {:type :copied-shapes
:file-id (:current-file-id state)
@ -1371,7 +1371,7 @@
(catch :default e
(on-copy-error e)))
(->> (rx/from (seq (vals pdata)))
(rx/merge-map (partial prepare-object objects selected+children))
(rx/merge-map (partial prepare-object objects parent-frame-id))
(rx/reduce collect-data initial)
(rx/map (partial sort-selected state))
(rx/map t/encode-str)

View file

@ -138,6 +138,7 @@
(pcb/with-objects objects)
(cond-> (not (ctl/any-layout? objects frame-id))
(pcb/update-shapes ordered-indexes ctl/remove-layout-item-data))
(pcb/update-shapes ordered-indexes #(cond-> % (cph/frame-shape? %) (assoc :hide-in-viewer true)))
(pcb/change-parent frame-id to-move-shapes 0)
(cond-> (ctl/grid-layout? objects frame-id)
(pcb/update-shapes [frame-id] ctl/assign-cells))))]

View file

@ -354,12 +354,14 @@
:fn #(st/emit! (dw/select-all))}
:toggle-grid {:tooltip (ds/meta "'")
:command (ds/c-mod "'")
;;https://github.com/ccampbell/mousetrap/issues/85
:command [(ds/c-mod "'") (ds/c-mod "219")]
:subsections [:main-menu]
:fn #(st/emit! (toggle-layout-flag :display-grid))}
:toggle-snap-grid {:tooltip (ds/meta-shift "'")
:command (ds/c-mod "shift+'")
;;https://github.com/ccampbell/mousetrap/issues/85
:command [(ds/c-mod "shift+'") (ds/c-mod "shift+219")]
:subsections [:main-menu]
:fn #(st/emit! (toggle-layout-flag :snap-grid))}

View file

@ -164,11 +164,13 @@
(cond-> shape
(get-in shape [:svg-attrs :opacity])
(-> (update :svg-attrs dissoc :opacity)
(assoc :opacity (get-in shape [:svg-attrs :opacity])))
(assoc :opacity (-> (get-in shape [:svg-attrs :opacity])
(d/parse-double))))
(get-in shape [:svg-attrs :style :opacity])
(-> (update-in [:svg-attrs :style] dissoc :opacity)
(assoc :opacity (get-in shape [:svg-attrs :style :opacity])))
(assoc :opacity (-> (get-in shape [:svg-attrs :style :opacity])
(d/parse-double))))
(get-in shape [:svg-attrs :mix-blend-mode])
@ -410,7 +412,8 @@
(assoc :strokes [])
(assoc :svg-defs (select-keys (:defs svg-data) references))
(setup-fill)
(setup-stroke))
(setup-stroke)
(setup-opacity))
shape (cond-> shape
hidden (assoc :hidden true))

View file

@ -377,7 +377,7 @@
(assoc-in [:workspace-local :edition] (-> selected first :id)))))))
(defn not-changed? [old-dim new-dim]
(> (mth/abs (- old-dim new-dim)) 1))
(> (mth/abs (- old-dim new-dim)) 0.1))
(defn commit-resize-text
[]

View file

@ -104,7 +104,7 @@
(defn start-resize
"Enter mouse resize mode, until mouse button is released."
[handler ids shape]
(letfn [(resize
(letfn [(resize
[shape initial layout [point lock? center? point-snap]]
(let [{:keys [width height]} (:selrect shape)
{:keys [rotation]} shape
@ -745,13 +745,16 @@
(remove (fn [shape]
(and (ctl/layout-absolute? shape)
(= frame-id (:parent-id shape))))))
moving-shapes-ids
(map :id moving-shapes)
changes
(-> (pcb/empty-changes it page-id)
(pcb/with-objects objects)
;; Remove layout-item properties when moving a shape outside a layout
(cond-> (not (ctl/any-layout? objects frame-id))
(pcb/update-shapes (map :id moving-shapes) ctl/remove-layout-item-data))
(pcb/update-shapes moving-shapes-ids ctl/remove-layout-item-data))
(pcb/update-shapes moving-shapes-ids #(cond-> % (cph/frame-shape? %) (assoc :hide-in-viewer true)))
(pcb/change-parent frame-id moving-shapes drop-index)
(pcb/remove-objects empty-parents))]

View file

@ -269,7 +269,8 @@
{:option-name (tr "labels.rename")
:id "file-rename"
:option-handler on-edit
:data-test "file-rename"}
:data-test "file-rename"})
(when (not is-search-page?)
{:option-name (tr "dashboard.duplicate")
:id "file-duplicate"
:option-handler on-duplicate

View file

@ -144,6 +144,7 @@
create-file
(mf/use-fn
(mf/deps project)
(fn [origin]
(st/emit! (with-meta (dd/create-file {:project-id (:id project)})
{::ev/origin origin}))))]

View file

@ -269,7 +269,9 @@
(mf/use-fn
(mf/deps file)
(fn [name]
(st/emit! (dd/rename-file (assoc file :name name)))
(let [name (str/trim name)]
(when (not= name "")
(st/emit! (dd/rename-file (assoc file :name name)))))
(swap! local assoc :edition false)))
on-edit

View file

@ -22,6 +22,7 @@
[app.util.keyboard :as kbd]
[app.util.webapi :as wapi]
[beicon.core :as rx]
[cuerdas.core :as str]
[potok.core :as ptk]
[rumext.v2 :as mf]))
@ -61,9 +62,11 @@
(->> files
(mapv
(fn [file]
(cond-> file
(= (:file-id file) file-id)
(assoc :name new-name))))))
(let [new-name (str/trim new-name)]
(cond-> file
(and (= (:file-id file) file-id)
(not= "" new-name))
(assoc :name new-name)))))))
(defn remove-file [files file-id]
(->> files
@ -378,7 +381,7 @@
[:div.feedback-banner
[:div.icon i/checkbox-checked]
[:div.message (tr "dashboard.import.import-message" (if (some? template) 1 success-files))]]))
[:div.message (tr "dashboard.import.import-message" (i18n/c (if (some? template) 1 success-files)))]]))
(for [file files]
(let [editing? (and (some? (:file-id file))

View file

@ -362,8 +362,13 @@
(reverse))
recent-map (mf/deref recent-files-ref)
props (some-> profile (get :props {}))
team-hero? (and (:team-hero? props true)
(not (:is-default team)))
you-owner? (get-in team [:permissions :is-owner])
you-admin? (get-in team [:permissions :is-admin])
can-invite? (or you-owner? you-admin?)
team-hero? (and can-invite?
(:team-hero? props true)
(not (:is-default team)))
tutorial-viewed? (:viewed-tutorial? props true)
walkthrough-viewed? (:viewed-walkthrough? props true)

View file

@ -177,7 +177,9 @@
:on-submit on-submit}]]
[:div.action-buttons
[:& fm/submit-button {:label (tr "modals.invite-member-confirm.accept")}]]]]))
[:& fm/submit-button {:label (tr "modals.invite-member-confirm.accept")
:disabled (and (boolean (some current-data-emails current-members-emails))
(empty? (remove current-members-emails current-data-emails)))}]]]]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; MEMBERS SECTION
@ -586,7 +588,8 @@
[:div.empty-invitations
[:span (tr "labels.no-invitations")]
(when can-invite?
[:span (tr "labels.no-invitations-hint")])])
[:& i18n/tr-html {:label "labels.no-invitations-hint"
:tag-name "span"}])])
(mf/defc invitation-section
[{:keys [team invitations] :as props}]
@ -897,6 +900,10 @@
stats (mf/deref refs/dashboard-team-stats)
you-owner? (get-in team [:permissions :is-owner])
you-admin? (get-in team [:permissions :is-admin])
can-edit? (or you-owner? you-admin?)
on-image-click
(mf/use-callback #(dom/click (mf/ref-val finput)))
@ -928,12 +935,14 @@
[:div.label (tr "dashboard.team-info")]
[:div.name (:name team)]
[:div.icon
[:span.update-overlay {:on-click on-image-click} i/image]
(when can-edit?
[:span.update-overlay {:on-click on-image-click} i/image])
[:img {:src (cfg/resolve-team-photo-url team)}]
[:& file-uploader {:accept "image/jpeg,image/png"
:multi false
:ref finput
:on-selected on-file-selected}]]]
(when can-edit?
[:& file-uploader {:accept "image/jpeg,image/png"
:multi false
:ref finput
:on-selected on-file-selected}])]]
[:div.block.owner-block
[:div.label (tr "dashboard.team-members")]

View file

@ -185,6 +185,7 @@
:auto-focus? true
:trim true
:valid-item-fn us/parse-email
:caution-item-fn #{}
:on-submit on-submit
:label (tr "modals.invite-member.emails")}]]

View file

@ -18,6 +18,7 @@
[app.main.ui.releases.v1-15]
[app.main.ui.releases.v1-16]
[app.main.ui.releases.v1-17]
[app.main.ui.releases.v1-18]
[app.main.ui.releases.v1-4]
[app.main.ui.releases.v1-5]
[app.main.ui.releases.v1-6]
@ -87,4 +88,4 @@
(defmethod rc/render-release-notes "0.0"
[params]
(rc/render-release-notes (assoc params :version "1.17")))
(rc/render-release-notes (assoc params :version "1.18")))

View file

@ -0,0 +1,108 @@
;; 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.ui.releases.v1-18
(:require
[app.main.ui.releases.common :as c]
[rumext.v2 :as mf]))
(defmethod c/render-release-notes "1.18"
[{:keys [slide klass next finish navigate version]}]
(mf/html
(case @slide
:start
[:div.modal-overlay
[:div.animated {:class @klass}
[:div.modal-container.onboarding.feature
[:div.modal-left
[:img {:src "images/onboarding-version.jpg" :border "0" :alt "What's new release 1.18"}]]
[:div.modal-right
[:div.modal-title
[:h2 "What's new?"]]
[:span.release "Version " version]
[:div.modal-content
[:p "On this 1.18 release we make Flex Layout even more powerful with smart spacing, absolute position and z-index management."]
[:p "We also continued implementing accessibility improvements to make Penpot more inclusive and published stability and performance enhancements."]]
[:div.modal-navigation
[:button.btn-secondary {:on-click next} "Continue"]]]
[:img.deco {:src "images/deco-left.png" :border "0"}]
[:img.deco.right {:src "images/deco-right.png" :border "0"}]]]]
0
[:div.modal-overlay
[:div.animated {:class @klass}
[:div.modal-container.onboarding.feature
[:div.modal-left
[:img {:src "images/features/1.18-spacing.gif" :border "0" :alt "Spacing management"}]]
[:div.modal-right
[:div.modal-title
[:h2 "Spacing management for Flex layoutFlex-Layout"]]
[:div.modal-content
[:p "Managing Flex Layout spacing is much more intuitive now. Visualize paddings, margins and gaps and drag to resize them."]
[:p "And not only that, when creating Flex layouts, the spacing is predicted, helping you to maintain your design composition."]]
[:div.modal-navigation
[:button.btn-secondary {:on-click next} "Continue"]
[:& c/navigation-bullets
{:slide @slide
:navigate navigate
:total 4}]]]]]]
1
[:div.modal-overlay
[:div.animated {:class @klass}
[:div.modal-container.onboarding.feature
[:div.modal-left
[:img {:src "images/features/1.18-absolute.gif" :border "0" :alt "Position absolute feature"}]]
[:div.modal-right
[:div.modal-title
[:h2 "Absolute position elements in Flex layout"]]
[:div.modal-content
[:p "Sometimes you need to freely position an element in a specific place regardless of the size of the layout where it belongs."]
[:p "Now you can exclude elements from the Flex layout flow using absolute position."]]
[:div.modal-navigation
[:button.btn-secondary {:on-click next} "Continue"]
[:& c/navigation-bullets
{:slide @slide
:navigate navigate
:total 4}]]]]]]
2
[:div.modal-overlay
[:div.animated {:class @klass}
[:div.modal-container.onboarding.feature
[:div.modal-left
[:img {:src "images/features/1.18-z-index.gif" :border "0" :alt "Z-index feature"}]]
[:div.modal-right
[:div.modal-title
[:h2 "More on Flex layout: z-index"]]
[:div.modal-content
[:p "With the new z-index option you can decide the order of overlapping elements while maintaining the layers order."]
[:p "This is another capability that brings Penpot Flex layout even closer to the power of CSS standards."]]
[:div.modal-navigation
[:button.btn-secondary {:on-click next} "Continue"]
[:& c/navigation-bullets
{:slide @slide
:navigate navigate
:total 4}]]]]]]
3
[:div.modal-overlay
[:div.animated {:class @klass}
[:div.modal-container.onboarding.feature
[:div.modal-left
[:img {:src "images/features/1.18-scale.gif" :border "0" :alt "Scale content proportionally"}]]
[:div.modal-right
[:div.modal-title
[:h2 "Scale content proportionally affects strokes, shadows, blurs and corners"]]
[:div.modal-content
[:p "Now you can resize your layers and groups preserving their aspect ratio while scaling their properties proportionally, including strokes, shadows, blurs and corners."]
[:p "Activate the scale tool by pressing K and scale your elements, maintaining their visual aspect."]]
[:div.modal-navigation
[:button.btn-secondary {:on-click finish} "Start!"]
[:& c/navigation-bullets
{:slide @slide
:navigate navigate
:total 4}]]]]]])))

View file

@ -38,20 +38,27 @@
[:use {:href (str "#" shape-id)}]]))
(mf/defc outer-stroke-mask
[{:keys [shape render-id index]}]
[{:keys [shape stroke render-id index]}]
(let [suffix (if index (str "-" index) "")
stroke-mask-id (str "outer-stroke-" render-id "-" (:id shape) suffix)
shape-id (str "stroke-shape-" render-id "-" (:id shape) suffix)
stroke-width (case (:stroke-alignment shape :center)
:center (/ (:stroke-width shape 0) 2)
:outer (:stroke-width shape 0)
stroke-width (case (:stroke-alignment stroke :center)
:center (/ (:stroke-width stroke 0) 2)
:outer (:stroke-width stroke 0)
0)
margin (gsb/shape-stroke-margin shape stroke-width)
bounding-box (-> (gsh/points->selrect (:points shape))
(update :x - (+ stroke-width margin))
(update :y - (+ stroke-width margin))
(update :width + (* 2 (+ stroke-width margin)))
(update :height + (* 2 (+ stroke-width margin))))]
margin (gsb/shape-stroke-margin stroke stroke-width)
selrect
(if (cph/text-shape? shape)
(gsh/position-data-selrect shape)
(gsh/points->selrect (:points shape)))
bounding-box
(-> selrect
(update :x - (+ stroke-width margin))
(update :y - (+ stroke-width margin))
(update :width + (* 2 (+ stroke-width margin)))
(update :height + (* 2 (+ stroke-width margin))))]
[:mask {:id stroke-mask-id
:x (:x bounding-box)
@ -67,17 +74,17 @@
:stroke "none"}}]]))
(mf/defc cap-markers
[{:keys [shape render-id index]}]
[{:keys [stroke render-id index]}]
(let [marker-id-prefix (str "marker-" render-id)
cap-start (:stroke-cap-start shape)
cap-end (:stroke-cap-end shape)
cap-start (:stroke-cap-start stroke)
cap-end (:stroke-cap-end stroke)
stroke-color (if (:stroke-color-gradient shape)
stroke-color (if (:stroke-color-gradient stroke)
(str/format "url(#%s)" (str "stroke-color-gradient_" render-id "_" index))
(:stroke-color shape))
(:stroke-color stroke))
stroke-opacity (when-not (:stroke-color-gradient shape)
(:stroke-opacity shape))]
stroke-opacity (when-not (:stroke-color-gradient stroke)
(:stroke-opacity stroke))]
[:*
(when (or (= cap-start :line-arrow) (= cap-end :line-arrow))
@ -169,36 +176,37 @@
[:rect {:x 3 :y 2.5 :width 0.5 :height 1}]])]))
(mf/defc stroke-defs
[{:keys [shape render-id index]}]
[{:keys [shape stroke render-id index]}]
(let [open-path? (and (= :path (:type shape)) (gsh/open-path? shape))]
[:*
(cond (some? (:stroke-color-gradient shape))
(case (:type (:stroke-color-gradient shape))
(cond (some? (:stroke-color-gradient stroke))
(case (:type (:stroke-color-gradient stroke))
:linear [:> grad/linear-gradient #js {:id (str (name :stroke-color-gradient) "_" render-id "_" index)
:gradient (:stroke-color-gradient shape)
:gradient (:stroke-color-gradient stroke)
:shape shape}]
:radial [:> grad/radial-gradient #js {:id (str (name :stroke-color-gradient) "_" render-id "_" index)
:gradient (:stroke-color-gradient shape)
:gradient (:stroke-color-gradient stroke)
:shape shape}]))
(cond
(and (not open-path?)
(= :inner (:stroke-alignment shape :center))
(> (:stroke-width shape 0) 0))
(= :inner (:stroke-alignment stroke :center))
(> (:stroke-width stroke 0) 0))
[:& inner-stroke-clip-path {:shape shape
:render-id render-id
:index index}]
(and (not open-path?)
(= :outer (:stroke-alignment shape :center))
(> (:stroke-width shape 0) 0))
(= :outer (:stroke-alignment stroke :center))
(> (:stroke-width stroke 0) 0))
[:& outer-stroke-mask {:shape shape
:stroke stroke
:render-id render-id
:index index}]
(or (some? (:stroke-cap-start shape))
(some? (:stroke-cap-end shape)))
[:& cap-markers {:shape shape
(or (some? (:stroke-cap-start stroke))
(some? (:stroke-cap-end stroke)))
[:& cap-markers {:stroke stroke
:render-id render-id
:index index}])]))
@ -216,8 +224,9 @@
base-props (obj/get child "props")
elem-name (obj/get child "type")
shape (obj/get props "shape")
stroke (obj/get props "stroke")
index (obj/get props "index")
stroke-width (:stroke-width shape)
stroke-width (:stroke-width stroke)
suffix (if index (str "-" index) "")
stroke-mask-id (str "outer-stroke-" render-id "-" (:id shape) suffix)
@ -225,7 +234,7 @@
[:g.outer-stroke-shape
[:defs
[:& stroke-defs {:shape shape :render-id render-id :index index}]
[:& stroke-defs {:shape shape :stroke stroke :render-id render-id :index index}]
[:> elem-name (-> (obj/clone base-props)
(obj/set! "id" shape-id)
(obj/set!
@ -258,10 +267,11 @@
base-props (obj/get child "props")
elem-name (obj/get child "type")
shape (obj/get props "shape")
stroke (obj/get props "stroke")
index (obj/get props "index")
transform (obj/get base-props "transform")
stroke-width (:stroke-width shape 0)
stroke-width (:stroke-width stroke 0)
suffix (if index (str "-" index) "")
clip-id (str "inner-stroke-" render-id "-" (:id shape) suffix)
@ -275,7 +285,7 @@
[:g.inner-stroke-shape {:transform transform}
[:defs
[:& stroke-defs {:shape shape :render-id render-id :index index}]
[:& stroke-defs {:shape shape :stroke stroke :render-id render-id :index index}]
[:> elem-name shape-props]]
[:use {:href (str "#" shape-id)
@ -290,33 +300,34 @@
{::mf/wrap-props false}
[props]
(let [child (obj/get props "children")
shape (obj/get props "shape")
(let [child (obj/get props "children")
shape (obj/get props "shape")
stroke (obj/get props "stroke")
render-id (mf/use-ctx muc/render-id)
index (obj/get props "index")
stroke-width (:stroke-width shape 0)
stroke-style (:stroke-style shape :none)
stroke-position (:stroke-alignment shape :center)
stroke-width (:stroke-width stroke 0)
stroke-style (:stroke-style stroke :none)
stroke-position (:stroke-alignment stroke :center)
has-stroke? (and (> stroke-width 0)
(not= stroke-style :none))
closed? (or (not= :path (:type shape))
(not (gsh/open-path? shape)))
closed? (or (not= :path (:type shape)) (not (gsh/open-path? shape)))
inner? (= :inner stroke-position)
outer? (= :outer stroke-position)]
(cond
(and has-stroke? inner? closed?)
[:& inner-stroke {:shape shape :index index}
[:& inner-stroke {:shape shape :stroke stroke :index index}
child]
(and has-stroke? outer? closed?)
[:& outer-stroke {:shape shape :index index}
[:& outer-stroke {:shape shape :stroke stroke :index index}
child]
:else
[:g.stroke-shape
[:defs
[:& stroke-defs {:shape shape :render-id render-id :index index}]]
[:& stroke-defs {:shape shape :stroke stroke :render-id render-id :index index}]]
child])))
(defn build-fill-props [shape child position render-id]
@ -426,6 +437,7 @@
[props]
(let [child (obj/get props "children")
shape (obj/get props "shape")
elem-name (obj/get child "type")
render-id (or (obj/get props "render-id") (mf/use-ctx muc/render-id))
stroke-id (dm/fmt "strokes-%" (:id shape))
@ -445,9 +457,8 @@
(d/not-empty? (:strokes shape))
[:> :g stroke-props
(for [[index value] (-> (d/enumerate (:strokes shape)) reverse)]
(let [props (build-stroke-props index child value render-id)
shape (assoc value :points (:points shape))]
[:& shape-custom-stroke {:shape shape :index index :key (dm/str index "-" stroke-id)}
(let [props (build-stroke-props index child value render-id)]
[:& shape-custom-stroke {:shape shape :stroke value :index index :key (dm/str index "-" stroke-id)}
[:> elem-name props]]))])]))
(mf/defc shape-custom-strokes

View file

@ -46,6 +46,7 @@
(defn- activate-interaction
[interaction shape base-frame frame-offset objects overlays]
(case (:action-type interaction)
:navigate
(when-let [frame-id (:destination interaction)]
@ -69,6 +70,7 @@
overlays-ids (set (map :id overlays))
relative-to-base-frame (find-relative-to-base-frame relative-to-shape objects overlays-ids base-frame)
position (ctsi/calc-overlay-position interaction
shape
viewer-objects
relative-to-shape
relative-to-base-frame
@ -91,6 +93,7 @@
overlays-ids (set (map :id overlays))
relative-to-base-frame (find-relative-to-base-frame relative-to-shape objects overlays-ids base-frame)
position (ctsi/calc-overlay-position interaction
shape
objects
relative-to-shape
relative-to-base-frame
@ -156,6 +159,7 @@
overlays-ids (set (map :id overlays))
relative-to-base-frame (find-relative-to-base-frame relative-to-shape objects overlays-ids base-frame)
position (ctsi/calc-overlay-position interaction
shape
objects
relative-to-shape
relative-to-base-frame

View file

@ -67,7 +67,8 @@
(mf/use-fn
(mf/deps current-color @drag?)
(fn [color]
(when (not= (str/lower (:hex color)) (str/lower (:hex current-color)))
(when (or (not= (str/lower (:hex color)) (str/lower (:hex current-color)))
(not= (:h color) (:h current-color)))
(let [recent-color (merge current-color color)
recent-color (dc/materialize-color-components recent-color)]
(st/emit! (dc/update-colorpicker-color recent-color (not @drag?)))))))

View file

@ -15,6 +15,7 @@
[app.main.data.modal :as modal]
[app.main.data.workspace :as dw]
[app.main.data.workspace.colors :as dc]
[app.main.data.workspace.common :as dwc]
[app.main.data.workspace.libraries :as dwl]
[app.main.data.workspace.shortcuts :as sc]
[app.main.refs :as refs]
@ -32,6 +33,7 @@
[app.util.keyboard :as kbd]
[app.util.router :as rt]
[beicon.core :as rx]
[cuerdas.core :as str]
[okulary.core :as l]
[potok.core :as ptk]
[rumext.v2 :as mf]))
@ -149,10 +151,12 @@
:on-accept #(st/emit! (dwl/set-file-shared (:id file) false))
:count-libraries 1}))))
handle-blur (fn [_]
(let [value (-> edit-input-ref mf/ref-val dom/get-value)]
(st/emit! (dw/rename-file (:id file) value)))
(reset! editing? false))
handle-blur
(fn [_]
(let [value (str/trim (-> edit-input-ref mf/ref-val dom/get-value))]
(when (not= value "")
(st/emit! (dw/rename-file (:id file) value))))
(reset! editing? false))
handle-name-keydown (fn [event]
(when (kbd/enter? event)
@ -306,12 +310,14 @@
[:li {:on-click #(st/emit! (dw/select-all))}
[:span (tr "workspace.header.menu.select-all")]
[:span.shortcut (sc/get-tooltip :select-all)]]
[:li {:on-click #(st/emit! (toggle-flag :scale-text))}
[:span
(if (contains? layout :scale-text)
(tr "workspace.header.menu.disable-scale-text")
(tr "workspace.header.menu.enable-scale-text"))]
[:span.shortcut (sc/get-tooltip :toggle-scale-text)]]]]
[:li {:on-click #(st/emit! dwc/undo)}
[:span (tr "workspace.header.menu.undo")]
[:span.shortcut (sc/get-tooltip :undo)]]
[:li {:on-click #(st/emit! dwc/redo)}
[:span (tr "workspace.header.menu.redo")]
[:span.shortcut (sc/get-tooltip :redo)]]]]
[:& dropdown {:show (= @show-sub-menu? :view)
:on-close #(reset! show-sub-menu? false)}
@ -374,6 +380,13 @@
[:& dropdown {:show (= @show-sub-menu? :preferences)
:on-close #(reset! show-sub-menu? false)}
[:ul.sub-menu.preferences
[:li {:on-click #(st/emit! (toggle-flag :scale-text))}
[:span
(if (contains? layout :scale-text)
(tr "workspace.header.menu.disable-scale-content")
(tr "workspace.header.menu.enable-scale-content"))]
[:span.shortcut (sc/get-tooltip :toggle-scale-text)]]
[:li {:on-click #(st/emit! (toggle-flag :snap-guides))}
[:span
(if (contains? layout :snap-guides)

View file

@ -66,7 +66,8 @@
(when (contains? #{:auto-height :auto-width} grow-type)
(let [{:keys [width height]}
(-> (dom/query node ".paragraph-set")
(dom/get-client-size))
(dom/get-bounding-rect))
width (mth/ceil width)
height (mth/ceil height)]
(when (and (not (mth/almost-zero? width))

View file

@ -161,27 +161,37 @@
on-change
(mf/use-fn
(fn [new-color old-color]
(fn [new-color old-color from-picker?]
(let [old-color (-> old-color
(dissoc :name)
(dissoc :path)
(d/without-nils))
prev-color (-> @prev-color*
(dissoc :name)
(dissoc :path)
(d/without-nils))
prev-color (when @prev-color*
(-> @prev-color*
(dissoc :name)
(dissoc :path)
(d/without-nils)))
;; When dragging on the color picker sometimes all the shapes hasn't updated the color to the prev value so we need this extra calculation
shapes-by-old-color (get @grouped-colors* old-color)
shapes-by-prev-color (get @grouped-colors* prev-color)
shapes-by-color (or shapes-by-prev-color shapes-by-old-color)]
(reset! prev-color* new-color)
(st/emit! (dc/change-color-in-selected new-color shapes-by-color old-color)))))
on-open (mf/use-fn
(fn [color]
(reset! prev-color* color)))
(when from-picker?
(reset! prev-color* new-color))
(st/emit! (dc/change-color-in-selected new-color shapes-by-color (or prev-color old-color))))))
on-open
(mf/use-fn
(fn []
(reset! prev-color* nil)))
on-close
(mf/use-fn
(fn []
(reset! prev-color* nil)))
on-detach
(mf/use-fn
@ -212,8 +222,9 @@
:index index
:on-detach on-detach
:select-only select-only
:on-change #(on-change % color)
:on-open on-open}])
:on-change #(on-change %1 color %2)
:on-open on-open
:on-close on-close}])
(when (and (false? @expand-lib-color) (< 3 (count library-colors)))
[:div.expand-colors {:on-click #(reset! expand-lib-color true)}
[:span i/actions]
@ -225,8 +236,9 @@
:index index
:on-detach on-detach
:select-only select-only
:on-change #(on-change % color)
:on-open on-open}]))]
:on-change #(on-change %1 color %2)
:on-open on-open
:on-close on-close}]))]
[:div.selected-colors
(for [[index color] (d/enumerate (take 3 colors))]
@ -234,8 +246,9 @@
:color color
:index index
:select-only select-only
:on-change #(on-change % color)
:on-open on-open}])
:on-change #(on-change %1 color %2)
:on-open on-open
:on-close on-close}])
(when (and (false? @expand-color) (< 3 (count colors)))
[:div.expand-colors {:on-click #(reset! expand-color true)}
[:span i/actions]
@ -246,5 +259,6 @@
:color color
:index index
:select-only select-only
:on-change #(on-change % color)
:on-open on-open}]))]]])))
:on-change #(on-change %1 color %2)
:on-open on-open
:on-close on-close}]))]]])))

View file

@ -113,7 +113,8 @@
:y y
:disable-gradient disable-gradient
:disable-opacity disable-opacity
:on-change #(on-change (merge uc/empty-color %))
;; on-change second parameter means if the source is the color-picker
:on-change #(on-change (merge uc/empty-color %) true)
:on-close (fn [value opacity id file-id]
(when on-close
(on-close value opacity id file-id)))

View file

@ -46,4 +46,5 @@
(defn camelize
[str]
;; str.replace(":", "-").replace(/-./g, x=>x[1].toUpperCase())
(js* "~{}.replace(\":\", \"-\").replace(/-./g, x=>x[1].toUpperCase())", str))
(when (not (nil? str))
(js* "~{}.replace(\":\", \"-\").replace(/-./g, x=>x[1].toUpperCase())", str)))