mirror of
https://github.com/penpot/penpot.git
synced 2025-05-07 23:55:54 +02:00
Merge remote-tracking branch 'origin/staging' into develop
This commit is contained in:
commit
a055a31286
46 changed files with 756 additions and 620 deletions
10
CHANGES.md
10
CHANGES.md
|
@ -52,6 +52,7 @@
|
||||||
|
|
||||||
### :sparkles: New features
|
### :sparkles: New features
|
||||||
|
|
||||||
|
- Add some cosmetic changes in viewer mode [Taiga #3688](https://tree.taiga.io/project/penpot/us/3688)
|
||||||
- Allow for nested and rotated boards inside other boards and groups [Taiga #2874](https://tree.taiga.io/project/penpot/us/2874?milestone=319982)
|
- Allow for nested and rotated boards inside other boards and groups [Taiga #2874](https://tree.taiga.io/project/penpot/us/2874?milestone=319982)
|
||||||
- View mode improvements to enable access and use in different conditions [Taiga #3023](https://tree.taiga.io/project/penpot/us/3023)
|
- View mode improvements to enable access and use in different conditions [Taiga #3023](https://tree.taiga.io/project/penpot/us/3023)
|
||||||
- Improved share link options. Now you can allow non-team members to comment and/or inspect [Taiga #3056] (https://tree.taiga.io/project/penpot/us/3056)
|
- Improved share link options. Now you can allow non-team members to comment and/or inspect [Taiga #3056] (https://tree.taiga.io/project/penpot/us/3056)
|
||||||
|
@ -63,7 +64,10 @@
|
||||||
|
|
||||||
### :bug: Bugs fixed
|
### :bug: Bugs fixed
|
||||||
|
|
||||||
- Fix font rendering on grid thumbnails [Taiga #3473](https://tree.taiga.io/project/penpot/issue/3473)
|
- Fix viewer scroll problems [Taiga 3403](https://tree.taiga.io/project/penpot/issue/3403)
|
||||||
|
- Fix hide html options on handoff [Taiga 3533](https://tree.taiga.io/project/penpot/issue/3533)
|
||||||
|
- Fix share prototypes overlay and stroke [Taiga #3994](https://tree.taiga.io/project/penpot/issue/3994)
|
||||||
|
- Fix border radious on boolean operations [Taiga #3959](https://tree.taiga.io/project/penpot/issue/3959)
|
||||||
- Fix inconsistent representation of rectangles [Taiga #3977](https://tree.taiga.io/project/penpot/issue/3977)
|
- Fix inconsistent representation of rectangles [Taiga #3977](https://tree.taiga.io/project/penpot/issue/3977)
|
||||||
- Fix recent fonts info [Taiga #3953](https://tree.taiga.io/project/penpot/issue/3953)
|
- Fix recent fonts info [Taiga #3953](https://tree.taiga.io/project/penpot/issue/3953)
|
||||||
- Fix clipped elements affect boards and centering [Taiga #3666](https://tree.taiga.io/project/penpot/issue/3666)
|
- Fix clipped elements affect boards and centering [Taiga #3666](https://tree.taiga.io/project/penpot/issue/3666)
|
||||||
|
@ -80,6 +84,8 @@
|
||||||
- Fix props preserving on copy&paste texts [Taiga #3629](https://tree.taiga.io/project/penpot/issue/3629) by @andrewzhurov
|
- Fix props preserving on copy&paste texts [Taiga #3629](https://tree.taiga.io/project/penpot/issue/3629) by @andrewzhurov
|
||||||
- Fix unexpected layers ungrouping on moving it [Taiga #3932](https://tree.taiga.io/project/penpot/issue/3932) by @andrewzhurov
|
- Fix unexpected layers ungrouping on moving it [Taiga #3932](https://tree.taiga.io/project/penpot/issue/3932) by @andrewzhurov
|
||||||
- Fix unexpected exception and behavior on colorpicker with gradients [Taiga #3448](https://tree.taiga.io/project/penpot/issue/3448)
|
- Fix unexpected exception and behavior on colorpicker with gradients [Taiga #3448](https://tree.taiga.io/project/penpot/issue/3448)
|
||||||
|
- Fix multiselection with shift not working inside a library group [Taiga #3532](https://tree.taiga.io/project/penpot/issue/3532)
|
||||||
|
- Fix drag and drop graphic assets in groups [Taiga #4002](https://tree.taiga.io/project/penpot/issue/4002)
|
||||||
|
|
||||||
### :arrow_up: Deps updates
|
### :arrow_up: Deps updates
|
||||||
### :heart: Community contributions by (Thank you!)
|
### :heart: Community contributions by (Thank you!)
|
||||||
|
@ -91,6 +97,8 @@
|
||||||
- Fix colors from unlinked libs in color selected widget [Taiga #3712](https://tree.taiga.io/project/penpot/issue/3712)
|
- Fix colors from unlinked libs in color selected widget [Taiga #3712](https://tree.taiga.io/project/penpot/issue/3712)
|
||||||
- Fix fill information not complete when paste plain text [Taiga #3680](https://tree.taiga.io/project/penpot/issue/3680)
|
- Fix fill information not complete when paste plain text [Taiga #3680](https://tree.taiga.io/project/penpot/issue/3680)
|
||||||
- Fix problem when resizing groups [Taiga #3702](https://tree.taiga.io/project/penpot/issue/3702)
|
- Fix problem when resizing groups [Taiga #3702](https://tree.taiga.io/project/penpot/issue/3702)
|
||||||
|
- Fix issues on typographies assets grouping [#2073](https://github.com/penpot/penpot/issues/2073)
|
||||||
|
- Fix text positioning inconsistencies between browsers
|
||||||
|
|
||||||
## 1.14.1-beta
|
## 1.14.1-beta
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,12 @@
|
||||||
:labels ["name"]
|
:labels ["name"]
|
||||||
:type :histogram}
|
:type :histogram}
|
||||||
|
|
||||||
|
:rpc-command-timing
|
||||||
|
{:name "rpc_command_timing"
|
||||||
|
:help "RPC command method call timming."
|
||||||
|
:labels ["name"]
|
||||||
|
:type :histogram}
|
||||||
|
|
||||||
:rpc-query-timing
|
:rpc-query-timing
|
||||||
{:name "rpc_query_timing"
|
{:name "rpc_query_timing"
|
||||||
:help "RPC query method call timing."
|
:help "RPC query method call timing."
|
||||||
|
|
|
@ -204,7 +204,6 @@
|
||||||
(defn- process-method
|
(defn- process-method
|
||||||
[cfg vfn]
|
[cfg vfn]
|
||||||
(let [mdata (meta vfn)]
|
(let [mdata (meta vfn)]
|
||||||
;; (prn mdata)
|
|
||||||
[(keyword (::sv/name mdata))
|
[(keyword (::sv/name mdata))
|
||||||
(wrap cfg vfn mdata)]))
|
(wrap cfg vfn mdata)]))
|
||||||
|
|
||||||
|
|
|
@ -728,11 +728,16 @@
|
||||||
[data]
|
[data]
|
||||||
(letfn [(process-map-form [form]
|
(letfn [(process-map-form [form]
|
||||||
(cond-> form
|
(cond-> form
|
||||||
;; Relink Image Shapes
|
;; Relink image shapes
|
||||||
(and (map? (:metadata form))
|
(and (map? (:metadata form))
|
||||||
(= :image (:type form)))
|
(= :image (:type form)))
|
||||||
(update-in [:metadata :id] lookup-index)
|
(update-in [:metadata :id] lookup-index)
|
||||||
|
|
||||||
|
;; Relink paths with fill image
|
||||||
|
(and (map? (:fill-image form))
|
||||||
|
(= :path (:type form)))
|
||||||
|
(update-in [:fill-image :id] lookup-index)
|
||||||
|
|
||||||
;; This covers old shapes and the new :fills.
|
;; This covers old shapes and the new :fills.
|
||||||
(uuid? (:fill-color-ref-file form))
|
(uuid? (:fill-color-ref-file form))
|
||||||
(update :fill-color-ref-file lookup-index)
|
(update :fill-color-ref-file lookup-index)
|
||||||
|
|
|
@ -496,16 +496,15 @@
|
||||||
;; --- COMMAND: Update comment thread position
|
;; --- COMMAND: Update comment thread position
|
||||||
|
|
||||||
(s/def ::update-comment-thread-position
|
(s/def ::update-comment-thread-position
|
||||||
(s/keys :req-un [::profile-id ::id ::position ::frame-id]))
|
(s/keys :req-un [::profile-id ::id ::position ::frame-id]
|
||||||
|
:opt-un [::share-id]))
|
||||||
|
|
||||||
(sv/defmethod ::update-comment-thread-position
|
(sv/defmethod ::update-comment-thread-position
|
||||||
{::doc/added "1.15"}
|
{::doc/added "1.15"}
|
||||||
[{:keys [pool] :as cfg} {:keys [profile-id id position frame-id] :as params}]
|
[{:keys [pool] :as cfg} {:keys [profile-id id position frame-id share-id] :as params}]
|
||||||
(db/with-atomic [conn pool]
|
(db/with-atomic [conn pool]
|
||||||
(let [thread (db/get-by-id conn :comment-thread id {:for-update true})]
|
(let [thread (db/get-by-id conn :comment-thread id {:for-update true})]
|
||||||
(when-not (= (:owner-id thread) profile-id)
|
(files/check-comment-permissions! conn profile-id (:file-id thread) share-id)
|
||||||
(ex/raise :type :validation
|
|
||||||
:code :not-allowed))
|
|
||||||
(db/update! conn :comment-thread
|
(db/update! conn :comment-thread
|
||||||
{:modified-at (dt/now)
|
{:modified-at (dt/now)
|
||||||
:position (db/pgpoint position)
|
:position (db/pgpoint position)
|
||||||
|
@ -516,16 +515,15 @@
|
||||||
;; --- COMMAND: Update comment frame
|
;; --- COMMAND: Update comment frame
|
||||||
|
|
||||||
(s/def ::update-comment-thread-frame
|
(s/def ::update-comment-thread-frame
|
||||||
(s/keys :req-un [::profile-id ::id ::frame-id]))
|
(s/keys :req-un [::profile-id ::id ::frame-id]
|
||||||
|
:opt-un [::share-id]))
|
||||||
|
|
||||||
(sv/defmethod ::update-comment-thread-frame
|
(sv/defmethod ::update-comment-thread-frame
|
||||||
{::doc/added "1.15"}
|
{::doc/added "1.15"}
|
||||||
[{:keys [pool] :as cfg} {:keys [profile-id id frame-id] :as params}]
|
[{:keys [pool] :as cfg} {:keys [profile-id id frame-id share-id] :as params}]
|
||||||
(db/with-atomic [conn pool]
|
(db/with-atomic [conn pool]
|
||||||
(let [thread (db/get-by-id conn :comment-thread id {:for-update true})]
|
(let [thread (db/get-by-id conn :comment-thread id {:for-update true})]
|
||||||
(when-not (= (:owner-id thread) profile-id)
|
(files/check-comment-permissions! conn profile-id (:file-id thread) share-id)
|
||||||
(ex/raise :type :validation
|
|
||||||
:code :not-allowed))
|
|
||||||
(db/update! conn :comment-thread
|
(db/update! conn :comment-thread
|
||||||
{:modified-at (dt/now)
|
{:modified-at (dt/now)
|
||||||
:frame-id frame-id}
|
:frame-id frame-id}
|
||||||
|
|
|
@ -46,14 +46,11 @@
|
||||||
(t/is (sto/storage-object? mobj1))
|
(t/is (sto/storage-object? mobj1))
|
||||||
(t/is (sto/storage-object? mobj2))
|
(t/is (sto/storage-object? mobj2))
|
||||||
(t/is (= 122785 (:size mobj1)))
|
(t/is (= 122785 (:size mobj1)))
|
||||||
|
|
||||||
;; This is because in ubuntu 21.04 generates different
|
;; This is because in ubuntu 21.04 generates different
|
||||||
;; thumbnail that in ubuntu 22.04. This hack should be removed
|
;; thumbnail that in ubuntu 22.04. This hack should be removed
|
||||||
;; when we all use the ubuntu 22.04 devenv image.
|
;; when we all use the ubuntu 22.04 devenv image.
|
||||||
(t/is (or
|
(t/is (or (= 3302 (:size mobj2))
|
||||||
(= 3302 (:size mobj2))
|
(= 3303 (:size mobj2))))))))
|
||||||
(= 3303 (:size mobj2))))))
|
|
||||||
))
|
|
||||||
|
|
||||||
(t/deftest media-object-upload
|
(t/deftest media-object-upload
|
||||||
(let [prof (th/create-profile* 1)
|
(let [prof (th/create-profile* 1)
|
||||||
|
|
|
@ -41,6 +41,5 @@
|
||||||
|
|
||||||
(defn is-in-focus?
|
(defn is-in-focus?
|
||||||
[objects focus id]
|
[objects focus id]
|
||||||
(d/seek
|
(d/seek (partial contains? focus)
|
||||||
#(contains? focus %)
|
(cons id (cph/get-parent-ids objects id))))
|
||||||
(cph/get-parents-seq objects id)))
|
|
||||||
|
|
|
@ -79,16 +79,6 @@
|
||||||
[objects id]
|
[objects id]
|
||||||
(-> objects (get id) :parent-id))
|
(-> objects (get id) :parent-id))
|
||||||
|
|
||||||
(defn get-parents-seq
|
|
||||||
[objects shape-id]
|
|
||||||
|
|
||||||
(cond
|
|
||||||
(nil? shape-id)
|
|
||||||
nil
|
|
||||||
|
|
||||||
:else
|
|
||||||
(lazy-seq (cons shape-id (get-parents-seq objects (get-in objects [shape-id :parent-id]))))))
|
|
||||||
|
|
||||||
(defn get-parent-ids
|
(defn get-parent-ids
|
||||||
"Returns a vector of parents of the specified shape."
|
"Returns a vector of parents of the specified shape."
|
||||||
[objects shape-id]
|
[objects shape-id]
|
||||||
|
@ -430,7 +420,7 @@
|
||||||
|
|
||||||
(defn is-child?
|
(defn is-child?
|
||||||
[objects parent-id candidate-child-id]
|
[objects parent-id candidate-child-id]
|
||||||
(let [parents (get-parents-seq objects candidate-child-id)]
|
(let [parents (get-parent-ids objects candidate-child-id)]
|
||||||
(some? (d/seek #(= % parent-id) parents))))
|
(some? (d/seek #(= % parent-id) parents))))
|
||||||
|
|
||||||
(defn reduce-objects
|
(defn reduce-objects
|
||||||
|
@ -470,10 +460,9 @@
|
||||||
|
|
||||||
(defn get-shape-id-root-frame
|
(defn get-shape-id-root-frame
|
||||||
[objects shape-id]
|
[objects shape-id]
|
||||||
(->> (get-parents-seq objects shape-id)
|
(->> (get-parent-ids objects shape-id)
|
||||||
|
(cons shape-id)
|
||||||
(map (d/getf objects))
|
(map (d/getf objects))
|
||||||
(d/seek #(and (= :frame (:type %))
|
(d/seek root-frame?)
|
||||||
(= uuid/zero (:frame-id %))))
|
|
||||||
|
|
||||||
:id))
|
:id))
|
||||||
|
|
||||||
|
|
|
@ -132,8 +132,8 @@
|
||||||
(defn get-base
|
(defn get-base
|
||||||
[objects id-a id-b]
|
[objects id-a id-b]
|
||||||
|
|
||||||
(let [parents-a (reverse (cph/get-parents-seq objects id-a))
|
(let [parents-a (reverse (cons id-a (cph/get-parent-ids objects id-a)))
|
||||||
parents-b (reverse (cph/get-parents-seq objects id-b))
|
parents-b (reverse (cons id-b (cph/get-parent-ids objects id-b)))
|
||||||
|
|
||||||
[base base-child-a base-child-b]
|
[base base-child-a base-child-b]
|
||||||
(loop [parents-a (rest parents-a)
|
(loop [parents-a (rest parents-a)
|
||||||
|
|
|
@ -3,7 +3,7 @@ LABEL maintainer="Andrey Antukh <niwi@niwi.nz>"
|
||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
ENV NODE_VERSION=v16.16.0 \
|
ENV NODE_VERSION=v16.17.0 \
|
||||||
CLOJURE_VERSION=1.11.1.1149 \
|
CLOJURE_VERSION=1.11.1.1149 \
|
||||||
CLJKONDO_VERSION=2022.06.22 \
|
CLJKONDO_VERSION=2022.06.22 \
|
||||||
BABASHKA_VERSION=0.8.156 \
|
BABASHKA_VERSION=0.8.156 \
|
||||||
|
|
|
@ -5,7 +5,7 @@ ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
ENV LANG=en_US.UTF-8 \
|
ENV LANG=en_US.UTF-8 \
|
||||||
LC_ALL=en_US.UTF-8 \
|
LC_ALL=en_US.UTF-8 \
|
||||||
NODE_VERSION=v16.15.1
|
NODE_VERSION=v16.17.0
|
||||||
|
|
||||||
RUN set -ex; \
|
RUN set -ex; \
|
||||||
mkdir -p /etc/resolvconf/resolv.conf.d; \
|
mkdir -p /etc/resolvconf/resolv.conf.d; \
|
||||||
|
|
|
@ -1,13 +1,2 @@
|
||||||
// Frontend configuration
|
// Frontend configuration
|
||||||
|
|
||||||
//var penpotPublicURI = "https://penpot.example.com";
|
|
||||||
//var penpotDemoWarning = <true|false>;
|
|
||||||
//var penpotAllowDemoUsers = <true|false>;
|
|
||||||
//var penpotGoogleClientID = "<google-client-id-here>";
|
|
||||||
//var penpotGitlabClientID = "<gitlab-client-id-here>";
|
|
||||||
//var penpotGithubClientID = "<github-client-id-here>";
|
|
||||||
//var penpotOIDCClientID = "<oidc-client-id-here>";
|
|
||||||
//var penpotLoginWithLDAP = <true|false>;
|
|
||||||
//var penpotRegistrationEnabled = <true|false>;
|
|
||||||
//var penpotAnalyticsEnabled = <true|false>;
|
|
||||||
//var penpotFlags = "";
|
//var penpotFlags = "";
|
||||||
|
|
|
@ -330,26 +330,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.code-row-lang {
|
.code-row-lang {
|
||||||
|
color: $color-gray-10;
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
font-size: $fs14;
|
||||||
margin: 0.5rem;
|
margin: 0.5rem;
|
||||||
|
|
||||||
.code-selection {
|
|
||||||
height: 100%;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0.5rem;
|
|
||||||
width: 4.5rem;
|
|
||||||
font-size: $fs12;
|
|
||||||
background: $color-gray-50;
|
|
||||||
color: $color-gray-10;
|
|
||||||
border-radius: 2px;
|
|
||||||
border: 1px solid $color-gray-30;
|
|
||||||
background-image: url("/images/icons/arrow-down-white.svg");
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: 90% 48%;
|
|
||||||
background-size: 8px;
|
|
||||||
}
|
|
||||||
.expand-button,
|
.expand-button,
|
||||||
.copy-button {
|
.copy-button {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
.share-modal {
|
.share-modal {
|
||||||
|
background: none;
|
||||||
display: block;
|
display: block;
|
||||||
top: 50px;
|
top: 50px;
|
||||||
left: calc(100vw - 500px);
|
left: calc(100vw - 500px);
|
||||||
|
@ -7,6 +8,7 @@
|
||||||
width: 480px;
|
width: 480px;
|
||||||
background-color: $color-white;
|
background-color: $color-white;
|
||||||
box-shadow: 0px 2px 8px 0px rgb(0 0 0 / 20%);
|
box-shadow: 0px 2px 8px 0px rgb(0 0 0 / 20%);
|
||||||
|
|
||||||
.modal-content {
|
.modal-content {
|
||||||
padding: 16px 32px;
|
padding: 16px 32px;
|
||||||
&:first-child {
|
&:first-child {
|
||||||
|
|
|
@ -30,7 +30,6 @@
|
||||||
grid-row: 1 / span 2;
|
grid-row: 1 / span 2;
|
||||||
grid-column: 1 / span 1;
|
grid-column: 1 / span 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-flow: wrap;
|
flex-flow: wrap;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
@ -72,8 +71,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
& .viewer-go-next {
|
& .viewer-go-next {
|
||||||
right: 0;
|
right: 8px;
|
||||||
padding-right: 29px;
|
width: 46px;
|
||||||
svg {
|
svg {
|
||||||
margin-left: 2px;
|
margin-left: 2px;
|
||||||
}
|
}
|
||||||
|
@ -97,12 +96,13 @@
|
||||||
|
|
||||||
& .viewer-bottom {
|
& .viewer-bottom {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 8px;
|
||||||
height: 50px;
|
height: 30px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
z-index: 2;
|
||||||
|
|
||||||
&.left-bar {
|
&.left-bar {
|
||||||
width: calc(100% - 512px);
|
width: calc(100% - 512px);
|
||||||
|
@ -144,6 +144,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
& .viewer-wrapper {
|
& .viewer-wrapper {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,6 +182,7 @@
|
||||||
top: 50px;
|
top: 50px;
|
||||||
width: 256px;
|
width: 256px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
z-index: 10;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -342,6 +342,13 @@
|
||||||
(some? list)
|
(some? list)
|
||||||
(assoc :list list)))))))
|
(assoc :list list)))))))
|
||||||
|
|
||||||
|
(defn update-options
|
||||||
|
[params]
|
||||||
|
(ptk/reify ::update-options
|
||||||
|
ptk/UpdateEvent
|
||||||
|
(update [_ state]
|
||||||
|
(update state :comments-local merge params))))
|
||||||
|
|
||||||
(s/def ::create-draft-params
|
(s/def ::create-draft-params
|
||||||
(s/keys :req-un [::page-id ::file-id ::position]))
|
(s/keys :req-un [::page-id ::file-id ::position]))
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
(ns app.main.data.viewer
|
(ns app.main.data.viewer
|
||||||
(:require
|
(:require
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
|
[app.common.data.macros :as dm]
|
||||||
[app.common.geom.point :as gpt]
|
[app.common.geom.point :as gpt]
|
||||||
[app.common.pages.helpers :as cph]
|
[app.common.pages.helpers :as cph]
|
||||||
[app.common.spec :as us]
|
[app.common.spec :as us]
|
||||||
|
@ -22,6 +23,9 @@
|
||||||
[cljs.spec.alpha :as s]
|
[cljs.spec.alpha :as s]
|
||||||
[potok.core :as ptk]))
|
[potok.core :as ptk]))
|
||||||
|
|
||||||
|
(s/def ::nilable-boolean (s/nilable ::us/boolean))
|
||||||
|
(s/def ::nilable-animation (s/nilable ::ctsi/animation))
|
||||||
|
|
||||||
;; --- Local State Initialization
|
;; --- Local State Initialization
|
||||||
|
|
||||||
(def ^:private
|
(def ^:private
|
||||||
|
@ -34,7 +38,6 @@
|
||||||
:comments-show :unresolved
|
:comments-show :unresolved
|
||||||
:selected #{}
|
:selected #{}
|
||||||
:collapsed #{}
|
:collapsed #{}
|
||||||
:overlays []
|
|
||||||
:hover nil
|
:hover nil
|
||||||
:share-id ""
|
:share-id ""
|
||||||
:file-comments-users []})
|
:file-comments-users []})
|
||||||
|
@ -351,7 +354,8 @@
|
||||||
|
|
||||||
(declare flash-done)
|
(declare flash-done)
|
||||||
|
|
||||||
(def flash-interactions
|
(defn flash-interactions
|
||||||
|
[]
|
||||||
(ptk/reify ::flash-interactions
|
(ptk/reify ::flash-interactions
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
|
@ -389,7 +393,7 @@
|
||||||
(ptk/reify ::complete-animation
|
(ptk/reify ::complete-animation
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(d/dissoc-in state [:viewer-local :current-animation]))))
|
(dissoc state :viewer-animation))))
|
||||||
|
|
||||||
;; --- Navigation inside page
|
;; --- Navigation inside page
|
||||||
|
|
||||||
|
@ -398,7 +402,7 @@
|
||||||
(ptk/reify ::go-to-frame-by-index
|
(ptk/reify ::go-to-frame-by-index
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(assoc-in state [:viewer-local :overlays] []))
|
(assoc state :viewer-overlays []))
|
||||||
|
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state _]
|
(watch [_ state _]
|
||||||
|
@ -413,8 +417,9 @@
|
||||||
(go-to-frame frame-id nil))
|
(go-to-frame frame-id nil))
|
||||||
|
|
||||||
([frame-id animation]
|
([frame-id animation]
|
||||||
(us/verify ::us/uuid frame-id)
|
(us/assert! ::us/uuid frame-id)
|
||||||
(us/verify (s/nilable ::ctsi/animation) animation)
|
(us/assert! ::nilable-animation animation)
|
||||||
|
|
||||||
(ptk/reify ::go-to-frame
|
(ptk/reify ::go-to-frame
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
|
@ -426,10 +431,10 @@
|
||||||
frame (get frames index)]
|
frame (get frames index)]
|
||||||
(cond-> state
|
(cond-> state
|
||||||
:always
|
:always
|
||||||
(assoc-in [:viewer-local :overlays] [])
|
(assoc :viewer-overlays [])
|
||||||
|
|
||||||
(some? animation)
|
(some? animation)
|
||||||
(assoc-in [:viewer-local :current-animation]
|
(assoc :viewer-animation
|
||||||
{:kind :go-to-frame
|
{:kind :go-to-frame
|
||||||
:orig-frame-id (:id frame)
|
:orig-frame-id (:id frame)
|
||||||
:animation animation}))))
|
:animation animation}))))
|
||||||
|
@ -462,7 +467,7 @@
|
||||||
(ptk/reify ::go-to-section
|
(ptk/reify ::go-to-section
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(assoc-in state [:viewer-local :overlays] []))
|
(assoc state :viewer-overlays []))
|
||||||
|
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state _]
|
(watch [_ state _]
|
||||||
|
@ -473,50 +478,53 @@
|
||||||
|
|
||||||
;; --- Overlays
|
;; --- Overlays
|
||||||
|
|
||||||
(defn- do-open-overlay
|
(defn- open-overlay*
|
||||||
[state frame position close-click-outside background-overlay animation]
|
[state frame position close-click-outside background-overlay animation]
|
||||||
(cond-> state
|
(cond-> state
|
||||||
:always
|
:always
|
||||||
(update-in [:viewer-local :overlays] conj
|
(update :viewer-overlays conj
|
||||||
{:frame frame
|
{:frame frame
|
||||||
|
:id (:id frame)
|
||||||
:position position
|
:position position
|
||||||
:close-click-outside close-click-outside
|
:close-click-outside close-click-outside
|
||||||
:background-overlay background-overlay})
|
:background-overlay background-overlay})
|
||||||
|
|
||||||
(some? animation)
|
(some? animation)
|
||||||
(assoc-in [:viewer-local :current-animation]
|
(assoc :viewer-animation
|
||||||
{:kind :open-overlay
|
{:kind :open-overlay
|
||||||
:overlay-id (:id frame)
|
:overlay-id (:id frame)
|
||||||
:animation animation})))
|
:animation animation})))
|
||||||
|
|
||||||
(defn- do-close-overlay
|
(defn- close-overlay*
|
||||||
[state frame-id animation]
|
[state frame-id animation]
|
||||||
(if (nil? animation)
|
(if (nil? animation)
|
||||||
(update-in state [:viewer-local :overlays]
|
(update state :viewer-overlays
|
||||||
(fn [overlays]
|
(fn [overlays]
|
||||||
(d/removev #(= (:id (:frame %)) frame-id) overlays)))
|
(d/removev #(= (:id (:frame %)) frame-id) overlays)))
|
||||||
(assoc-in state [:viewer-local :current-animation]
|
(assoc state :viewer-animation
|
||||||
{:kind :close-overlay
|
{:kind :close-overlay
|
||||||
:overlay-id frame-id
|
:overlay-id frame-id
|
||||||
:animation animation})))
|
:animation animation})))
|
||||||
|
|
||||||
(defn open-overlay
|
(defn open-overlay
|
||||||
[frame-id position close-click-outside background-overlay animation]
|
[frame-id position close-click-outside background-overlay animation]
|
||||||
(us/verify ::us/uuid frame-id)
|
(us/assert! ::us/uuid frame-id)
|
||||||
(us/verify ::gpt/point position)
|
(us/assert! ::gpt/point position)
|
||||||
(us/verify (s/nilable ::us/boolean) close-click-outside)
|
(us/assert! ::nilable-boolean close-click-outside)
|
||||||
(us/verify (s/nilable ::us/boolean) background-overlay)
|
(us/assert! ::nilable-boolean background-overlay)
|
||||||
(us/verify (s/nilable ::ctsi/animation) animation)
|
(us/assert! ::nilable-animation animation)
|
||||||
|
|
||||||
(ptk/reify ::open-overlay
|
(ptk/reify ::open-overlay
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(let [route (:route state)
|
(let [route (:route state)
|
||||||
qparams (:query-params route)
|
qparams (:query-params route)
|
||||||
page-id (:page-id qparams)
|
page-id (:page-id qparams)
|
||||||
frames (get-in state [:viewer :pages page-id :all-frames])
|
frames (dm/get-in state [:viewer :pages page-id :all-frames])
|
||||||
frame (d/seek #(= (:id %) frame-id) frames)
|
frame (d/seek #(= (:id %) frame-id) frames)
|
||||||
overlays (get-in state [:viewer-local :overlays])]
|
overlays (:viewer-overlays state)]
|
||||||
(if-not (some #(= (:frame %) frame) overlays)
|
(if-not (some #(= (:frame %) frame) overlays)
|
||||||
(do-open-overlay state
|
(open-overlay* state
|
||||||
frame
|
frame
|
||||||
position
|
position
|
||||||
close-click-outside
|
close-click-outside
|
||||||
|
@ -524,13 +532,15 @@
|
||||||
animation)
|
animation)
|
||||||
state)))))
|
state)))))
|
||||||
|
|
||||||
|
|
||||||
(defn toggle-overlay
|
(defn toggle-overlay
|
||||||
[frame-id position close-click-outside background-overlay animation]
|
[frame-id position close-click-outside background-overlay animation]
|
||||||
(us/verify ::us/uuid frame-id)
|
(us/assert! ::us/uuid frame-id)
|
||||||
(us/verify ::gpt/point position)
|
(us/assert! ::gpt/point position)
|
||||||
(us/verify (s/nilable ::us/boolean) close-click-outside)
|
(us/assert! ::nilable-boolean close-click-outside)
|
||||||
(us/verify (s/nilable ::us/boolean) background-overlay)
|
(us/assert! ::nilable-boolean background-overlay)
|
||||||
(us/verify (s/nilable ::ctsi/animation) animation)
|
(us/assert! ::nilable-animation animation)
|
||||||
|
|
||||||
(ptk/reify ::toggle-overlay
|
(ptk/reify ::toggle-overlay
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
|
@ -539,27 +549,28 @@
|
||||||
page-id (:page-id qparams)
|
page-id (:page-id qparams)
|
||||||
frames (get-in state [:viewer :pages page-id :all-frames])
|
frames (get-in state [:viewer :pages page-id :all-frames])
|
||||||
frame (d/seek #(= (:id %) frame-id) frames)
|
frame (d/seek #(= (:id %) frame-id) frames)
|
||||||
overlays (get-in state [:viewer-local :overlays])]
|
overlays (:viewer-overlays state)]
|
||||||
(if-not (some #(= (:frame %) frame) overlays)
|
(if-not (some #(= (:frame %) frame) overlays)
|
||||||
(do-open-overlay state
|
(open-overlay* state
|
||||||
frame
|
frame
|
||||||
position
|
position
|
||||||
close-click-outside
|
close-click-outside
|
||||||
background-overlay
|
background-overlay
|
||||||
animation)
|
animation)
|
||||||
(do-close-overlay state
|
(close-overlay* state
|
||||||
(:id frame)
|
(:id frame)
|
||||||
(ctsi/invert-direction animation)))))))
|
(ctsi/invert-direction animation)))))))
|
||||||
|
|
||||||
(defn close-overlay
|
(defn close-overlay
|
||||||
([frame-id] (close-overlay frame-id nil))
|
([frame-id] (close-overlay frame-id nil))
|
||||||
([frame-id animation]
|
([frame-id animation]
|
||||||
(us/verify ::us/uuid frame-id)
|
(us/assert! ::us/uuid frame-id)
|
||||||
(us/verify (s/nilable ::ctsi/animation) animation)
|
(us/assert! ::nilable-animation animation)
|
||||||
|
|
||||||
(ptk/reify ::close-overlay
|
(ptk/reify ::close-overlay
|
||||||
ptk/UpdateEvent
|
ptk/UpdateEvent
|
||||||
(update [_ state]
|
(update [_ state]
|
||||||
(do-close-overlay state
|
(close-overlay* state
|
||||||
frame-id
|
frame-id
|
||||||
animation)))))
|
animation)))))
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
[app.common.types.shape-tree :as ctst]
|
[app.common.types.shape-tree :as ctst]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
[app.config :as cfg]
|
[app.config :as cfg]
|
||||||
|
[app.main.data.comments :as dcm]
|
||||||
[app.main.data.events :as ev]
|
[app.main.data.events :as ev]
|
||||||
[app.main.data.messages :as msg]
|
[app.main.data.messages :as msg]
|
||||||
[app.main.data.users :as du]
|
[app.main.data.users :as du]
|
||||||
|
@ -115,7 +116,8 @@
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ _ stream]
|
(watch [_ _ stream]
|
||||||
(rx/merge
|
(rx/merge
|
||||||
(rx/of (dwp/fetch-bundle project-id file-id))
|
(rx/of (dwp/fetch-bundle project-id file-id)
|
||||||
|
(dcm/retrieve-comment-threads file-id))
|
||||||
|
|
||||||
;; Initialize notifications (websocket connection) and the file persistence
|
;; Initialize notifications (websocket connection) and the file persistence
|
||||||
(->> stream
|
(->> stream
|
||||||
|
|
|
@ -239,6 +239,8 @@
|
||||||
(defn- do-update-tipography
|
(defn- do-update-tipography
|
||||||
[it state typography file-id]
|
[it state typography file-id]
|
||||||
(let [data (get state :workspace-data)
|
(let [data (get state :workspace-data)
|
||||||
|
[path name] (cph/parse-path-name (:name typography))
|
||||||
|
typography (assoc typography :path path :name name)
|
||||||
changes (-> (pcb/empty-changes it)
|
changes (-> (pcb/empty-changes it)
|
||||||
(pcb/with-library-data data)
|
(pcb/with-library-data data)
|
||||||
(pcb/update-typography typography))]
|
(pcb/update-typography typography))]
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
[app.common.pages.helpers :as cph]
|
[app.common.pages.helpers :as cph]
|
||||||
[app.common.spec :as us]
|
[app.common.spec :as us]
|
||||||
[app.common.types.shape-tree :as ctt]
|
[app.common.types.shape-tree :as ctt]
|
||||||
|
[app.common.uuid :as uuid]
|
||||||
[app.main.data.workspace.changes :as dch]
|
[app.main.data.workspace.changes :as dch]
|
||||||
[app.main.data.workspace.collapse :as dwc]
|
[app.main.data.workspace.collapse :as dwc]
|
||||||
[app.main.data.workspace.comments :as-alias dwcm]
|
[app.main.data.workspace.comments :as-alias dwcm]
|
||||||
|
@ -762,7 +763,17 @@
|
||||||
changes
|
changes
|
||||||
(-> (pcb/empty-changes it page-id)
|
(-> (pcb/empty-changes it page-id)
|
||||||
(pcb/with-objects objects)
|
(pcb/with-objects objects)
|
||||||
(pcb/update-shapes moving-frames (fn [shape] (assoc shape :hide-in-viewer true)))
|
(pcb/update-shapes moving-frames
|
||||||
|
(fn [shape]
|
||||||
|
;; Hide in viwer must be enabled just when a board is moved
|
||||||
|
;; inside another artboard an nested to it, we have to avoid
|
||||||
|
;; situations like: - Moving inside the same frame - Moving
|
||||||
|
;; outside the frame
|
||||||
|
(cond-> shape
|
||||||
|
(and (not= frame-id (:id shape))
|
||||||
|
(not= frame-id (:frame-id shape))
|
||||||
|
(not= frame-id uuid/zero))
|
||||||
|
(assoc :hide-in-viewer true))))
|
||||||
(pcb/change-parent frame-id moving-shapes))]
|
(pcb/change-parent frame-id moving-shapes))]
|
||||||
|
|
||||||
(when-not (empty? changes)
|
(when-not (empty? changes)
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
(mf/defc on-main-error
|
(mf/defc on-main-error
|
||||||
[{:keys [error] :as props}]
|
[{:keys [error] :as props}]
|
||||||
(mf/with-effect
|
(mf/with-effect
|
||||||
|
(js/console.log error)
|
||||||
(st/emit! (rt/assign-exception error)))
|
(st/emit! (rt/assign-exception error)))
|
||||||
[:span "Internal application error"])
|
[:span "Internal application error"])
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
(ns app.main.ui.comments
|
(ns app.main.ui.comments
|
||||||
(:require
|
(:require
|
||||||
|
[app.common.geom.point :as gpt]
|
||||||
[app.config :as cfg]
|
[app.config :as cfg]
|
||||||
[app.main.data.comments :as dcm]
|
[app.main.data.comments :as dcm]
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
|
@ -110,8 +111,10 @@
|
||||||
[:input.btn-secondary {:type "button" :value "Cancel" :on-click on-cancel}]])]))
|
[:input.btn-secondary {:type "button" :value "Cancel" :on-click on-cancel}]])]))
|
||||||
|
|
||||||
(mf/defc draft-thread
|
(mf/defc draft-thread
|
||||||
[{:keys [draft zoom on-cancel on-submit] :as props}]
|
[{:keys [draft zoom on-cancel on-submit position-modifier]}]
|
||||||
(let [position (:position draft)
|
(let [position (cond-> (:position draft)
|
||||||
|
(some? position-modifier)
|
||||||
|
(gpt/transform position-modifier))
|
||||||
content (:content draft)
|
content (:content draft)
|
||||||
pos-x (* (:x position) zoom)
|
pos-x (* (:x position) zoom)
|
||||||
pos-y (* (:y position) zoom)
|
pos-y (* (:y position) zoom)
|
||||||
|
@ -281,9 +284,12 @@
|
||||||
(l/derived (l/in [:comments id]) st/state))
|
(l/derived (l/in [:comments id]) st/state))
|
||||||
|
|
||||||
(mf/defc thread-comments
|
(mf/defc thread-comments
|
||||||
[{:keys [thread zoom users origin]}]
|
{::mf/wrap [mf/memo]}
|
||||||
|
[{:keys [thread zoom users origin position-modifier]}]
|
||||||
(let [ref (mf/use-ref)
|
(let [ref (mf/use-ref)
|
||||||
pos (:position thread)
|
pos (cond-> (:position thread)
|
||||||
|
(some? position-modifier)
|
||||||
|
(gpt/transform position-modifier))
|
||||||
|
|
||||||
pos-x (+ (* (:x pos) zoom) 14)
|
pos-x (+ (* (:x pos) zoom) 14)
|
||||||
pos-y (- (* (:y pos) zoom) 14)
|
pos-y (- (* (:y pos) zoom) 14)
|
||||||
|
@ -384,8 +390,11 @@
|
||||||
|
|
||||||
(mf/defc thread-bubble
|
(mf/defc thread-bubble
|
||||||
{::mf/wrap [mf/memo]}
|
{::mf/wrap [mf/memo]}
|
||||||
[{:keys [thread zoom open? on-click origin]}]
|
[{:keys [thread zoom open? on-click origin position-modifier]}]
|
||||||
(let [pos (:position thread)
|
(let [pos (cond-> (:position thread)
|
||||||
|
(some? position-modifier)
|
||||||
|
(gpt/transform position-modifier))
|
||||||
|
|
||||||
drag? (mf/use-ref nil)
|
drag? (mf/use-ref nil)
|
||||||
was-open? (mf/use-ref nil)
|
was-open? (mf/use-ref nil)
|
||||||
|
|
||||||
|
@ -398,7 +407,8 @@
|
||||||
pos-x (* (or (:new-position-x @state) (:x pos)) zoom)
|
pos-x (* (or (:new-position-x @state) (:x pos)) zoom)
|
||||||
pos-y (* (or (:new-position-y @state) (:y pos)) zoom)
|
pos-y (* (or (:new-position-y @state) (:y pos)) zoom)
|
||||||
|
|
||||||
on-pointer-down* (mf/use-callback
|
on-pointer-down*
|
||||||
|
(mf/use-callback
|
||||||
(mf/deps origin was-open? open? drag? on-pointer-down)
|
(mf/deps origin was-open? open? drag? on-pointer-down)
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(when (not= origin :viewer)
|
(when (not= origin :viewer)
|
||||||
|
@ -408,7 +418,8 @@
|
||||||
(dom/stop-propagation event)
|
(dom/stop-propagation event)
|
||||||
(on-pointer-down event))))
|
(on-pointer-down event))))
|
||||||
|
|
||||||
on-pointer-up* (mf/use-callback
|
on-pointer-up*
|
||||||
|
(mf/use-callback
|
||||||
(mf/deps origin thread was-open? drag? on-pointer-up)
|
(mf/deps origin thread was-open? drag? on-pointer-up)
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(when (not= origin :viewer)
|
(when (not= origin :viewer)
|
||||||
|
@ -419,7 +430,8 @@
|
||||||
(and (not (mf/ref-val was-open?)) (not (mf/ref-val drag?))))
|
(and (not (mf/ref-val was-open?)) (not (mf/ref-val drag?))))
|
||||||
(st/emit! (dcm/open-thread thread))))))
|
(st/emit! (dcm/open-thread thread))))))
|
||||||
|
|
||||||
on-mouse-move* (mf/use-callback
|
on-mouse-move*
|
||||||
|
(mf/use-callback
|
||||||
(mf/deps origin drag? on-mouse-move)
|
(mf/deps origin drag? on-mouse-move)
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(when (not= origin :viewer)
|
(when (not= origin :viewer)
|
||||||
|
@ -427,7 +439,8 @@
|
||||||
(dom/stop-propagation event)
|
(dom/stop-propagation event)
|
||||||
(on-mouse-move event))))
|
(on-mouse-move event))))
|
||||||
|
|
||||||
on-click* (mf/use-callback
|
on-click*
|
||||||
|
(mf/use-callback
|
||||||
(mf/deps origin thread on-click)
|
(mf/deps origin thread on-click)
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(dom/stop-propagation event)
|
(dom/stop-propagation event)
|
||||||
|
@ -448,7 +461,7 @@
|
||||||
[:span (:seqn thread)]]))
|
[:span (:seqn thread)]]))
|
||||||
|
|
||||||
(mf/defc comment-thread
|
(mf/defc comment-thread
|
||||||
[{:keys [item users on-click] :as props}]
|
[{:keys [item users on-click]}]
|
||||||
(let [owner (get users (:owner-id item))
|
(let [owner (get users (:owner-id item))
|
||||||
on-click*
|
on-click*
|
||||||
(mf/use-callback
|
(mf/use-callback
|
||||||
|
|
|
@ -8,12 +8,7 @@
|
||||||
(:require
|
(:require
|
||||||
[rumext.alpha :as mf]))
|
[rumext.alpha :as mf]))
|
||||||
|
|
||||||
(def render-ctx (mf/create-context nil))
|
(def render-id (mf/create-context nil))
|
||||||
(def def-ctx (mf/create-context false))
|
|
||||||
|
|
||||||
;; This content is used to replace complex colors to simple ones
|
|
||||||
;; for text shapes in the export process
|
|
||||||
(def text-plain-colors-ctx (mf/create-context false))
|
|
||||||
|
|
||||||
(def current-route (mf/create-context nil))
|
(def current-route (mf/create-context nil))
|
||||||
(def current-profile (mf/create-context nil))
|
(def current-profile (mf/create-context nil))
|
||||||
|
@ -21,8 +16,12 @@
|
||||||
(def current-project-id (mf/create-context nil))
|
(def current-project-id (mf/create-context nil))
|
||||||
(def current-page-id (mf/create-context nil))
|
(def current-page-id (mf/create-context nil))
|
||||||
(def current-file-id (mf/create-context nil))
|
(def current-file-id (mf/create-context nil))
|
||||||
(def libraries (mf/create-context nil))
|
|
||||||
(def scroll-ctx (mf/create-context nil))
|
(def active-frames (mf/create-context nil))
|
||||||
(def active-frames-ctx (mf/create-context nil))
|
|
||||||
(def render-thumbnails (mf/create-context nil))
|
(def render-thumbnails (mf/create-context nil))
|
||||||
|
|
||||||
|
(def libraries (mf/create-context nil))
|
||||||
(def components-v2 (mf/create-context nil))
|
(def components-v2 (mf/create-context nil))
|
||||||
|
|
||||||
|
(def current-scroll (mf/create-context nil))
|
||||||
|
(def current-zoom (mf/create-context nil))
|
||||||
|
|
|
@ -159,7 +159,7 @@
|
||||||
|
|
||||||
(defn add-style-attrs
|
(defn add-style-attrs
|
||||||
([props shape]
|
([props shape]
|
||||||
(let [render-id (mf/use-ctx muc/render-ctx)]
|
(let [render-id (mf/use-ctx muc/render-id)]
|
||||||
(add-style-attrs props shape render-id)))
|
(add-style-attrs props shape render-id)))
|
||||||
|
|
||||||
([props shape render-id]
|
([props shape render-id]
|
||||||
|
|
|
@ -211,7 +211,7 @@
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
[props]
|
[props]
|
||||||
|
|
||||||
(let [render-id (mf/use-ctx muc/render-ctx)
|
(let [render-id (mf/use-ctx muc/render-id)
|
||||||
child (obj/get props "children")
|
child (obj/get props "children")
|
||||||
base-props (obj/get child "props")
|
base-props (obj/get child "props")
|
||||||
elem-name (obj/get child "type")
|
elem-name (obj/get child "type")
|
||||||
|
@ -253,7 +253,7 @@
|
||||||
(mf/defc inner-stroke
|
(mf/defc inner-stroke
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
[props]
|
[props]
|
||||||
(let [render-id (mf/use-ctx muc/render-ctx)
|
(let [render-id (mf/use-ctx muc/render-id)
|
||||||
child (obj/get props "children")
|
child (obj/get props "children")
|
||||||
base-props (obj/get child "props")
|
base-props (obj/get child "props")
|
||||||
elem-name (obj/get child "type")
|
elem-name (obj/get child "type")
|
||||||
|
@ -292,7 +292,7 @@
|
||||||
|
|
||||||
(let [child (obj/get props "children")
|
(let [child (obj/get props "children")
|
||||||
shape (obj/get props "shape")
|
shape (obj/get props "shape")
|
||||||
render-id (mf/use-ctx muc/render-ctx)
|
render-id (mf/use-ctx muc/render-id)
|
||||||
index (obj/get props "index")
|
index (obj/get props "index")
|
||||||
stroke-width (:stroke-width shape 0)
|
stroke-width (:stroke-width shape 0)
|
||||||
stroke-style (:stroke-style shape :none)
|
stroke-style (:stroke-style shape :none)
|
||||||
|
@ -417,7 +417,7 @@
|
||||||
shape (obj/get props "shape")
|
shape (obj/get props "shape")
|
||||||
elem-name (obj/get child "type")
|
elem-name (obj/get child "type")
|
||||||
position (or (obj/get props "position") 0)
|
position (or (obj/get props "position") 0)
|
||||||
render-id (or (obj/get props "render-id") (mf/use-ctx muc/render-ctx))]
|
render-id (or (obj/get props "render-id") (mf/use-ctx muc/render-id))]
|
||||||
[:g {:id (dm/fmt "fills-%" (:id shape))}
|
[:g {:id (dm/fmt "fills-%" (:id shape))}
|
||||||
[:> elem-name (build-fill-props shape child position render-id)]]))
|
[:> elem-name (build-fill-props shape child position render-id)]]))
|
||||||
|
|
||||||
|
@ -427,7 +427,7 @@
|
||||||
(let [child (obj/get props "children")
|
(let [child (obj/get props "children")
|
||||||
shape (obj/get props "shape")
|
shape (obj/get props "shape")
|
||||||
elem-name (obj/get child "type")
|
elem-name (obj/get child "type")
|
||||||
render-id (or (obj/get props "render-id") (mf/use-ctx muc/render-ctx))
|
render-id (or (obj/get props "render-id") (mf/use-ctx muc/render-id))
|
||||||
stroke-id (dm/fmt "strokes-%" (:id shape))
|
stroke-id (dm/fmt "strokes-%" (:id shape))
|
||||||
stroke-props (-> (obj/create)
|
stroke-props (-> (obj/create)
|
||||||
(obj/set! "id" stroke-id)
|
(obj/set! "id" stroke-id)
|
||||||
|
|
|
@ -286,7 +286,7 @@
|
||||||
(for [[index fill] (d/enumerate fills)]
|
(for [[index fill] (d/enumerate fills)]
|
||||||
[:> "penpot:fill"
|
[:> "penpot:fill"
|
||||||
#js {:penpot:fill-color (if (some? (:fill-color-gradient fill))
|
#js {:penpot:fill-color (if (some? (:fill-color-gradient fill))
|
||||||
(str/format "url(#%s)" (str "fill-color-gradient_" (mf/use-ctx muc/render-ctx) "_" index))
|
(str/format "url(#%s)" (str "fill-color-gradient_" (mf/use-ctx muc/render-id) "_" index))
|
||||||
(d/name (:fill-color fill)))
|
(d/name (:fill-color fill)))
|
||||||
:penpot:fill-color-ref-file (d/name (:fill-color-ref-file fill))
|
:penpot:fill-color-ref-file (d/name (:fill-color-ref-file fill))
|
||||||
:penpot:fill-color-ref-id (d/name (:fill-color-ref-id fill))
|
:penpot:fill-color-ref-id (d/name (:fill-color-ref-id fill))
|
||||||
|
@ -299,7 +299,7 @@
|
||||||
(for [[index stroke] (d/enumerate strokes)]
|
(for [[index stroke] (d/enumerate strokes)]
|
||||||
[:> "penpot:stroke"
|
[:> "penpot:stroke"
|
||||||
#js {:penpot:stroke-color (if (some? (:stroke-color-gradient stroke))
|
#js {:penpot:stroke-color (if (some? (:stroke-color-gradient stroke))
|
||||||
(str/format "url(#%s)" (str "stroke-color-gradient_" (mf/use-ctx muc/render-ctx) "_" index))
|
(str/format "url(#%s)" (str "stroke-color-gradient_" (mf/use-ctx muc/render-id) "_" index))
|
||||||
(d/name (:stroke-color stroke)))
|
(d/name (:stroke-color stroke)))
|
||||||
:penpot:stroke-color-ref-file (d/name (:stroke-color-ref-file stroke))
|
:penpot:stroke-color-ref-file (d/name (:stroke-color-ref-file stroke))
|
||||||
:penpot:stroke-color-ref-id (d/name (:stroke-color-ref-id stroke))
|
:penpot:stroke-color-ref-id (d/name (:stroke-color-ref-id stroke))
|
||||||
|
|
|
@ -62,7 +62,7 @@
|
||||||
:height height
|
:height height
|
||||||
:className "frame-background"}))
|
:className "frame-background"}))
|
||||||
path? (some? (.-d props))
|
path? (some? (.-d props))
|
||||||
render-id (mf/use-ctx muc/render-ctx)]
|
render-id (mf/use-ctx muc/render-id)]
|
||||||
|
|
||||||
[:*
|
[:*
|
||||||
[:g {:clip-path (when (not show-content) (frame-clip-url shape render-id))}
|
[:g {:clip-path (when (not show-content) (frame-clip-url shape render-id))}
|
||||||
|
|
|
@ -104,7 +104,7 @@
|
||||||
(let [attr (obj/get props "attr")
|
(let [attr (obj/get props "attr")
|
||||||
shape (obj/get props "shape")
|
shape (obj/get props "shape")
|
||||||
id (obj/get props "id")
|
id (obj/get props "id")
|
||||||
id' (mf/use-ctx muc/render-ctx)
|
id' (mf/use-ctx muc/render-id)
|
||||||
id (or id (dm/str (name attr) "_" id'))
|
id (or id (dm/str (name attr) "_" id'))
|
||||||
gradient (get shape attr)
|
gradient (get shape attr)
|
||||||
gradient-props #js {:id id
|
gradient-props #js {:id id
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
(let [shape (unchecked-get props "shape")
|
(let [shape (unchecked-get props "shape")
|
||||||
childs (unchecked-get props "childs")
|
childs (unchecked-get props "childs")
|
||||||
objects (unchecked-get props "objects")
|
objects (unchecked-get props "objects")
|
||||||
render-id (mf/use-ctx muc/render-ctx)
|
render-id (mf/use-ctx muc/render-id)
|
||||||
masked-group? (:masked-group? shape)
|
masked-group? (:masked-group? shape)
|
||||||
|
|
||||||
[mask childs] (if masked-group?
|
[mask childs] (if masked-group?
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false}
|
||||||
[props]
|
[props]
|
||||||
(let [mask (unchecked-get props "mask")
|
(let [mask (unchecked-get props "mask")
|
||||||
render-id (mf/use-ctx muc/render-ctx)
|
render-id (mf/use-ctx muc/render-id)
|
||||||
svg-text? (and (= :text (:type mask)) (some? (:position-data mask)))
|
svg-text? (and (= :text (:type mask)) (some? (:position-data mask)))
|
||||||
|
|
||||||
;; This factory is generic, it's used for viewer, workspace and handoff.
|
;; This factory is generic, it's used for viewer, workspace and handoff.
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.common.pages.helpers :as cph]
|
[app.common.pages.helpers :as cph]
|
||||||
[app.common.uuid :as uuid]
|
|
||||||
[app.main.ui.context :as muc]
|
[app.main.ui.context :as muc]
|
||||||
|
[app.main.ui.hooks :as h]
|
||||||
[app.main.ui.shapes.attrs :as attrs]
|
[app.main.ui.shapes.attrs :as attrs]
|
||||||
[app.main.ui.shapes.export :as ed]
|
[app.main.ui.shapes.export :as ed]
|
||||||
[app.main.ui.shapes.fills :as fills]
|
[app.main.ui.shapes.fills :as fills]
|
||||||
|
@ -49,14 +49,15 @@
|
||||||
{::mf/forward-ref true
|
{::mf/forward-ref true
|
||||||
::mf/wrap-props false}
|
::mf/wrap-props false}
|
||||||
[props ref]
|
[props ref]
|
||||||
(let [shape (obj/get props "shape")
|
|
||||||
children (obj/get props "children")
|
(let [shape (unchecked-get props "shape")
|
||||||
pointer-events (obj/get props "pointer-events")
|
children (unchecked-get props "children")
|
||||||
disable-shadows? (obj/get props "disable-shadows?")
|
pointer-events (unchecked-get props "pointer-events")
|
||||||
|
disable-shadows? (unchecked-get props "disable-shadows?")
|
||||||
|
|
||||||
type (:type shape)
|
type (:type shape)
|
||||||
render-id (mf/use-memo #(str (uuid/next)))
|
render-id (h/use-id)
|
||||||
filter-id (str "filter_" render-id)
|
filter-id (dm/str "filter_" render-id)
|
||||||
styles (-> (obj/create)
|
styles (-> (obj/create)
|
||||||
(obj/set! "pointerEvents" pointer-events)
|
(obj/set! "pointerEvents" pointer-events)
|
||||||
(cond-> (and (:blend-mode shape) (not= (:blend-mode shape) :normal))
|
(cond-> (and (:blend-mode shape) (not= (:blend-mode shape) :normal))
|
||||||
|
@ -91,7 +92,7 @@
|
||||||
svg-group?
|
svg-group?
|
||||||
(propagate-wrapper-styles wrapper-props))]
|
(propagate-wrapper-styles wrapper-props))]
|
||||||
|
|
||||||
[:& (mf/provider muc/render-ctx) {:value render-id}
|
[:& (mf/provider muc/render-id) {:value render-id}
|
||||||
[:> :g wrapper-props
|
[:> :g wrapper-props
|
||||||
(when include-metadata?
|
(when include-metadata?
|
||||||
[:& ed/export-data {:shape shape}])
|
[:& ed/export-data {:shape shape}])
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
[app.common.colors :as clr]
|
[app.common.colors :as clr]
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.geom.shapes :as gsh]
|
[app.common.geom.shapes :as gsh]
|
||||||
[app.main.ui.context :as muc]
|
|
||||||
[app.main.ui.shapes.attrs :as attrs]
|
[app.main.ui.shapes.attrs :as attrs]
|
||||||
[app.main.ui.shapes.text.styles :as sts]
|
[app.main.ui.shapes.text.styles :as sts]
|
||||||
[app.util.color :as uc]
|
[app.util.color :as uc]
|
||||||
|
@ -91,23 +90,6 @@
|
||||||
(recur (uc/next-rgb current-rgb))
|
(recur (uc/next-rgb current-rgb))
|
||||||
current-hex))))
|
current-hex))))
|
||||||
|
|
||||||
(defn- remap-colors
|
|
||||||
"Returns a new content replacing the original colors by their mapped 'simple color'"
|
|
||||||
[content color-mapping]
|
|
||||||
|
|
||||||
(cond-> content
|
|
||||||
(and (:fill-opacity content) (< (:fill-opacity content) 1.0))
|
|
||||||
(-> (assoc :fill-color (get color-mapping [(:fill-color content) (:fill-opacity content)]))
|
|
||||||
(assoc :fill-opacity 1.0))
|
|
||||||
|
|
||||||
(some? (:fill-color-gradient content))
|
|
||||||
(-> (assoc :fill-color (get color-mapping (:fill-color-gradient content)))
|
|
||||||
(assoc :fill-opacity 1.0)
|
|
||||||
(dissoc :fill-color-gradient))
|
|
||||||
|
|
||||||
(contains? content :children)
|
|
||||||
(update :children #(mapv (fn [node] (remap-colors node color-mapping)) %))))
|
|
||||||
|
|
||||||
(defn- fill->color
|
(defn- fill->color
|
||||||
"Given a content node returns the information about that node fill color"
|
"Given a content node returns the information about that node fill color"
|
||||||
[{:keys [fill-color fill-opacity fill-color-gradient]}]
|
[{:keys [fill-color fill-opacity fill-color-gradient]}]
|
||||||
|
@ -199,13 +181,7 @@
|
||||||
;; We add 8px to add a padding for the exporter
|
;; We add 8px to add a padding for the exporter
|
||||||
;; width (+ width 8)
|
;; width (+ width 8)
|
||||||
|
|
||||||
[colors color-mapping color-mapping-inverse] (retrieve-colors shape)
|
[colors _color-mapping color-mapping-inverse] (retrieve-colors shape)]
|
||||||
|
|
||||||
plain-colors? (mf/use-ctx muc/text-plain-colors-ctx)
|
|
||||||
|
|
||||||
content (cond-> content
|
|
||||||
plain-colors?
|
|
||||||
(remap-colors color-mapping))]
|
|
||||||
|
|
||||||
[:foreignObject
|
[:foreignObject
|
||||||
{:x x
|
{:x x
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
::mf/wrap [mf/memo]}
|
::mf/wrap [mf/memo]}
|
||||||
[props]
|
[props]
|
||||||
|
|
||||||
(let [render-id (mf/use-ctx muc/render-ctx)
|
(let [render-id (mf/use-ctx muc/render-id)
|
||||||
shape (obj/get props "shape")
|
shape (obj/get props "shape")
|
||||||
shape (cond-> shape (:is-mask? shape) set-white-fill)
|
shape (cond-> shape (:is-mask? shape) set-white-fill)
|
||||||
|
|
||||||
|
@ -109,6 +109,6 @@
|
||||||
(obj/set! "fill" (str "url(#fill-" index "-" render-id ")")))})
|
(obj/set! "fill" (str "url(#fill-" index "-" render-id ")")))})
|
||||||
shape (assoc shape :fills (:fills data))]
|
shape (assoc shape :fills (:fills data))]
|
||||||
|
|
||||||
[:& (mf/provider muc/render-ctx) {:key index :value (str render-id "_" (:id shape) "_" index)}
|
[:& (mf/provider muc/render-id) {:key index :value (str render-id "_" (:id shape) "_" index)}
|
||||||
[:& shape-custom-strokes {:shape shape :position index :render-id render-id}
|
[:& shape-custom-strokes {:shape shape :position index :render-id render-id}
|
||||||
[:> :text props (:text data)]]]))]]))
|
[:> :text props (:text data)]]]))]]))
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
[app.main.ui.static :as static]
|
[app.main.ui.static :as static]
|
||||||
[app.main.ui.viewer.comments :refer [comments-layer comments-sidebar]]
|
[app.main.ui.viewer.comments :refer [comments-layer comments-sidebar]]
|
||||||
[app.main.ui.viewer.handoff :as handoff]
|
[app.main.ui.viewer.handoff :as handoff]
|
||||||
[app.main.ui.viewer.header :refer [header]]
|
[app.main.ui.viewer.header :as header]
|
||||||
[app.main.ui.viewer.interactions :as interactions]
|
[app.main.ui.viewer.interactions :as interactions]
|
||||||
[app.main.ui.viewer.login]
|
[app.main.ui.viewer.login]
|
||||||
[app.main.ui.viewer.share-link]
|
[app.main.ui.viewer.share-link]
|
||||||
|
@ -36,8 +36,15 @@
|
||||||
[app.util.webapi :as wapi]
|
[app.util.webapi :as wapi]
|
||||||
[cuerdas.core :as str]
|
[cuerdas.core :as str]
|
||||||
[goog.events :as events]
|
[goog.events :as events]
|
||||||
|
[okulary.core :as l]
|
||||||
[rumext.alpha :as mf]))
|
[rumext.alpha :as mf]))
|
||||||
|
|
||||||
|
(def current-animation-ref
|
||||||
|
(l/derived :viewer-animation st/state))
|
||||||
|
|
||||||
|
(def current-overlays-ref
|
||||||
|
(l/derived :viewer-overlays st/state))
|
||||||
|
|
||||||
(defn- calculate-size
|
(defn- calculate-size
|
||||||
[objects frame zoom]
|
[objects frame zoom]
|
||||||
(let [{:keys [x y width height]} (gsb/get-object-bounds objects frame)]
|
(let [{:keys [x y width height]} (gsb/get-object-bounds objects frame)]
|
||||||
|
@ -60,7 +67,6 @@
|
||||||
:height (* height zoom)
|
:height (* height zoom)
|
||||||
:vbox (str "0 0 " width " " height)})))
|
:vbox (str "0 0 " width " " height)})))
|
||||||
|
|
||||||
|
|
||||||
(mf/defc viewer-pagination
|
(mf/defc viewer-pagination
|
||||||
[{:keys [index num-frames left-bar right-bar] :as props}]
|
[{:keys [index num-frames left-bar right-bar] :as props}]
|
||||||
[:*
|
[:*
|
||||||
|
@ -75,23 +81,83 @@
|
||||||
[:div.counter (str/join " / " [(+ index 1) num-frames])]
|
[:div.counter (str/join " / " [(+ index 1) num-frames])]
|
||||||
[:span]]])
|
[:span]]])
|
||||||
|
|
||||||
(mf/defc viewer-wrapper
|
(mf/defc viewer-pagination-and-sidebar
|
||||||
[{:keys [wrapper-size scroll orig-frame orig-viewport-ref orig-size page file users current-viewport-ref
|
{::mf/wrap [mf/memo]}
|
||||||
size frame interactions-mode overlays zoom close-overlay section index] :as props}]
|
[{:keys [section index users frame page]}]
|
||||||
(let [{clist :list} (mf/deref refs/comments-local)
|
(let [comments-local (mf/deref refs/comments-local)
|
||||||
show-comments-list (and (= section :comments) (= :show clist))]
|
show-sidebar? (and (= section :comments) (:show-sidebar? comments-local))]
|
||||||
[:*
|
[:*
|
||||||
[:& viewer-pagination {:index index :num-frames (count (:frames page)) :right-bar show-comments-list}]
|
[:& viewer-pagination
|
||||||
|
{:index index
|
||||||
|
:num-frames (count (:frames page))
|
||||||
|
:right-bar show-sidebar?}]
|
||||||
|
|
||||||
(when show-comments-list
|
(when show-sidebar?
|
||||||
[:& comments-sidebar {:users users :frame frame :page page}])
|
[:& comments-sidebar
|
||||||
|
{:users users
|
||||||
|
:frame frame
|
||||||
|
:page page}])]))
|
||||||
|
|
||||||
|
(mf/defc viewer-overlay
|
||||||
|
[{:keys [overlay page frame zoom wrapper-size close-overlay interactions-mode]}]
|
||||||
|
(let [close-click-outside? (:close-click-outside overlay)
|
||||||
|
background-overlay? (:background-overlay overlay)
|
||||||
|
overlay-frame (:frame overlay)
|
||||||
|
overlay-position (:position overlay)
|
||||||
|
|
||||||
|
size
|
||||||
|
(mf/with-memo [page overlay zoom]
|
||||||
|
(calculate-size (:objects page) (:frame overlay) zoom))
|
||||||
|
|
||||||
|
on-click
|
||||||
|
(mf/use-fn
|
||||||
|
(mf/deps overlay close-overlay close-click-outside?)
|
||||||
|
(fn [_]
|
||||||
|
(when close-click-outside?
|
||||||
|
(close-overlay (:frame overlay)))))]
|
||||||
|
|
||||||
|
[:*
|
||||||
|
(when (or close-click-outside? background-overlay?)
|
||||||
|
[:div.viewer-overlay-background
|
||||||
|
{:class (dom/classnames :visible background-overlay?)
|
||||||
|
:style {:width (:width wrapper-size)
|
||||||
|
:height (:height wrapper-size)
|
||||||
|
:position "absolute"
|
||||||
|
:left 0
|
||||||
|
:top 0}
|
||||||
|
:on-click on-click}])
|
||||||
|
|
||||||
|
[:div.viewport-container.viewer-overlay
|
||||||
|
{:id (dm/str "overlay-" (:id overlay-frame))
|
||||||
|
:style {:width (:width size)
|
||||||
|
:height (:height size)
|
||||||
|
:left (* (:x overlay-position) zoom)
|
||||||
|
:top (* (:y overlay-position) zoom)}}
|
||||||
|
|
||||||
|
[:& interactions/viewport
|
||||||
|
{:frame overlay-frame
|
||||||
|
:base-frame frame
|
||||||
|
:frame-offset overlay-position
|
||||||
|
:size size
|
||||||
|
:page page
|
||||||
|
:interactions-mode interactions-mode}]]]))
|
||||||
|
|
||||||
|
|
||||||
|
(mf/defc viewer-wrapper
|
||||||
|
[{:keys [wrapper-size orig-frame orig-viewport-ref orig-size page file users current-viewport-ref
|
||||||
|
size frame interactions-mode overlays zoom close-overlay section index] :as props}]
|
||||||
|
[:*
|
||||||
|
[:& viewer-pagination-and-sidebar
|
||||||
|
{:section section
|
||||||
|
:index index
|
||||||
|
:page page
|
||||||
|
:users users
|
||||||
|
:frame frame}]
|
||||||
|
|
||||||
[:div.viewer-wrapper
|
[:div.viewer-wrapper
|
||||||
{:style {:width (:width wrapper-size)
|
{:style {:width (:width wrapper-size)
|
||||||
:height (:height wrapper-size)}}
|
:height (:height wrapper-size)}}
|
||||||
[:& (mf/provider ctx/scroll-ctx) {:value @scroll}
|
|
||||||
[:div.viewer-clipper
|
[:div.viewer-clipper
|
||||||
[:*
|
|
||||||
(when orig-frame
|
(when orig-frame
|
||||||
[:div.viewport-container
|
[:div.viewport-container
|
||||||
{:ref orig-viewport-ref
|
{:ref orig-viewport-ref
|
||||||
|
@ -105,7 +171,6 @@
|
||||||
:frame-offset (gpt/point 0 0)
|
:frame-offset (gpt/point 0 0)
|
||||||
:size orig-size
|
:size orig-size
|
||||||
:page page
|
:page page
|
||||||
:file file
|
|
||||||
:users users
|
:users users
|
||||||
:interactions-mode :hide}]])
|
:interactions-mode :hide}]])
|
||||||
|
|
||||||
|
@ -121,48 +186,27 @@
|
||||||
:frame-offset (gpt/point 0 0)
|
:frame-offset (gpt/point 0 0)
|
||||||
:size size
|
:size size
|
||||||
:page page
|
:page page
|
||||||
:file file
|
|
||||||
:users users
|
|
||||||
:interactions-mode interactions-mode}]
|
:interactions-mode interactions-mode}]
|
||||||
|
|
||||||
(for [overlay overlays]
|
(for [overlay overlays]
|
||||||
(let [size-over (calculate-size (:objects page) (:frame overlay) zoom)]
|
[:& viewer-overlay {:overlay overlay
|
||||||
[:*
|
:key (dm/str (:id overlay))
|
||||||
(when (or (:close-click-outside overlay)
|
|
||||||
(:background-overlay overlay))
|
|
||||||
[:div.viewer-overlay-background
|
|
||||||
{:class (dom/classnames
|
|
||||||
:visible (:background-overlay overlay))
|
|
||||||
:style {:width (:width wrapper-size)
|
|
||||||
:height (:height wrapper-size)
|
|
||||||
:position "absolute"
|
|
||||||
:left 0
|
|
||||||
:top 0}
|
|
||||||
:on-click #(when (:close-click-outside overlay)
|
|
||||||
(close-overlay (:frame overlay)))}])
|
|
||||||
[:div.viewport-container.viewer-overlay
|
|
||||||
|
|
||||||
{:id (str "overlay-" (-> overlay :frame :id))
|
|
||||||
:style {:width (:width size-over)
|
|
||||||
:height (:height size-over)
|
|
||||||
:left (* (:x (:position overlay)) zoom)
|
|
||||||
:top (* (:y (:position overlay)) zoom)}}
|
|
||||||
[:& interactions/viewport
|
|
||||||
{:frame (:frame overlay)
|
|
||||||
:base-frame frame
|
|
||||||
:frame-offset (:position overlay)
|
|
||||||
:size size-over
|
|
||||||
:page page
|
:page page
|
||||||
:file file
|
:frame frame
|
||||||
:users users
|
:zoom zoom
|
||||||
:interactions-mode interactions-mode}]]]))]]
|
:wrapper-size wrapper-size
|
||||||
|
:close-overlay close-overlay
|
||||||
|
:interactions-mode interactions-mode}])
|
||||||
|
|
||||||
|
]]
|
||||||
|
|
||||||
|
|
||||||
(when (= section :comments)
|
(when (= section :comments)
|
||||||
[:& comments-layer {:file file
|
[:& comments-layer {:file file
|
||||||
:users users
|
:users users
|
||||||
:frame frame
|
:frame frame
|
||||||
:page page
|
:page page
|
||||||
:zoom zoom}])]]]]))
|
:zoom zoom}])]])
|
||||||
|
|
||||||
(mf/defc viewer
|
(mf/defc viewer
|
||||||
[{:keys [params data]}]
|
[{:keys [params data]}]
|
||||||
|
@ -187,7 +231,8 @@
|
||||||
orig-viewport-ref (mf/use-ref nil)
|
orig-viewport-ref (mf/use-ref nil)
|
||||||
current-viewport-ref (mf/use-ref nil)
|
current-viewport-ref (mf/use-ref nil)
|
||||||
viewer-section-ref (mf/use-ref nil)
|
viewer-section-ref (mf/use-ref nil)
|
||||||
current-animation (:current-animation local)
|
|
||||||
|
current-animation (mf/deref current-animation-ref)
|
||||||
|
|
||||||
page-id (or page-id (-> file :data :pages first))
|
page-id (or page-id (-> file :data :pages first))
|
||||||
|
|
||||||
|
@ -208,26 +253,26 @@
|
||||||
frames (:frames page)
|
frames (:frames page)
|
||||||
frame (get frames index)
|
frame (get frames index)
|
||||||
|
|
||||||
fullscreen? (mf/deref refs/viewer-fullscreen?)
|
fullscreen? (mf/deref header/fullscreen-ref)
|
||||||
overlays (:overlays local)
|
overlays (mf/deref current-overlays-ref)
|
||||||
scroll (mf/use-state nil)
|
scroll (mf/use-state nil)
|
||||||
|
|
||||||
orig-frame
|
orig-frame
|
||||||
(when (:orig-frame-id current-animation)
|
(when (:orig-frame-id current-animation)
|
||||||
(d/seek #(= (:id %) (:orig-frame-id current-animation)) frames))
|
(d/seek #(= (:id %) (:orig-frame-id current-animation)) frames))
|
||||||
|
|
||||||
size (mf/use-memo
|
size
|
||||||
(mf/deps frame zoom)
|
(mf/with-memo [frame zoom]
|
||||||
(fn [] (calculate-size (:objects page) frame zoom)))
|
(calculate-size (:objects page) frame zoom))
|
||||||
|
|
||||||
orig-size (mf/use-memo
|
orig-size
|
||||||
(mf/deps orig-frame zoom)
|
(mf/with-memo [orig-frame zoom]
|
||||||
(fn [] (when orig-frame
|
(when orig-frame
|
||||||
(calculate-size (:objects page) orig-frame zoom))))
|
(calculate-size (:objects page) orig-frame zoom)))
|
||||||
|
|
||||||
wrapper-size (mf/use-memo
|
wrapper-size
|
||||||
(mf/deps size orig-size zoom)
|
(mf/with-memo [size orig-size zoom]
|
||||||
(fn [] (calculate-wrapper size orig-size zoom)))
|
(calculate-wrapper size orig-size zoom))
|
||||||
|
|
||||||
interactions-mode
|
interactions-mode
|
||||||
(:interactions-mode local)
|
(:interactions-mode local)
|
||||||
|
@ -246,22 +291,23 @@
|
||||||
(dom/add-class! layout "force-visible"))))))
|
(dom/add-class! layout "force-visible"))))))
|
||||||
|
|
||||||
on-click
|
on-click
|
||||||
(mf/use-callback
|
(mf/use-fn
|
||||||
(mf/deps section)
|
(mf/deps section)
|
||||||
(fn [_]
|
(fn [_]
|
||||||
(when (= section :comments)
|
(when (= section :comments)
|
||||||
(st/emit! (dcm/close-thread)))))
|
(st/emit! (dcm/close-thread)))))
|
||||||
|
|
||||||
set-up-new-size
|
set-up-new-size
|
||||||
(mf/use-callback
|
(mf/use-fn
|
||||||
(fn [_]
|
(fn [_]
|
||||||
(let [viewer-section (dom/get-element "viewer-section")
|
(let [viewer-section (dom/get-element "viewer-section")
|
||||||
size (dom/get-client-size viewer-section)]
|
size (dom/get-client-size viewer-section)]
|
||||||
(st/emit! (dv/set-viewport-size {:size size})))))
|
(st/emit! (dv/set-viewport-size {:size size})))))
|
||||||
|
|
||||||
on-scroll
|
on-scroll
|
||||||
|
(mf/use-fn
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(reset! scroll (dom/get-target-scroll event)))]
|
(reset! scroll (dom/get-target-scroll event))))]
|
||||||
|
|
||||||
(hooks/use-shortcuts ::viewer sc/shortcuts)
|
(hooks/use-shortcuts ::viewer sc/shortcuts)
|
||||||
(when (nil? page)
|
(when (nil? page)
|
||||||
|
@ -278,14 +324,13 @@
|
||||||
(let [name (:name file)]
|
(let [name (:name file)]
|
||||||
(dom/set-html-title (str "\u25b6 " (tr "title.viewer" name))))))
|
(dom/set-html-title (str "\u25b6 " (tr "title.viewer" name))))))
|
||||||
|
|
||||||
(mf/use-effect
|
(mf/with-effect []
|
||||||
(fn []
|
|
||||||
(dom/set-html-theme-color clr/gray-50 "dark")
|
(dom/set-html-theme-color clr/gray-50 "dark")
|
||||||
(let [key1 (events/listen js/window "click" on-click)
|
(let [key1 (events/listen js/window "click" on-click)
|
||||||
key2 (events/listen (mf/ref-val viewer-section-ref) "scroll" on-scroll)]
|
key2 (events/listen (mf/ref-val viewer-section-ref) "scroll" on-scroll)]
|
||||||
(fn []
|
(fn []
|
||||||
(events/unlistenByKey key1)
|
(events/unlistenByKey key1)
|
||||||
(events/unlistenByKey key2)))))
|
(events/unlistenByKey key2))))
|
||||||
|
|
||||||
(mf/use-layout-effect
|
(mf/use-layout-effect
|
||||||
(fn []
|
(fn []
|
||||||
|
@ -388,14 +433,16 @@
|
||||||
fonts (into #{} (keep :font-id) text-nodes)]
|
fonts (into #{} (keep :font-id) text-nodes)]
|
||||||
(run! fonts/ensure-loaded! fonts))))
|
(run! fonts/ensure-loaded! fonts))))
|
||||||
|
|
||||||
[:div#viewer-layout {:class (dom/classnames
|
[:div#viewer-layout
|
||||||
|
{:class (dom/classnames
|
||||||
:force-visible (:show-thumbnails local)
|
:force-visible (:show-thumbnails local)
|
||||||
:viewer-layout (not= section :handoff)
|
:viewer-layout (not= section :handoff)
|
||||||
:handoff-layout (= section :handoff)
|
:handoff-layout (= section :handoff)
|
||||||
:fullscreen fullscreen?)}
|
:fullscreen fullscreen?)}
|
||||||
|
|
||||||
[:div.viewer-content
|
[:div.viewer-content
|
||||||
[:& header {:project project
|
[:& header/header
|
||||||
|
{:project project
|
||||||
:index index
|
:index index
|
||||||
:file file
|
:file file
|
||||||
:page page
|
:page page
|
||||||
|
@ -403,6 +450,7 @@
|
||||||
:permissions permissions
|
:permissions permissions
|
||||||
:zoom zoom
|
:zoom zoom
|
||||||
:section section}]
|
:section section}]
|
||||||
|
|
||||||
[:div.thumbnail-close {:on-click #(st/emit! dv/close-thumbnails-panel)
|
[:div.thumbnail-close {:on-click #(st/emit! dv/close-thumbnails-panel)
|
||||||
:class (dom/classnames :invisible (not (:show-thumbnails local false)))}]
|
:class (dom/classnames :invisible (not (:show-thumbnails local false)))}]
|
||||||
[:& thumbnails-panel {:frames frames
|
[:& thumbnails-panel {:frames frames
|
||||||
|
@ -436,9 +484,10 @@
|
||||||
:index index
|
:index index
|
||||||
:viewer-pagination viewer-pagination}]
|
:viewer-pagination viewer-pagination}]
|
||||||
|
|
||||||
|
[:& (mf/provider ctx/current-scroll) {:value @scroll}
|
||||||
|
[:& (mf/provider ctx/current-zoom) {:value zoom}
|
||||||
[:& viewer-wrapper
|
[:& viewer-wrapper
|
||||||
{:wrapper-size wrapper-size
|
{:wrapper-size wrapper-size
|
||||||
:scroll scroll
|
|
||||||
:orig-frame orig-frame
|
:orig-frame orig-frame
|
||||||
:orig-viewport-ref orig-viewport-ref
|
:orig-viewport-ref orig-viewport-ref
|
||||||
:orig-size orig-size
|
:orig-size orig-size
|
||||||
|
@ -452,7 +501,7 @@
|
||||||
:overlays overlays
|
:overlays overlays
|
||||||
:zoom zoom
|
:zoom zoom
|
||||||
:section section
|
:section section
|
||||||
:index index}]))]]]))
|
:index index}]]]))]]]))
|
||||||
|
|
||||||
;; --- Component: Viewer Page
|
;; --- Component: Viewer Page
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
(ns app.main.ui.viewer.comments
|
(ns app.main.ui.viewer.comments
|
||||||
(:require
|
(:require
|
||||||
|
[app.common.data :as d]
|
||||||
[app.common.geom.matrix :as gmt]
|
[app.common.geom.matrix :as gmt]
|
||||||
[app.common.geom.point :as gpt]
|
[app.common.geom.point :as gpt]
|
||||||
[app.common.geom.shapes :as gsh]
|
[app.common.geom.shapes :as gsh]
|
||||||
|
@ -23,132 +24,141 @@
|
||||||
[rumext.alpha :as mf]))
|
[rumext.alpha :as mf]))
|
||||||
|
|
||||||
(mf/defc comments-menu
|
(mf/defc comments-menu
|
||||||
|
{::mf/wrap [mf/memo]
|
||||||
|
::mf/wrap-props false}
|
||||||
[]
|
[]
|
||||||
(let [{cmode :mode cshow :show clist :list} (mf/deref refs/comments-local)
|
(let [local (mf/deref refs/comments-local)
|
||||||
|
owner-filter (:owner-filter local)
|
||||||
|
status-filter (:status-filter local)
|
||||||
|
show-sidebar? (:show-sidebar? local)
|
||||||
|
|
||||||
show-dropdown? (mf/use-state false)
|
show-dropdown? (mf/use-state false)
|
||||||
toggle-dropdown (mf/use-fn #(swap! show-dropdown? not))
|
toggle-dropdown (mf/use-fn #(swap! show-dropdown? not))
|
||||||
hide-dropdown (mf/use-fn #(reset! show-dropdown? false))
|
hide-dropdown (mf/use-fn #(reset! show-dropdown? false))
|
||||||
|
|
||||||
update-mode
|
update-option (mf/use-fn
|
||||||
(mf/use-callback
|
(fn [event]
|
||||||
(fn [mode]
|
(let [target (dom/get-current-target event)
|
||||||
(st/emit! (dcm/update-filters {:mode mode}))))
|
key (d/read-string (dom/get-attribute target "data-key"))
|
||||||
|
val (d/read-string (dom/get-attribute target "data-val"))]
|
||||||
update-show
|
(st/emit! (dcm/update-options {key val})))))]
|
||||||
(mf/use-callback
|
|
||||||
(fn [mode]
|
|
||||||
(st/emit! (dcm/update-filters {:show mode}))))
|
|
||||||
|
|
||||||
update-list
|
|
||||||
(mf/use-callback
|
|
||||||
(fn [show-list]
|
|
||||||
(st/emit! (dcm/update-filters {:list show-list}))))]
|
|
||||||
|
|
||||||
[:div.view-options {:on-click toggle-dropdown}
|
[:div.view-options {:on-click toggle-dropdown}
|
||||||
[:span.label (tr "labels.comments")]
|
[:span.label (tr "labels.comments")]
|
||||||
[:span.icon i/arrow-down]
|
[:span.icon i/arrow-down]
|
||||||
[:& dropdown {:show @show-dropdown?
|
[:& dropdown {:show @show-dropdown?
|
||||||
:on-close hide-dropdown}
|
:on-close hide-dropdown}
|
||||||
|
|
||||||
[:ul.dropdown.with-check
|
[:ul.dropdown.with-check
|
||||||
[:li {:class (dom/classnames :selected (= :all cmode))
|
[:li {:class (dom/classnames :selected (= :all owner-filter))
|
||||||
:on-click #(update-mode :all)}
|
:data-key ":owner-filter"
|
||||||
|
:data-val ":all"
|
||||||
|
:on-click update-option}
|
||||||
[:span.icon i/tick]
|
[:span.icon i/tick]
|
||||||
[:span.label (tr "labels.show-all-comments")]]
|
[:span.label (tr "labels.show-all-comments")]]
|
||||||
|
|
||||||
[:li {:class (dom/classnames :selected (= :yours cmode))
|
[:li {:class (dom/classnames :selected (= :yours owner-filter))
|
||||||
:on-click #(update-mode :yours)}
|
:data-key ":owner-filter"
|
||||||
|
:data-val ":yours"
|
||||||
|
:on-click update-option}
|
||||||
[:span.icon i/tick]
|
[:span.icon i/tick]
|
||||||
[:span.label (tr "labels.show-your-comments")]]
|
[:span.label (tr "labels.show-your-comments")]]
|
||||||
|
|
||||||
[:hr]
|
[:hr]
|
||||||
|
|
||||||
[:li {:class (dom/classnames :selected (= :pending cshow))
|
[:li {:class (dom/classnames :selected (= :pending status-filter))
|
||||||
:on-click #(update-show (if (= :pending cshow) :all :pending))}
|
:data-key ":status-filter"
|
||||||
|
:data-val (if (= :pending status-filter) ":all" ":pending")
|
||||||
|
:on-click update-option}
|
||||||
[:span.icon i/tick]
|
[:span.icon i/tick]
|
||||||
[:span.label (tr "labels.hide-resolved-comments")]]
|
[:span.label (tr "labels.hide-resolved-comments")]]
|
||||||
|
|
||||||
[:hr]
|
[:hr]
|
||||||
|
[:li {:class (dom/classnames :selected show-sidebar?)
|
||||||
[:li {:class (dom/classnames :selected (= :show clist))
|
:data-key ":show-sidebar?"
|
||||||
:on-click #(update-list (if (= :show clist) :hide :show))}
|
:data-val (if show-sidebar? "false" "true")
|
||||||
|
:on-click update-option}
|
||||||
[:span.icon i/tick]
|
[:span.icon i/tick]
|
||||||
[:span.label (tr "labels.show-comments-list")]]]]]))
|
[:span.label (tr "labels.show-comments-list")]]]]]))
|
||||||
|
|
||||||
|
|
||||||
(def threads-ref
|
(defn- update-thread-position [positions {:keys [id] :as thread}]
|
||||||
(l/derived :comment-threads st/state))
|
(if-let [data (get positions id)]
|
||||||
|
(-> thread
|
||||||
(def comments-local-ref
|
(assoc :position (:position data))
|
||||||
(l/derived :comments-local st/state))
|
(assoc :frame-id (:frame-id data)))
|
||||||
|
thread))
|
||||||
|
|
||||||
(mf/defc comments-layer
|
(mf/defc comments-layer
|
||||||
[{:keys [zoom file users frame page] :as props}]
|
[{:keys [zoom file users frame page] :as props}]
|
||||||
(let [profile (mf/deref refs/profile)
|
(let [profile (mf/deref refs/profile)
|
||||||
threads-position-ref (l/derived (l/in [:viewer :pages (:id page) :options :comment-threads-position]) st/state)
|
local (mf/deref refs/comments-local)
|
||||||
threads-position-map (mf/deref threads-position-ref)
|
|
||||||
threads-map (mf/deref threads-ref)
|
|
||||||
|
|
||||||
frame-corner (-> frame :points gsh/points->selrect gpt/point)
|
open-thread-id (:open local)
|
||||||
modifier1 (-> (gmt/matrix)
|
page-id (:id page)
|
||||||
(gmt/translate (gpt/negate frame-corner)))
|
file-id (:id file)
|
||||||
|
frame-id (:id frame)
|
||||||
|
|
||||||
modifier2 (-> (gpt/point frame-corner)
|
tpos-ref (mf/with-memo [page-id]
|
||||||
(gmt/translate-matrix))
|
(-> (l/in [:pages page-id :options :comment-threads-position])
|
||||||
|
(l/derived refs/viewer-data)))
|
||||||
|
|
||||||
cstate (mf/deref refs/comments-local)
|
positions (mf/deref tpos-ref)
|
||||||
|
threads-map (mf/deref refs/comment-threads)
|
||||||
|
|
||||||
update-thread-position (fn update-thread-position [thread]
|
frame-corner (mf/with-memo [frame]
|
||||||
(if (contains? threads-position-map (:id thread))
|
(-> frame :points gsh/points->selrect gpt/point))
|
||||||
(-> thread
|
|
||||||
(assoc :position (get-in threads-position-map [(:id thread) :position]))
|
|
||||||
(assoc :frame-id (get-in threads-position-map [(:id thread) :frame-id])))
|
|
||||||
thread))
|
|
||||||
|
|
||||||
threads (->> (vals threads-map)
|
modifier1 (mf/with-memo [frame-corner]
|
||||||
(map update-thread-position)
|
(-> (gmt/matrix)
|
||||||
|
(gmt/translate (gpt/negate frame-corner))))
|
||||||
|
|
||||||
|
modifier2 (mf/with-memo [frame-corner]
|
||||||
|
(-> (gpt/point frame-corner)
|
||||||
|
(gmt/translate-matrix)))
|
||||||
|
|
||||||
|
threads (mf/with-memo [threads-map positions frame local profile]
|
||||||
|
(->> (vals threads-map)
|
||||||
|
(map (partial update-thread-position positions))
|
||||||
(filter #(= (:frame-id %) (:id frame)))
|
(filter #(= (:frame-id %) (:id frame)))
|
||||||
(dcm/apply-filters cstate profile)
|
(dcm/apply-filters local profile)
|
||||||
(filter (fn [{:keys [position]}]
|
(filter (fn [{:keys [position]}]
|
||||||
(gsh/has-point? frame position))))
|
(gsh/has-point? frame position)))))
|
||||||
|
|
||||||
on-bubble-click
|
on-bubble-click
|
||||||
(mf/use-callback
|
(mf/use-fn
|
||||||
(mf/deps cstate)
|
(mf/deps open-thread-id)
|
||||||
(fn [thread]
|
(fn [{:keys [id] :as thread}]
|
||||||
(if (= (:open cstate) (:id thread))
|
(st/emit! (if (= open-thread-id id)
|
||||||
(st/emit! (dcm/close-thread))
|
(dcm/close-thread)
|
||||||
(st/emit! (-> (dcm/open-thread thread)
|
(-> (dcm/open-thread thread)
|
||||||
(with-meta {::ev/origin "viewer"}))))))
|
(with-meta {::ev/origin "viewer"}))))))
|
||||||
|
|
||||||
on-click
|
on-click
|
||||||
(mf/use-callback
|
(mf/use-fn
|
||||||
(mf/deps cstate frame page file zoom)
|
(mf/deps open-thread-id zoom page-id file-id modifier2)
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(dom/stop-propagation event)
|
(dom/stop-propagation event)
|
||||||
(if (some? (:open cstate))
|
(if (some? open-thread-id)
|
||||||
(st/emit! (dcm/close-thread))
|
(st/emit! (dcm/close-thread))
|
||||||
(let [event (.-nativeEvent ^js event)
|
(let [event (dom/event->native-event event)
|
||||||
viewport-point (dom/get-offset-position event)
|
position (-> (dom/get-offset-position event)
|
||||||
viewport-point (-> viewport-point (update :x #(/ % zoom)) (update :y #(/ % zoom)))
|
(update :x #(/ % zoom))
|
||||||
position (gpt/transform viewport-point modifier2)
|
(update :y #(/ % zoom))
|
||||||
|
(gpt/transform modifier2))
|
||||||
params {:position position
|
params {:position position
|
||||||
:page-id (:id page)
|
:page-id (:id page)
|
||||||
:file-id (:id file)}]
|
:file-id (:id file)}]
|
||||||
(st/emit! (dcm/create-draft params))))))
|
(st/emit! (dcm/create-draft params))))))
|
||||||
|
|
||||||
on-draft-cancel
|
on-draft-cancel
|
||||||
(mf/use-callback
|
(mf/use-fn #(st/emit! (dcm/close-thread)))
|
||||||
(mf/deps cstate)
|
|
||||||
#(st/emit! (dcm/close-thread)))
|
|
||||||
|
|
||||||
on-draft-submit
|
on-draft-submit
|
||||||
(mf/use-callback
|
(mf/use-fn
|
||||||
(mf/deps frame)
|
(mf/deps frame-id modifier2)
|
||||||
(fn [draft]
|
(fn [draft]
|
||||||
(let [params (-> draft
|
(let [params (assoc draft :frame-id frame-id)]
|
||||||
(update :position gpt/transform modifier2)
|
|
||||||
(assoc :frame-id (:id frame)))]
|
|
||||||
(st/emit! (dcm/create-thread-on-viewer params)
|
(st/emit! (dcm/create-thread-on-viewer params)
|
||||||
(dcm/close-thread)))))]
|
(dcm/close-thread)))))]
|
||||||
|
|
||||||
|
@ -156,24 +166,26 @@
|
||||||
[:div.viewer-comments-container
|
[:div.viewer-comments-container
|
||||||
[:div.threads
|
[:div.threads
|
||||||
(for [item threads]
|
(for [item threads]
|
||||||
(let [item (update item :position gpt/transform modifier1)]
|
[:& cmt/thread-bubble
|
||||||
[:& cmt/thread-bubble {:thread item
|
{:thread item
|
||||||
|
:position-modifier modifier1
|
||||||
:zoom zoom
|
:zoom zoom
|
||||||
:on-click on-bubble-click
|
:on-click on-bubble-click
|
||||||
:open? (= (:id item) (:open cstate))
|
:open? (= (:id item) (:open local))
|
||||||
:key (:seqn item)
|
:key (:seqn item)
|
||||||
:origin :viewer}]))
|
:origin :viewer}])
|
||||||
|
|
||||||
(when-let [id (:open cstate)]
|
(when-let [thread (get threads-map open-thread-id)]
|
||||||
(when-let [thread (as-> (get threads-map id) $
|
[:& cmt/thread-comments
|
||||||
(when (some? $)
|
{:thread thread
|
||||||
(update $ :position gpt/transform modifier1)))]
|
:position-modifier modifier1
|
||||||
[:& cmt/thread-comments {:thread thread
|
|
||||||
:users users
|
:users users
|
||||||
:zoom zoom}]))
|
:zoom zoom}])
|
||||||
|
|
||||||
(when-let [draft (:draft cstate)]
|
(when-let [draft (:draft local)]
|
||||||
[:& cmt/draft-thread {:draft (update draft :position gpt/transform modifier1)
|
[:& cmt/draft-thread
|
||||||
|
{:draft draft
|
||||||
|
:position-modifier modifier1
|
||||||
:on-cancel on-draft-cancel
|
:on-cancel on-draft-cancel
|
||||||
:on-submit on-draft-submit
|
:on-submit on-draft-submit
|
||||||
:zoom zoom}])]]]))
|
:zoom zoom}])]]]))
|
||||||
|
@ -181,10 +193,10 @@
|
||||||
(mf/defc comments-sidebar
|
(mf/defc comments-sidebar
|
||||||
[{:keys [users frame page]}]
|
[{:keys [users frame page]}]
|
||||||
(let [profile (mf/deref refs/profile)
|
(let [profile (mf/deref refs/profile)
|
||||||
cstate (mf/deref refs/comments-local)
|
local (mf/deref refs/comments-local)
|
||||||
threads-map (mf/deref threads-ref)
|
threads-map (mf/deref refs/comment-threads)
|
||||||
threads (->> (vals threads-map)
|
threads (->> (vals threads-map)
|
||||||
(dcm/apply-filters cstate profile)
|
(dcm/apply-filters local profile)
|
||||||
(filter (fn [{:keys [position]}]
|
(filter (fn [{:keys [position]}]
|
||||||
(gsh/has-point? frame position))))]
|
(gsh/has-point? frame position))))]
|
||||||
[:aside.settings-bar.settings-bar-right.comments-right-sidebar
|
[:aside.settings-bar.settings-bar-right.comments-right-sidebar
|
||||||
|
|
|
@ -72,12 +72,7 @@
|
||||||
|
|
||||||
[:div.element-options
|
[:div.element-options
|
||||||
[:div.code-block
|
[:div.code-block
|
||||||
[:div.code-row-lang
|
[:div.code-row-lang "CSS"
|
||||||
[:select.code-selection
|
|
||||||
[:option {:value "css"} "CSS"]
|
|
||||||
#_[:option {:value "sass"} "SASS"]
|
|
||||||
#_[:option {:value "less"} "Less"]
|
|
||||||
#_[:option {:value "stylus"} "Stylus"]]
|
|
||||||
|
|
||||||
[:button.expand-button
|
[:button.expand-button
|
||||||
{:on-click on-expand }
|
{:on-click on-expand }
|
||||||
|
@ -91,10 +86,7 @@
|
||||||
:code style-code}]]]
|
:code style-code}]]]
|
||||||
|
|
||||||
[:div.code-block
|
[:div.code-block
|
||||||
[:div.code-row-lang
|
[:div.code-row-lang "SVG"
|
||||||
[:select.code-selection
|
|
||||||
[:option "SVG"]
|
|
||||||
[:option "HTML"]]
|
|
||||||
|
|
||||||
[:button.expand-button
|
[:button.expand-button
|
||||||
{:on-click on-expand}
|
{:on-click on-expand}
|
||||||
|
|
|
@ -188,8 +188,7 @@
|
||||||
|
|
||||||
(mf/defc render-frame-svg
|
(mf/defc render-frame-svg
|
||||||
[{:keys [page frame local size]}]
|
[{:keys [page frame local size]}]
|
||||||
(let [objects (mf/use-memo
|
(let [objects (mf/with-memo [page frame size]
|
||||||
(mf/deps page frame)
|
|
||||||
(prepare-objects page frame size))
|
(prepare-objects page frame size))
|
||||||
|
|
||||||
;; Retrieve frame again with correct modifier
|
;; Retrieve frame again with correct modifier
|
||||||
|
|
|
@ -6,10 +6,10 @@
|
||||||
|
|
||||||
(ns app.main.ui.viewer.header
|
(ns app.main.ui.viewer.header
|
||||||
(:require
|
(:require
|
||||||
|
[app.common.data.macros :as dm]
|
||||||
[app.main.data.modal :as modal]
|
[app.main.data.modal :as modal]
|
||||||
[app.main.data.viewer :as dv]
|
[app.main.data.viewer :as dv]
|
||||||
[app.main.data.viewer.shortcuts :as sc]
|
[app.main.data.viewer.shortcuts :as sc]
|
||||||
[app.main.refs :as refs]
|
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.components.dropdown :refer [dropdown]]
|
[app.main.ui.components.dropdown :refer [dropdown]]
|
||||||
[app.main.ui.export :refer [export-progress-widget]]
|
[app.main.ui.export :refer [export-progress-widget]]
|
||||||
|
@ -19,8 +19,14 @@
|
||||||
[app.main.ui.viewer.interactions :refer [flows-menu interactions-menu]]
|
[app.main.ui.viewer.interactions :refer [flows-menu interactions-menu]]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
[app.util.i18n :refer [tr]]
|
[app.util.i18n :refer [tr]]
|
||||||
|
[okulary.core :as l]
|
||||||
[rumext.alpha :as mf]))
|
[rumext.alpha :as mf]))
|
||||||
|
|
||||||
|
(def fullscreen-ref
|
||||||
|
(l/derived (fn [state]
|
||||||
|
(dm/get-in state [:viewer-local :fullscreen?]))
|
||||||
|
st/state))
|
||||||
|
|
||||||
(defn open-login-dialog
|
(defn open-login-dialog
|
||||||
[]
|
[]
|
||||||
(modal/show! :login-register {}))
|
(modal/show! :login-register {}))
|
||||||
|
@ -65,7 +71,7 @@
|
||||||
|
|
||||||
(mf/defc header-options
|
(mf/defc header-options
|
||||||
[{:keys [section zoom page file index permissions]}]
|
[{:keys [section zoom page file index permissions]}]
|
||||||
(let [fullscreen? (mf/deref refs/viewer-fullscreen?)
|
(let [fullscreen? (mf/deref fullscreen-ref)
|
||||||
|
|
||||||
toggle-fullscreen
|
toggle-fullscreen
|
||||||
(mf/use-callback
|
(mf/use-callback
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
[app.main.refs :as refs]
|
[app.main.refs :as refs]
|
||||||
[app.main.store :as st]
|
[app.main.store :as st]
|
||||||
[app.main.ui.components.dropdown :refer [dropdown]]
|
[app.main.ui.components.dropdown :refer [dropdown]]
|
||||||
|
[app.main.ui.hooks :as h]
|
||||||
[app.main.ui.icons :as i]
|
[app.main.ui.icons :as i]
|
||||||
[app.main.ui.viewer.shapes :as shapes]
|
[app.main.ui.viewer.shapes :as shapes]
|
||||||
[app.util.dom :as dom]
|
[app.util.dom :as dom]
|
||||||
|
@ -27,7 +28,6 @@
|
||||||
|
|
||||||
(defn prepare-objects
|
(defn prepare-objects
|
||||||
[page frame size]
|
[page frame size]
|
||||||
(fn []
|
|
||||||
(let [objects (:objects page)
|
(let [objects (:objects page)
|
||||||
frame-id (:id frame)
|
frame-id (:id frame)
|
||||||
modifier (-> (gpt/point (:x size) (:y size))
|
modifier (-> (gpt/point (:x size) (:y size))
|
||||||
|
@ -38,34 +38,69 @@
|
||||||
|
|
||||||
(->> (cph/get-children-ids objects frame-id)
|
(->> (cph/get-children-ids objects frame-id)
|
||||||
(into [frame-id])
|
(into [frame-id])
|
||||||
(reduce update-fn objects)))))
|
(reduce update-fn objects))))
|
||||||
|
|
||||||
(mf/defc viewport
|
(mf/defc viewport-svg
|
||||||
{::mf/wrap [mf/memo]}
|
{::mf/wrap [mf/memo]
|
||||||
[{:keys [page interactions-mode frame base-frame frame-offset size]}]
|
::mf/wrap-props false}
|
||||||
(let [objects (mf/use-memo
|
[props]
|
||||||
(mf/deps page frame size)
|
(let [page (unchecked-get props "page")
|
||||||
|
frame (unchecked-get props "frame")
|
||||||
|
base (unchecked-get props "base")
|
||||||
|
offset (unchecked-get props "offset")
|
||||||
|
size (unchecked-get props "size")
|
||||||
|
|
||||||
|
vbox (:vbox size)
|
||||||
|
|
||||||
|
objects (mf/with-memo [page frame size]
|
||||||
(prepare-objects page frame size))
|
(prepare-objects page frame size))
|
||||||
|
|
||||||
wrapper (mf/use-memo
|
wrapper (mf/with-memo [objects]
|
||||||
(mf/deps objects)
|
(shapes/frame-container-factory objects))
|
||||||
#(shapes/frame-container-factory objects))
|
|
||||||
|
|
||||||
;; Retrieve frames again with correct modifier
|
;; Retrieve frames again with correct modifier
|
||||||
frame (get objects (:id frame))
|
frame (get objects (:id frame))
|
||||||
base-frame (get objects (:id base-frame))
|
base (get objects (:id base))]
|
||||||
|
|
||||||
on-click
|
[:& (mf/provider shapes/base-frame-ctx) {:value base}
|
||||||
|
[:& (mf/provider shapes/frame-offset-ctx) {:value offset}
|
||||||
|
[:svg {:view-box vbox
|
||||||
|
:width (:width size)
|
||||||
|
:height (:height size)
|
||||||
|
:version "1.1"
|
||||||
|
:xmlnsXlink "http://www.w3.org/1999/xlink"
|
||||||
|
:xmlns "http://www.w3.org/2000/svg"
|
||||||
|
:fill "none"}
|
||||||
|
[:& wrapper {:shape frame :view-box vbox}]]]]))
|
||||||
|
|
||||||
|
(mf/defc viewport
|
||||||
|
{::mf/wrap [mf/memo]
|
||||||
|
::mf/wrap-props false}
|
||||||
|
[props]
|
||||||
|
(let [;; NOTE: with `use-equal-memo` hook we ensure that all values
|
||||||
|
;; conserves the reference identity for avoid unnecesary dummy
|
||||||
|
;; rerenders.
|
||||||
|
mode (h/use-equal-memo (unchecked-get props "interactions-mode"))
|
||||||
|
offset (h/use-equal-memo (unchecked-get props "frame-offset"))
|
||||||
|
size (h/use-equal-memo (unchecked-get props "size"))
|
||||||
|
|
||||||
|
page (unchecked-get props "page")
|
||||||
|
frame (unchecked-get props "frame")
|
||||||
|
base (unchecked-get props "base-frame")]
|
||||||
|
|
||||||
|
(mf/with-effect [mode]
|
||||||
|
(let [on-click
|
||||||
(fn [_]
|
(fn [_]
|
||||||
(when (= interactions-mode :show-on-click)
|
(when (= mode :show-on-click)
|
||||||
(st/emit! dv/flash-interactions)))
|
(st/emit! (dv/flash-interactions))))
|
||||||
|
|
||||||
on-mouse-wheel
|
on-mouse-wheel
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(when (kbd/mod? event)
|
(when (kbd/mod? event)
|
||||||
(dom/prevent-default event)
|
(dom/prevent-default event)
|
||||||
(let [event (.getBrowserEvent ^js event)
|
(let [event (dom/event->browser-event event)
|
||||||
delta (+ (.-deltaY ^js event) (.-deltaX ^js event))]
|
delta (+ (.-deltaY ^js event)
|
||||||
|
(.-deltaX ^js event))]
|
||||||
(if (pos? delta)
|
(if (pos? delta)
|
||||||
(st/emit! dv/decrease-zoom)
|
(st/emit! dv/decrease-zoom)
|
||||||
(st/emit! dv/increase-zoom)))))
|
(st/emit! dv/increase-zoom)))))
|
||||||
|
@ -73,38 +108,29 @@
|
||||||
on-key-down
|
on-key-down
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(when (kbd/esc? event)
|
(when (kbd/esc? event)
|
||||||
(st/emit! (dcm/close-thread))))]
|
(st/emit! (dcm/close-thread))))
|
||||||
|
|
||||||
|
|
||||||
(mf/use-effect
|
|
||||||
(mf/deps interactions-mode) ;; on-click event depends on interactions-mode
|
|
||||||
(fn []
|
|
||||||
;; bind with passive=false to allow the event to be cancelled
|
;; bind with passive=false to allow the event to be cancelled
|
||||||
;; https://stackoverflow.com/a/57582286/3219895
|
;; https://stackoverflow.com/a/57582286/3219895
|
||||||
(let [key1 (events/listen goog/global "wheel" on-mouse-wheel #js {"passive" false})
|
key1 (events/listen goog/global "wheel" on-mouse-wheel #js {"passive" false})
|
||||||
key2 (events/listen js/window "keydown" on-key-down)
|
key2 (events/listen goog/global "keydown" on-key-down)
|
||||||
key3 (events/listen js/window "click" on-click)]
|
key3 (events/listen goog/global "click" on-click)]
|
||||||
(fn []
|
(fn []
|
||||||
(events/unlistenByKey key1)
|
(events/unlistenByKey key1)
|
||||||
(events/unlistenByKey key2)
|
(events/unlistenByKey key2)
|
||||||
(events/unlistenByKey key3)))))
|
(events/unlistenByKey key3))))
|
||||||
|
|
||||||
[:& (mf/provider shapes/base-frame-ctx) {:value base-frame}
|
|
||||||
[:& (mf/provider shapes/frame-offset-ctx) {:value frame-offset}
|
|
||||||
[:svg {:view-box (:vbox size)
|
|
||||||
:width (:width size)
|
|
||||||
:height (:height size)
|
|
||||||
:version "1.1"
|
|
||||||
:xmlnsXlink "http://www.w3.org/1999/xlink"
|
|
||||||
:xmlns "http://www.w3.org/2000/svg"
|
|
||||||
:fill "none"}
|
|
||||||
[:& wrapper {:shape frame
|
|
||||||
:view-box (:vbox size)}]]]]))
|
|
||||||
|
|
||||||
|
[:& viewport-svg {:page page
|
||||||
|
:frame frame
|
||||||
|
:base base
|
||||||
|
:offset offset
|
||||||
|
:size size}]))
|
||||||
|
|
||||||
(mf/defc flows-menu
|
(mf/defc flows-menu
|
||||||
{::mf/wrap [mf/memo]}
|
{::mf/wrap [mf/memo]}
|
||||||
[{:keys [page index]}]
|
[{:keys [page index]}]
|
||||||
(let [flows (get-in page [:options :flows])
|
(let [flows (dm/get-in page [:options :flows])
|
||||||
frames (:frames page)
|
frames (:frames page)
|
||||||
frame (get frames index)
|
frame (get frames index)
|
||||||
current-flow (mf/use-state
|
current-flow (mf/use-state
|
||||||
|
@ -135,7 +161,6 @@
|
||||||
[:span.icon i/tick]
|
[:span.icon i/tick]
|
||||||
[:span.label (:name flow)]])]]])))
|
[:span.label (:name flow)]])]]])))
|
||||||
|
|
||||||
|
|
||||||
(mf/defc interactions-menu
|
(mf/defc interactions-menu
|
||||||
[]
|
[]
|
||||||
(let [local (mf/deref refs/viewer-local)
|
(let [local (mf/deref refs/viewer-local)
|
||||||
|
|
|
@ -206,6 +206,9 @@
|
||||||
:style {:pointer-events (when frame? "none")}
|
:style {:pointer-events (when frame? "none")}
|
||||||
:transform (gsh/transform-str shape)}])))
|
:transform (gsh/transform-str shape)}])))
|
||||||
|
|
||||||
|
|
||||||
|
;; TODO: use-memo use-fn
|
||||||
|
|
||||||
(defn generic-wrapper-factory
|
(defn generic-wrapper-factory
|
||||||
"Wrap some svg shape and add interaction controls"
|
"Wrap some svg shape and add interaction controls"
|
||||||
[component]
|
[component]
|
||||||
|
@ -226,20 +229,37 @@
|
||||||
interactions (:interactions shape)
|
interactions (:interactions shape)
|
||||||
|
|
||||||
svg-element? (and (= :svg-raw (:type shape))
|
svg-element? (and (= :svg-raw (:type shape))
|
||||||
(not= :svg (get-in shape [:content :tag])))]
|
(not= :svg (get-in shape [:content :tag])))
|
||||||
|
|
||||||
(mf/use-effect
|
|
||||||
(fn []
|
on-mouse-down
|
||||||
|
(mf/use-fn (mf/deps shape base-frame frame-offset objects)
|
||||||
|
#(on-mouse-down % shape base-frame frame-offset objects))
|
||||||
|
|
||||||
|
on-mouse-up
|
||||||
|
(mf/use-fn (mf/deps shape base-frame frame-offset objects)
|
||||||
|
#(on-mouse-up % shape base-frame frame-offset objects))
|
||||||
|
|
||||||
|
on-mouse-enter
|
||||||
|
(mf/use-fn (mf/deps shape base-frame frame-offset objects)
|
||||||
|
#(on-mouse-enter % shape base-frame frame-offset objects))
|
||||||
|
|
||||||
|
on-mouse-leave
|
||||||
|
(mf/use-fn (mf/deps shape base-frame frame-offset objects)
|
||||||
|
#(on-mouse-leave % shape base-frame frame-offset objects))]
|
||||||
|
|
||||||
|
|
||||||
|
(mf/with-effect []
|
||||||
(let [sems (on-load shape base-frame frame-offset objects)]
|
(let [sems (on-load shape base-frame frame-offset objects)]
|
||||||
#(run! tm/dispose! sems))))
|
(partial run! tm/dispose! sems)))
|
||||||
|
|
||||||
(if-not svg-element?
|
(if-not svg-element?
|
||||||
[:> shape-container {:shape shape
|
[:> shape-container {:shape shape
|
||||||
:cursor (when (ctsi/actionable? interactions) "pointer")
|
:cursor (when (ctsi/actionable? interactions) "pointer")
|
||||||
:on-mouse-down #(on-mouse-down % shape base-frame frame-offset objects)
|
:on-mouse-down on-mouse-down
|
||||||
:on-mouse-up #(on-mouse-up % shape base-frame frame-offset objects)
|
:on-mouse-up on-mouse-up
|
||||||
:on-mouse-enter #(on-mouse-enter % shape base-frame frame-offset objects)
|
:on-mouse-enter on-mouse-enter
|
||||||
:on-mouse-leave #(on-mouse-leave % shape base-frame frame-offset objects)}
|
:on-mouse-leave on-mouse-leave}
|
||||||
|
|
||||||
[:& component {:shape shape
|
[:& component {:shape shape
|
||||||
:frame frame
|
:frame frame
|
||||||
|
@ -311,6 +331,7 @@
|
||||||
#js {:shape shape
|
#js {:shape shape
|
||||||
:childs childs
|
:childs childs
|
||||||
:objects objects})]
|
:objects objects})]
|
||||||
|
|
||||||
[:> frame-wrapper props]))))
|
[:> frame-wrapper props]))))
|
||||||
|
|
||||||
(defn group-container-factory
|
(defn group-container-factory
|
||||||
|
@ -362,31 +383,43 @@
|
||||||
image-wrapper (image-wrapper)
|
image-wrapper (image-wrapper)
|
||||||
circle-wrapper (circle-wrapper)]
|
circle-wrapper (circle-wrapper)]
|
||||||
(mf/fnc shape-container
|
(mf/fnc shape-container
|
||||||
{::mf/wrap-props false}
|
{::mf/wrap-props false
|
||||||
|
::mf/wrap [mf/memo]}
|
||||||
[props]
|
[props]
|
||||||
(let [scroll (mf/use-ctx ctx/scroll-ctx)
|
(let [shape (unchecked-get props "shape")
|
||||||
local (mf/deref refs/viewer-local)
|
|
||||||
zoom (:zoom local)
|
|
||||||
shape (unchecked-get props "shape")
|
|
||||||
parents (map (d/getf objects) (cph/get-parent-ids objects (:id shape)))
|
|
||||||
fixed? (or (:fixed-scroll shape) (some :fixed-scroll parents))
|
|
||||||
frame (unchecked-get props "frame")
|
frame (unchecked-get props "frame")
|
||||||
delta {:x (/ (:scroll-left scroll) zoom) :y (/ (:scroll-top scroll) zoom)}
|
|
||||||
|
;; TODO: this watch of scroll position is killing
|
||||||
|
;; performance of the viewer.
|
||||||
|
scroll (mf/use-ctx ctx/current-scroll)
|
||||||
|
zoom (mf/use-ctx ctx/current-zoom)
|
||||||
|
|
||||||
|
fixed? (mf/with-memo [shape objects]
|
||||||
|
(->> (cph/get-parent-ids objects (:id shape))
|
||||||
|
(map (d/getf objects))
|
||||||
|
(concat [shape])
|
||||||
|
(some :fixed-scroll)))
|
||||||
|
|
||||||
|
delta {:x (/ (:scroll-left scroll) zoom)
|
||||||
|
:y (/ (:scroll-top scroll) zoom)}
|
||||||
|
|
||||||
group-container
|
group-container
|
||||||
(mf/use-memo (mf/deps objects)
|
(mf/with-memo [objects]
|
||||||
#(group-container-factory objects))
|
(group-container-factory objects))
|
||||||
|
|
||||||
frame-container
|
frame-container
|
||||||
(mf/use-memo (mf/deps objects)
|
(mf/with-memo [objects]
|
||||||
#(frame-container-factory objects))
|
(frame-container-factory objects))
|
||||||
|
|
||||||
bool-container
|
bool-container
|
||||||
(mf/use-memo (mf/deps objects)
|
(mf/with-memo [objects]
|
||||||
#(bool-container-factory objects))
|
(bool-container-factory objects))
|
||||||
|
|
||||||
svg-raw-container
|
svg-raw-container
|
||||||
(mf/use-memo (mf/deps objects)
|
(mf/with-memo [objects]
|
||||||
#(svg-raw-container-factory objects))]
|
(svg-raw-container-factory objects))
|
||||||
|
|
||||||
|
]
|
||||||
(when (and shape (not (:hidden shape)))
|
(when (and shape (not (:hidden shape)))
|
||||||
(let [shape (-> (gsh/transform-shape shape)
|
(let [shape (-> (gsh/transform-shape shape)
|
||||||
(gsh/translate-to-frame frame)
|
(gsh/translate-to-frame frame)
|
||||||
|
@ -404,4 +437,3 @@
|
||||||
:group [:> group-container {:shape shape :frame frame :objects objects :fixed? fixed? :delta delta}]
|
:group [:> group-container {:shape shape :frame frame :objects objects :fixed? fixed? :delta delta}]
|
||||||
:bool [:> bool-container {:shape shape :frame frame :objects objects}]
|
:bool [:> bool-container {:shape shape :frame frame :objects objects}]
|
||||||
:svg-raw [:> svg-raw-container {:shape shape :frame frame :objects objects}])))))))
|
:svg-raw [:> svg-raw-container {:shape shape :frame frame :objects objects}])))))))
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
(mf/deps objects)
|
(mf/deps objects)
|
||||||
#(cph/objects-by-frame objects))]
|
#(cph/objects-by-frame objects))]
|
||||||
|
|
||||||
[:& (mf/provider ctx/active-frames-ctx) {:value active-frames}
|
[:& (mf/provider ctx/active-frames) {:value active-frames}
|
||||||
;; Render font faces only for shapes that are part of the root
|
;; Render font faces only for shapes that are part of the root
|
||||||
;; frame but don't belongs to any other frame.
|
;; frame but don't belongs to any other frame.
|
||||||
(let [xform (comp
|
(let [xform (comp
|
||||||
|
@ -79,7 +79,7 @@
|
||||||
(let [shape (obj/get props "shape")
|
(let [shape (obj/get props "shape")
|
||||||
|
|
||||||
active-frames
|
active-frames
|
||||||
(when (cph/root-frame? shape) (mf/use-ctx ctx/active-frames-ctx))
|
(when (cph/root-frame? shape) (mf/use-ctx ctx/active-frames))
|
||||||
|
|
||||||
thumbnail?
|
thumbnail?
|
||||||
(and (some? active-frames)
|
(and (some? active-frames)
|
||||||
|
|
|
@ -909,6 +909,17 @@
|
||||||
(seq (:colors selected-assets))
|
(seq (:colors selected-assets))
|
||||||
(seq (:typographies selected-assets)))
|
(seq (:typographies selected-assets)))
|
||||||
|
|
||||||
|
extract-path-if-missing
|
||||||
|
(fn [graphic]
|
||||||
|
(let [[path name] (cph/parse-path-name (:name graphic))]
|
||||||
|
(if (and
|
||||||
|
(= (:name graphic) name)
|
||||||
|
(contains? graphic :path))
|
||||||
|
graphic
|
||||||
|
(assoc graphic :path path :name name))))
|
||||||
|
|
||||||
|
objects (->> objects
|
||||||
|
(map extract-path-if-missing))
|
||||||
|
|
||||||
|
|
||||||
groups (group-assets objects reverse-sort?)
|
groups (group-assets objects reverse-sort?)
|
||||||
|
@ -1572,7 +1583,6 @@
|
||||||
(fn [event]
|
(fn [event]
|
||||||
(on-drop-asset-group event dragging? prefix selected-typographies-paths selected-typographies-full move-typography)))]
|
(on-drop-asset-group event dragging? prefix selected-typographies-paths selected-typographies-full move-typography)))]
|
||||||
|
|
||||||
|
|
||||||
[:div {:on-drag-enter on-drag-enter
|
[:div {:on-drag-enter on-drag-enter
|
||||||
:on-drag-leave on-drag-leave
|
:on-drag-leave on-drag-leave
|
||||||
:on-drag-over on-drag-over
|
:on-drag-over on-drag-over
|
||||||
|
@ -1598,6 +1608,7 @@
|
||||||
[:div.drop-space])
|
[:div.drop-space])
|
||||||
(for [typography typographies]
|
(for [typography typographies]
|
||||||
[:& typography-item {:typography typography
|
[:& typography-item {:typography typography
|
||||||
|
:key (dm/str (:id typography))
|
||||||
:file file
|
:file file
|
||||||
:local? local?
|
:local? local?
|
||||||
:handle-change handle-change
|
:handle-change handle-change
|
||||||
|
@ -1615,6 +1626,7 @@
|
||||||
(when-not (empty? path-item)
|
(when-not (empty? path-item)
|
||||||
[:& typographies-group {:file-id file-id
|
[:& typographies-group {:file-id file-id
|
||||||
:prefix (cph/merge-path-item prefix path-item)
|
:prefix (cph/merge-path-item prefix path-item)
|
||||||
|
:key (dm/str path-item)
|
||||||
:groups content
|
:groups content
|
||||||
:open-groups open-groups
|
:open-groups open-groups
|
||||||
:file file
|
:file file
|
||||||
|
@ -1642,7 +1654,9 @@
|
||||||
extract-path-if-missing
|
extract-path-if-missing
|
||||||
(fn [typography]
|
(fn [typography]
|
||||||
(let [[path name] (cph/parse-path-name (:name typography))]
|
(let [[path name] (cph/parse-path-name (:name typography))]
|
||||||
(if (= (:name typography) name)
|
(if (and
|
||||||
|
(= (:name typography) name)
|
||||||
|
(contains? typography :path))
|
||||||
typography
|
typography
|
||||||
(assoc typography :path path :name name))))
|
(assoc typography :path path :name name))))
|
||||||
|
|
||||||
|
@ -1957,13 +1971,11 @@
|
||||||
(fn [asset-type asset-groups asset-id]
|
(fn [asset-type asset-groups asset-id]
|
||||||
(letfn [(flatten-groups
|
(letfn [(flatten-groups
|
||||||
[groups]
|
[groups]
|
||||||
(concat
|
(reduce concat [(get groups "" [])
|
||||||
(get groups "" [])
|
|
||||||
(reduce concat
|
|
||||||
(into []
|
(into []
|
||||||
(->> (filter #(seq (first %)) groups)
|
(->> (filter #(seq (first %)) groups)
|
||||||
(map second)
|
(map second)
|
||||||
(mapcat flatten-groups))))))]
|
(mapcat flatten-groups)))]))]
|
||||||
(let [selected-assets-type (get selected-assets asset-type)
|
(let [selected-assets-type (get selected-assets asset-type)
|
||||||
count-assets (count selected-assets-type)]
|
count-assets (count selected-assets-type)]
|
||||||
(if (<= count-assets 0)
|
(if (<= count-assets 0)
|
||||||
|
|
|
@ -174,7 +174,9 @@
|
||||||
(fn [shape]
|
(fn [shape]
|
||||||
(if (ctsr/has-radius? shape)
|
(if (ctsr/has-radius? shape)
|
||||||
(update-fn shape)
|
(update-fn shape)
|
||||||
shape)))))
|
shape))
|
||||||
|
{:reg-objects? true
|
||||||
|
:attrs [:rx :ry :r1 :r2 :r3 :r4]})))
|
||||||
|
|
||||||
on-switch-to-radius-1
|
on-switch-to-radius-1
|
||||||
(mf/use-callback
|
(mf/use-callback
|
||||||
|
|
|
@ -469,25 +469,19 @@
|
||||||
(when-not (str/blank? name)
|
(when-not (str/blank? name)
|
||||||
(on-change {:name name})))))]
|
(on-change {:name name})))))]
|
||||||
|
|
||||||
(mf/use-effect
|
(mf/with-effect [editing?]
|
||||||
(mf/deps editing?)
|
|
||||||
(fn []
|
|
||||||
(when editing?
|
(when editing?
|
||||||
(reset! open? editing?))))
|
(reset! open? editing?)))
|
||||||
|
|
||||||
(mf/use-effect
|
(mf/with-effect [focus-name?]
|
||||||
(mf/deps focus-name?)
|
|
||||||
(fn []
|
|
||||||
(when focus-name?
|
(when focus-name?
|
||||||
(tm/schedule
|
(tm/schedule
|
||||||
#(when-let [node (mf/ref-val name-input-ref)]
|
#(when-let [node (mf/ref-val name-input-ref)]
|
||||||
(dom/focus! node)
|
(dom/focus! node)
|
||||||
(dom/select-text! node))))))
|
(dom/select-text! node)))))
|
||||||
|
|
||||||
(mf/use-effect
|
(mf/with-effect [on-change]
|
||||||
(mf/deps on-change)
|
(mf/set-ref-val! on-change-ref {:on-change on-change}))
|
||||||
(fn []
|
|
||||||
(mf/set-ref-val! on-change-ref {:on-change on-change})))
|
|
||||||
|
|
||||||
[:*
|
[:*
|
||||||
[:div.element-set-options-group.typography-entry
|
[:div.element-set-options-group.typography-entry
|
||||||
|
|
|
@ -37,6 +37,14 @@
|
||||||
(when (some? e)
|
(when (some? e)
|
||||||
(.-target e)))
|
(.-target e)))
|
||||||
|
|
||||||
|
(defn event->native-event
|
||||||
|
[^js e]
|
||||||
|
(.-nativeEvent e))
|
||||||
|
|
||||||
|
(defn event->browser-event
|
||||||
|
[^js e]
|
||||||
|
(.getBrowserEvent e))
|
||||||
|
|
||||||
;; --- New methods
|
;; --- New methods
|
||||||
|
|
||||||
(declare get-elements-by-tag)
|
(declare get-elements-by-tag)
|
||||||
|
|
Loading…
Add table
Reference in a new issue