mirror of
https://github.com/penpot/penpot.git
synced 2025-05-02 22:05:54 +02:00
Merge remote-tracking branch 'origin/staging' into develop
This commit is contained in:
commit
064981ff3d
9 changed files with 150 additions and 71 deletions
|
@ -34,6 +34,11 @@
|
|||
- Increase the height of the right sidebar dropdowns [Taiga #10615](https://tree.taiga.io/project/penpot/issue/10615)
|
||||
- Fix scroll on token themes modal [Taiga #10745](https://tree.taiga.io/project/penpot/issue/10745)
|
||||
- Fix unexpected exception on path editor on merge segments when undo stack is empty
|
||||
- Fix pricing CTA to be under a config flag [Taiga #10808](https://tree.taiga.io/project/penpot/issue/10808)
|
||||
- Fix allow moving a main component into another [Taiga #10818](https://tree.taiga.io/project/penpot/issue/10818)
|
||||
- Fix several issues with internal srepl helpers
|
||||
- Fix unexpected exception on template import from libraries
|
||||
- Fix incorrect uuid parsing from different parts of code
|
||||
|
||||
## 2.6.1
|
||||
|
||||
|
|
|
@ -273,7 +273,7 @@
|
|||
|
||||
(defn- http-handler
|
||||
[cfg {:keys [params ::session/profile-id] :as request}]
|
||||
(let [session-id (some-> params :session-id sm/parse-uuid)]
|
||||
(let [session-id (some-> params :session-id uuid/parse*)]
|
||||
(when-not (uuid? session-id)
|
||||
(ex/raise :type :validation
|
||||
:code :missing-session-id
|
||||
|
|
|
@ -390,20 +390,22 @@
|
|||
(register! :merge (mu/-merge))
|
||||
(register! :union (mu/-union))
|
||||
|
||||
(def uuid-rx
|
||||
#"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$")
|
||||
|
||||
(defn parse-uuid
|
||||
(defn- parse-uuid
|
||||
[s]
|
||||
(try
|
||||
(uuid/parse s)
|
||||
(catch #?(:clj Exception :cljs :default) _cause
|
||||
s)))
|
||||
(if (uuid? s)
|
||||
s
|
||||
(if (str/empty? s)
|
||||
nil
|
||||
(try
|
||||
(uuid/parse s)
|
||||
(catch #?(:clj Exception :cljs :default) _cause
|
||||
s)))))
|
||||
|
||||
(defn encode-uuid
|
||||
(defn- encode-uuid
|
||||
[v]
|
||||
(when (uuid? v)
|
||||
(str v)))
|
||||
(if (uuid? v)
|
||||
(str v)
|
||||
v))
|
||||
|
||||
(register!
|
||||
{:type ::uuid
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
(let [smallest (-> params :shrunk :smallest vec)]
|
||||
(println)
|
||||
(println "Condition failed with the following params:")
|
||||
(println "Seed:" (:seed params))
|
||||
(println)
|
||||
(pp/pprint smallest)))
|
||||
|
||||
|
|
|
@ -479,7 +479,7 @@
|
|||
;; We can always move the children to the parent they already have.
|
||||
;; But if we are pasting, those are new items, so it is considered a change
|
||||
no-changes?
|
||||
(and (->> children (every? #(= parent-id (:parent-id %))))
|
||||
(and (every? #(= parent-id (:parent-id %)) children)
|
||||
(not pasting?))
|
||||
|
||||
;; When pasting frames, children have the frames and their children
|
||||
|
@ -489,7 +489,13 @@
|
|||
|
||||
;; Are all the top-children a main-instance of a component?
|
||||
all-main?
|
||||
(->> top-children (every? #(ctk/main-instance? %)))
|
||||
(every? ctk/main-instance? top-children)
|
||||
|
||||
any-main-descendant
|
||||
(some
|
||||
(fn [shape]
|
||||
(some ctk/main-instance? (cfh/get-children-with-self objects (:id shape))))
|
||||
children)
|
||||
|
||||
;; Are all the top-children a main-instance of a cutted component?
|
||||
all-comp-cut?
|
||||
|
@ -501,6 +507,8 @@
|
|||
(every? :deleted)))]
|
||||
(if (or no-changes?
|
||||
(and (not (invalid-structure-for-component? objects parent children pasting? libraries))
|
||||
;; If we are moving into a main component, no descendant can be main
|
||||
(or (nil? any-main-descendant) (not (ctk/main-instance? parent)))
|
||||
;; If we are moving into a variant-container, all the items should be main
|
||||
;; so if we are pasting, only allow main instances that are cut-and-pasted
|
||||
(or (not (ctk/is-variant-container? parent))
|
||||
|
|
|
@ -109,13 +109,27 @@
|
|||
(def check-animation!
|
||||
(sm/check-fn schema:animation))
|
||||
|
||||
(def schema:interaction-attrs
|
||||
[:map {:title "InteractionAttrs"}
|
||||
[:action-type {:optional true} [::sm/one-of action-types]]
|
||||
[:event-type {:optional true} [::sm/one-of event-types]]
|
||||
[:destination {:optional true} [:maybe ::sm/uuid]]
|
||||
[:preserve-scroll {:optional true} :boolean]
|
||||
[:animation {:optional true} schema:animation]
|
||||
[:overlay-position {:optional true} ::gpt/point]
|
||||
[:overlay-pos-type {:optional true} [::sm/one-of overlay-positioning-types]]
|
||||
[:close-click-outside {:optional true} :boolean]
|
||||
[:background-overlay {:optional true} :boolean]
|
||||
[:position-relative-to {:optional true} [:maybe ::sm/uuid]]
|
||||
[:url {:optional true} :string]])
|
||||
|
||||
(def schema:navigate-interaction
|
||||
[:map
|
||||
[:action-type [:= :navigate]]
|
||||
[:event-type [::sm/one-of event-types]]
|
||||
[:destination {:optional true} [:maybe ::sm/uuid]]
|
||||
[:preserve-scroll {:optional true} :boolean]
|
||||
[:animation {:optional true} ::animation]])
|
||||
[:animation {:optional true} schema:animation]])
|
||||
|
||||
(def schema:open-overlay-interaction
|
||||
[:map
|
||||
|
@ -126,7 +140,7 @@
|
|||
[:destination {:optional true} [:maybe ::sm/uuid]]
|
||||
[:close-click-outside {:optional true} :boolean]
|
||||
[:background-overlay {:optional true} :boolean]
|
||||
[:animation {:optional true} ::animation]
|
||||
[:animation {:optional true} schema:animation]
|
||||
[:position-relative-to {:optional true} [:maybe ::sm/uuid]]])
|
||||
|
||||
(def schema:toggle-overlay-interaction
|
||||
|
@ -138,7 +152,7 @@
|
|||
[:destination {:optional true} [:maybe ::sm/uuid]]
|
||||
[:close-click-outside {:optional true} :boolean]
|
||||
[:background-overlay {:optional true} :boolean]
|
||||
[:animation {:optional true} ::animation]
|
||||
[:animation {:optional true} schema:animation]
|
||||
[:position-relative-to {:optional true} [:maybe ::sm/uuid]]])
|
||||
|
||||
(def schema:close-overlay-interaction
|
||||
|
@ -146,7 +160,7 @@
|
|||
[:action-type [:= :close-overlay]]
|
||||
[:event-type [::sm/one-of event-types]]
|
||||
[:destination {:optional true} [:maybe ::sm/uuid]]
|
||||
[:animation {:optional true} ::animation]
|
||||
[:animation {:optional true} schema:animation]
|
||||
[:position-relative-to {:optional true} [:maybe ::sm/uuid]]])
|
||||
|
||||
(def schema:prev-scren-interaction
|
||||
|
@ -161,21 +175,21 @@
|
|||
[:url :string]])
|
||||
|
||||
(def schema:interaction
|
||||
[:multi {:dispatch :action-type
|
||||
:title "Interaction"
|
||||
:gen/gen (sg/one-of (sg/generator schema:navigate-interaction)
|
||||
(sg/generator schema:open-overlay-interaction)
|
||||
(sg/generator schema:close-overlay-interaction)
|
||||
(sg/generator schema:toggle-overlay-interaction)
|
||||
(sg/generator schema:prev-scren-interaction)
|
||||
(sg/generator schema:open-url-interaction))
|
||||
:decode/json #(update % :action-type keyword)}
|
||||
[:navigate schema:navigate-interaction]
|
||||
[:open-overlay schema:open-overlay-interaction]
|
||||
[:toggle-overlay schema:toggle-overlay-interaction]
|
||||
[:close-overlay schema:close-overlay-interaction]
|
||||
[:prev-screen schema:prev-scren-interaction]
|
||||
[:open-url schema:open-url-interaction]])
|
||||
[:and {:title "Interaction"
|
||||
:gen/gen (sg/one-of (sg/generator schema:navigate-interaction)
|
||||
(sg/generator schema:open-overlay-interaction)
|
||||
(sg/generator schema:close-overlay-interaction)
|
||||
(sg/generator schema:toggle-overlay-interaction)
|
||||
(sg/generator schema:prev-scren-interaction)
|
||||
(sg/generator schema:open-url-interaction))}
|
||||
schema:interaction-attrs
|
||||
[:multi {:dispatch :action-type}
|
||||
[:navigate schema:navigate-interaction]
|
||||
[:open-overlay schema:open-overlay-interaction]
|
||||
[:toggle-overlay schema:toggle-overlay-interaction]
|
||||
[:close-overlay schema:close-overlay-interaction]
|
||||
[:prev-screen schema:prev-scren-interaction]
|
||||
[:open-url schema:open-url-interaction]]])
|
||||
|
||||
(sm/register! ::interaction schema:interaction)
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
[app.main.ui.dashboard.file-menu :refer [file-menu*]]
|
||||
[app.main.ui.dashboard.import :refer [use-import-file]]
|
||||
[app.main.ui.dashboard.inline-edition :refer [inline-edition]]
|
||||
[app.main.ui.dashboard.placeholder :refer [empty-placeholder loading-placeholder]]
|
||||
[app.main.ui.dashboard.placeholder :refer [empty-grid-placeholder* loading-placeholder*]]
|
||||
[app.main.ui.ds.product.loader :refer [loader*]]
|
||||
[app.main.ui.hooks :as h]
|
||||
[app.main.ui.icons :as i]
|
||||
|
@ -511,7 +511,7 @@
|
|||
:ref node-ref}
|
||||
(cond
|
||||
(nil? files)
|
||||
[:& loading-placeholder]
|
||||
[:> loading-placeholder*]
|
||||
|
||||
(seq files)
|
||||
(for [[index slice] (d/enumerate (partition-all limit files))]
|
||||
|
@ -528,12 +528,13 @@
|
|||
:can-edit can-edit}])])
|
||||
|
||||
:else
|
||||
[:& empty-placeholder
|
||||
[:> empty-grid-placeholder*
|
||||
{:limit limit
|
||||
:can-edit can-edit
|
||||
:create-fn create-fn
|
||||
:origin origin
|
||||
:project-id project-id
|
||||
:team-id team-id
|
||||
:on-finish-import on-finish-import}])]))
|
||||
|
||||
(mf/defc line-grid-row
|
||||
|
@ -645,7 +646,7 @@
|
|||
:on-drop on-drop}
|
||||
(cond
|
||||
(nil? files)
|
||||
[:& loading-placeholder]
|
||||
[:> loading-placeholder*]
|
||||
|
||||
(seq files)
|
||||
[:& line-grid-row {:files files
|
||||
|
@ -656,10 +657,11 @@
|
|||
:limit limit}]
|
||||
|
||||
:else
|
||||
[:& empty-placeholder
|
||||
{:dragging? @dragging?
|
||||
[:> empty-grid-placeholder*
|
||||
{:is-dragging @dragging?
|
||||
:limit limit
|
||||
:can-edit can-edit
|
||||
:create-fn create-fn
|
||||
:project-id project-id
|
||||
:team-id team-id
|
||||
:on-finish-import on-finish-import}])]))
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.dashboard.import :as udi]
|
||||
[app.main.ui.ds.product.empty-placeholder :refer [empty-placeholder*]]
|
||||
|
@ -16,51 +15,92 @@
|
|||
[app.main.ui.icons :as i]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[okulary.core :as l]
|
||||
[potok.v2.core :as ptk]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc empty-placeholder-projects*
|
||||
{::mf/wrap-props false}
|
||||
[{:keys [on-create on-finish-import project-id] :as props}]
|
||||
(mf/defc empty-project-placeholder*
|
||||
{::mf/private true}
|
||||
[{:keys [on-create on-finish-import project-id]}]
|
||||
(let [file-input (mf/use-ref nil)
|
||||
on-add-library (mf/use-fn
|
||||
(fn [_]
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "explore-libraries-click"
|
||||
::ev/origin "dashboard"
|
||||
:section "empty-placeholder-projects"}))
|
||||
(dom/open-new-window "https://penpot.app/penpothub/libraries-templates")))
|
||||
on-import-files (mf/use-fn #(dom/click (mf/ref-val file-input)))]
|
||||
|
||||
on-add-library
|
||||
(mf/use-fn
|
||||
(fn [_]
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "explore-libraries-click"
|
||||
::ev/origin "dashboard"
|
||||
:section "empty-placeholder-projects"}))
|
||||
(dom/open-new-window "https://penpot.app/penpothub/libraries-templates")))
|
||||
|
||||
on-import
|
||||
(mf/use-fn #(dom/click (mf/ref-val file-input)))]
|
||||
|
||||
[:div {:class (stl/css :empty-project-container)}
|
||||
[:div {:class (stl/css :empty-project-card) :on-click on-create :title (tr "dashboard.add-file")}
|
||||
[:div {:class (stl/css :empty-project-card-title)} (tr "dashboard.empty-project.create")]
|
||||
[:div {:class (stl/css :empty-project-card-subtitle)} (tr "dashboard.empty-project.start")]]
|
||||
[:div {:class (stl/css :empty-project-card)
|
||||
:on-click on-create
|
||||
:title (tr "dashboard.add-file")}
|
||||
[:div {:class (stl/css :empty-project-card-title)}
|
||||
(tr "dashboard.empty-project.create")]
|
||||
[:div {:class (stl/css :empty-project-card-subtitle)}
|
||||
(tr "dashboard.empty-project.start")]]
|
||||
|
||||
[:div {:class (stl/css :empty-project-card) :on-click on-import-files :title (tr "dashboard.empty-project.import")}
|
||||
[:div {:class (stl/css :empty-project-card-title)} (tr "dashboard.empty-project.import")]
|
||||
[:div {:class (stl/css :empty-project-card-subtitle)} (tr "dashboard.empty-project.import-penpot")]]
|
||||
[:div {:class (stl/css :empty-project-card)
|
||||
:on-click on-import
|
||||
:title (tr "dashboard.empty-project.import")}
|
||||
[:div {:class (stl/css :empty-project-card-title)}
|
||||
(tr "dashboard.empty-project.import")]
|
||||
[:div {:class (stl/css :empty-project-card-subtitle)}
|
||||
(tr "dashboard.empty-project.import-penpot")]]
|
||||
|
||||
[:div {:class (stl/css :empty-project-card) :on-click on-add-library :title (tr "dashboard.empty-project.go-to-libraries")}
|
||||
[:div {:class (stl/css :empty-project-card-title)} (tr "dashboard.empty-project.add-library")]
|
||||
[:div {:class (stl/css :empty-project-card-subtitle)} (tr "dashboard.empty-project.explore")]]
|
||||
[:div {:class (stl/css :empty-project-card)
|
||||
:on-click on-add-library
|
||||
:title (tr "dashboard.empty-project.go-to-libraries")}
|
||||
[:div {:class (stl/css :empty-project-card-title)}
|
||||
(tr "dashboard.empty-project.add-library")]
|
||||
[:div {:class (stl/css :empty-project-card-subtitle)}
|
||||
(tr "dashboard.empty-project.explore")]]
|
||||
|
||||
[:& udi/import-form {:ref file-input
|
||||
:project-id project-id
|
||||
:on-finish-import on-finish-import}]]))
|
||||
|
||||
(mf/defc empty-placeholder
|
||||
[{:keys [dragging? limit origin create-fn can-edit project-id on-finish-import]}]
|
||||
(defn- make-has-other-files-or-projects-ref
|
||||
"Return a ref that resolves to true or false if there are at least some
|
||||
file or some project (a part of the default) exists; this determines
|
||||
if we need to show a complete placeholder or the small one."
|
||||
[team-id]
|
||||
(l/derived (fn [state]
|
||||
(or (let [projects (get state :projects)]
|
||||
(some (fn [[_ project]]
|
||||
(and (= (:team-id project) team-id)
|
||||
(not (:is-default project))))
|
||||
projects))
|
||||
(let [files (get state :files)]
|
||||
(some (fn [[_ file]]
|
||||
(= (:team-id file) team-id))
|
||||
files))))
|
||||
st/state))
|
||||
|
||||
(mf/defc empty-grid-placeholder*
|
||||
[{:keys [is-dragging limit origin create-fn can-edit team-id project-id on-finish-import]}]
|
||||
(let [on-click
|
||||
(mf/use-fn
|
||||
(mf/deps create-fn)
|
||||
(fn [_]
|
||||
(create-fn "dashboard:empty-folder-placeholder")))
|
||||
show-text (mf/use-state nil)
|
||||
on-mouse-enter (mf/use-fn #(reset! show-text true))
|
||||
on-mouse-leave (mf/use-fn #(reset! show-text nil))
|
||||
files (mf/deref refs/files)]
|
||||
|
||||
show-text* (mf/use-state nil)
|
||||
show-text? (deref show-text*)
|
||||
|
||||
on-mouse-enter (mf/use-fn #(reset! show-text* true))
|
||||
on-mouse-leave (mf/use-fn #(reset! show-text* nil))
|
||||
|
||||
has-other* (mf/with-memo [team-id]
|
||||
(make-has-other-files-or-projects-ref team-id))
|
||||
has-other? (mf/deref has-other*)]
|
||||
|
||||
(cond
|
||||
(true? dragging?)
|
||||
(true? is-dragging)
|
||||
[:ul
|
||||
{:class (stl/css :grid-row :no-wrap)
|
||||
:style {:grid-template-columns (str "repeat(" limit ", 1fr)")}}
|
||||
|
@ -80,18 +120,24 @@
|
|||
:tag-name "span"}])]
|
||||
|
||||
:else
|
||||
(if (= (count files) 0)
|
||||
[:> empty-placeholder-projects* {:on-create on-click :on-finish-import on-finish-import :project-id project-id}]
|
||||
(if-not has-other?
|
||||
[:> empty-project-placeholder*
|
||||
{:on-create on-click
|
||||
:on-finish-import on-finish-import
|
||||
:project-id project-id}]
|
||||
[:div {:class (stl/css :grid-empty-placeholder)}
|
||||
[:button {:class (stl/css :create-new)
|
||||
:on-click on-click
|
||||
:on-mouse-enter on-mouse-enter
|
||||
:on-mouse-leave on-mouse-leave}
|
||||
(if @show-text (tr "dashboard.empty-project.create") i/add)]]))))
|
||||
(if show-text?
|
||||
(tr "dashboard.empty-project.create")
|
||||
i/add)]]))))
|
||||
|
||||
(mf/defc loading-placeholder
|
||||
(mf/defc loading-placeholder*
|
||||
[]
|
||||
[:> loader* {:width 32
|
||||
:title (tr "labels.loading")
|
||||
:class (stl/css :placeholder-loader)}
|
||||
[:span {:class (stl/css :placeholder-text)} (tr "dashboard.loading-files")]])
|
||||
[:span {:class (stl/css :placeholder-text)}
|
||||
(tr "dashboard.loading-files")]])
|
||||
|
|
|
@ -371,6 +371,7 @@
|
|||
show-team-hero?
|
||||
can-invite))}
|
||||
(for [{:keys [id] :as project} projects]
|
||||
;; FIXME: refactor this, looks inneficient
|
||||
(let [files (when recent-map
|
||||
(->> (vals recent-map)
|
||||
(filterv #(= id (:project-id %)))
|
||||
|
|
Loading…
Add table
Reference in a new issue