mirror of
https://github.com/penpot/penpot.git
synced 2026-01-17 19:00:07 -05:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6519db82d1 | ||
|
|
0a60cbedb5 | ||
|
|
357fba5d2b | ||
|
|
6067e438a3 | ||
|
|
8affefbbab | ||
|
|
0225919a45 | ||
|
|
5155cf2b23 | ||
|
|
7403f60366 | ||
|
|
a8c34ccc1a | ||
|
|
8c501db2fa | ||
|
|
d2fbb9dfa7 | ||
|
|
05d6d2fcd4 | ||
|
|
61800d8945 | ||
|
|
f450c9dbe3 | ||
|
|
e3b3fa3342 |
42
CHANGES.md
42
CHANGES.md
@@ -1,28 +1,31 @@
|
||||
# CHANGELOG
|
||||
|
||||
## 2.5.3
|
||||
|
||||
### :rocket: Epics and highlights
|
||||
|
||||
### :boom: Breaking changes & Deprecations
|
||||
|
||||
### :heart: Community contributions (Thank you!)
|
||||
## 2.5.4
|
||||
|
||||
### :sparkles: New features
|
||||
|
||||
- Add support for WEBP format on shape export [Github #6053](https://github.com/penpot/penpot/pull/6053) and [Github #6074](https://github.com/penpot/penpot/pull/6074)
|
||||
|
||||
### :bug: Bugs fixed
|
||||
|
||||
- Fix feature loading on workspace when opening a file in a background
|
||||
tab [Taiga #10377](https://tree.taiga.io/project/penpot/issue/10377)
|
||||
- Fix minor inconsistencies on RPC `get-file-libraries` and `get-file`
|
||||
methods (add missing team-id prop)
|
||||
- Fix problem with viewer role and inspect mode [Taiga #9751](https://tree.taiga.io/project/penpot/issue/9751)
|
||||
- Fix error when clicking on a comment at the viewer's sidebar [Taiga #10465](https://tree.taiga.io/project/penpot/issue/10465)
|
||||
- Internal error when install a plugin by penpothub - Try plugin [Taiga #10542](https://tree.taiga.io/project/penpot/issue/10542)
|
||||
|
||||
## 2.5.3
|
||||
|
||||
### :bug: Bugs fixed
|
||||
|
||||
- Component sync issues with multiple tabs [Taiga #10471](https://tree.taiga.io/project/penpot/issue/10471)
|
||||
|
||||
## 2.5.2
|
||||
|
||||
### :rocket: Epics and highlights
|
||||
|
||||
### :boom: Breaking changes & Deprecations
|
||||
|
||||
### :heart: Community contributions (Thank you!)
|
||||
|
||||
### :sparkles: New features
|
||||
|
||||
- When the workspace is empty, set default the board creation tool [Taiga #9425](https://tree.taiga.io/project/penpot/us/9425)
|
||||
|
||||
### :bug: Bugs fixed
|
||||
@@ -34,22 +37,12 @@
|
||||
|
||||
## 2.5.1
|
||||
|
||||
### :rocket: Epics and highlights
|
||||
|
||||
### :boom: Breaking changes & Deprecations
|
||||
|
||||
### :heart: Community contributions (Thank you!)
|
||||
|
||||
### :sparkles: New features
|
||||
|
||||
- Improve Nginx entryponit to get the resolvers dinamically by default
|
||||
|
||||
### :bug: Bugs fixed
|
||||
|
||||
## 2.5.0
|
||||
|
||||
### :rocket: Epics and highlights
|
||||
|
||||
### :boom: Breaking changes & Deprecations
|
||||
|
||||
Although this is not a breaking change, we believe it’s important to highlight it in this
|
||||
@@ -78,9 +71,6 @@ If you have a big database and many cores available, you can reduce the time of
|
||||
all files by increasing paralelizacion changing the `max-jobs` value from 1 to N (where N
|
||||
is a number of cores)
|
||||
|
||||
|
||||
### :heart: Community contributions (Thank you!)
|
||||
|
||||
### :sparkles: New features
|
||||
|
||||
- [GRADIENTS] New gradients UI with multi-stop support. [Taiga #3418](https://tree.taiga.io/project/penpot/epic/3418)
|
||||
|
||||
@@ -323,6 +323,7 @@
|
||||
|
||||
file (-> (get-file cfg id :project-id project-id)
|
||||
(assoc :permissions perms)
|
||||
(assoc :team-id (:id team))
|
||||
(check-version!))]
|
||||
|
||||
(-> (cfeat/get-team-enabled-features cf/flags team)
|
||||
@@ -613,6 +614,7 @@
|
||||
SELECT l.id,
|
||||
l.features,
|
||||
l.project_id,
|
||||
p.team_id,
|
||||
l.created_at,
|
||||
l.modified_at,
|
||||
l.deleted_at,
|
||||
@@ -622,6 +624,7 @@
|
||||
l.synced_at,
|
||||
l.is_shared
|
||||
FROM libs AS l
|
||||
INNER JOIN project AS p ON (p.id = l.project_id)
|
||||
WHERE l.deleted_at IS NULL OR l.deleted_at > now();")
|
||||
|
||||
(defn get-file-libraries
|
||||
|
||||
@@ -1722,13 +1722,26 @@
|
||||
(pcb/update-shapes
|
||||
[shape-copy-id]
|
||||
(fn [shape-copy objects]
|
||||
(let [ids-map
|
||||
(let [component-page
|
||||
(ctf/get-component-page main-container main-component)
|
||||
|
||||
component-swap-children
|
||||
(->> shape-main
|
||||
:shapes
|
||||
(map #(get (:objects component-page) %))
|
||||
(filter #(some? (ctk/get-swap-slot %)))
|
||||
(group-by ctk/get-swap-slot))
|
||||
|
||||
ids-map
|
||||
(into {}
|
||||
(comp
|
||||
(map #(get objects %))
|
||||
(keep
|
||||
(fn [copy-shape]
|
||||
(let [main-shape (ctf/get-ref-shape main-container main-component copy-shape)]
|
||||
(let [main-shape
|
||||
(if (some? (ctk/get-swap-slot copy-shape))
|
||||
(first (get component-swap-children (ctk/get-swap-slot copy-shape)))
|
||||
(ctf/get-ref-shape main-container main-component copy-shape))]
|
||||
[(:id main-shape) (:id copy-shape)]))))
|
||||
(:shapes shape-copy))
|
||||
|
||||
@@ -1744,7 +1757,8 @@
|
||||
main-cells (-> shape-main (ctl/remap-grid-cells ids-map) :layout-grid-cells)]
|
||||
(-> shape-copy
|
||||
(assoc :layout-grid-cells
|
||||
(ctl/merge-cells copy-cells main-cells omit-touched?)))))
|
||||
(ctl/merge-cells main-cells copy-cells omit-touched?))
|
||||
(ctl/assign-cells objects))))
|
||||
{:ignore-touched true :with-objects? true})))
|
||||
|
||||
(defn- update-grid-main-attrs
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
(:require
|
||||
[app.common.schema :as sm]))
|
||||
|
||||
(def types #{:png :jpeg :svg :pdf})
|
||||
(def types #{:png :jpeg :webp :svg :pdf})
|
||||
|
||||
(def schema:export
|
||||
[:map {:title "ShapeExport"}
|
||||
|
||||
@@ -1643,15 +1643,10 @@
|
||||
untouched as possible"
|
||||
[target-cells source-cells omit-touched?]
|
||||
(if omit-touched?
|
||||
(letfn [(get-data [cells id]
|
||||
(dissoc (get cells id) :row :column :row-span :column-span))
|
||||
|
||||
(merge-cells [source-cell target-cell]
|
||||
(letfn [(merge-cells [source-cell target-cell]
|
||||
(-> source-cell
|
||||
(d/patch-object
|
||||
(dissoc target-cell :shapes :row :column :row-span :column-span))
|
||||
(cond-> (d/not-empty? (:shapes target-cell))
|
||||
(assoc :shapes (:shapes target-cell)))))]
|
||||
(dissoc target-cell :row :column :row-span :column-span))))]
|
||||
(let [deleted-cells
|
||||
(into #{}
|
||||
(filter #(not (contains? source-cells %)))
|
||||
@@ -1659,10 +1654,7 @@
|
||||
|
||||
touched-cells
|
||||
(into #{}
|
||||
(filter #(and
|
||||
(not (contains? deleted-cells %))
|
||||
(not= (get-data source-cells %)
|
||||
(get-data target-cells %))))
|
||||
(filter #(not (contains? deleted-cells %)))
|
||||
(keys target-cells))]
|
||||
|
||||
(->> touched-cells
|
||||
|
||||
@@ -489,6 +489,26 @@ PENPOT_STORAGE_ASSETS_S3_ENDPOINT: <endpoint-uri>
|
||||
These settings are equally useful if you have a Minio storage system.
|
||||
</p>
|
||||
|
||||
### Autosave
|
||||
|
||||
By default, Penpot stores manually saved versions indefinitely; these can be found in the History tab and can be renamed, restored, deleted, etc. Additionally, the default behavior of on-premise instances is to not keep automatic version history. This automatic behavior can be modified and adapted to each on-premise installation with the corresponding configuration.
|
||||
|
||||
<p class="advice">
|
||||
You need to be very careful when configuring automatic versioning, as it can significantly impact the size of your database. If you configure automatic versioning, you'll need to monitor this impact; if you're unsure about this management, we recommend leaving the default settings and using manual versioning.
|
||||
</p>
|
||||
|
||||
This is how configuration looks for auto-file-snapshot
|
||||
|
||||
```bash
|
||||
PENPOT_FLAGS: enable-auto-file-snapshot # Enable automatic version saving
|
||||
|
||||
# Backend
|
||||
PENPOT_AUTO_FILE_SNAPSHOT_EVERY: 5 # How many save operations trigger the auto-save-version?
|
||||
PENPOT_AUTO_FILE_SNAPSHOT_TIIMEOUT: "1h" # How often is an automatic save forced even if the `every` trigger is not met?
|
||||
```
|
||||
|
||||
Setting custom values for auto-file-snapshot does not change the behaviour for manual versions.
|
||||
|
||||
## Frontend
|
||||
|
||||
In comparison with backend, frontend only has a small number of runtime configuration
|
||||
|
||||
@@ -27,7 +27,7 @@ title: 07· Exporting objects
|
||||
<ul>
|
||||
<li><strong>Size</strong> - Options for the most common sizing scales.</li>
|
||||
<li><strong>Suffix</strong> - Especially useful if you are exporting at different scales.</li>
|
||||
<li><strong>File format</strong> - PNG, SVG, JPEG, PDF.</li>
|
||||
<li><strong>File format</strong> - PNG, JPEG, WEBP, SVG, PDF.</li>
|
||||
</ul>
|
||||
|
||||
<h2 id="export-multiple-elements">Exporting multiple elements</h2>
|
||||
|
||||
@@ -166,7 +166,7 @@ a design.</p>
|
||||
|
||||
<h2 id="curves">Curves (freehand)</h2>
|
||||
<p>The curve tool allows a path to be created directly in a freehand mode.
|
||||
Select the curve tool by clicking on the icon at the toolbar or pressing <kbd>Ctrl/⌘</kbd> + <kbd>c</kbd>.
|
||||
Select the curve tool by clicking on the icon at the toolbar or pressing <kbd>Shift/⇧</kbd> + <kbd>c</kbd>.
|
||||
<p>The path created will contain a lot of points, but it is edited the same way as any other curve.</p>
|
||||
|
||||
<h2 id="paths">Paths (bezier)</h2>
|
||||
@@ -206,7 +206,7 @@ You can choose to edit individual nodes or create new ones. Press <kbd>Esc</kbd>
|
||||
<h3>Insert images</h3>
|
||||
<p>There are several options for inserting an image into a Penpot file:</p>
|
||||
<ul>
|
||||
<li>Use the <strong>image tool</strong> at the toolbar or press <kbd>K</kbd> to inspect images in your file system.</li>
|
||||
<li>Use the <strong>image tool</strong> at the toolbar or press <kbd>K</kbd> to insert images in your file system.</li>
|
||||
<li><strong>Drag</strong> an image from your computer to the viewport.</li>
|
||||
<li>Copy an image & paste it or drag it right from a <strong>browser</strong>.</li>
|
||||
<li>Drag an image from a Penpot <strong>library</strong>.</li>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
(s/def ::name ::us/string)
|
||||
(s/def ::suffix ::us/string)
|
||||
(s/def ::type #{:jpeg :png :pdf :svg})
|
||||
(s/def ::type #{:png :jpeg :webp :pdf :svg})
|
||||
(s/def ::page-id ::us/uuid)
|
||||
(s/def ::file-id ::us/uuid)
|
||||
(s/def ::share-id ::us/uuid)
|
||||
@@ -40,6 +40,7 @@
|
||||
(case type
|
||||
:png (rb/render params on-object)
|
||||
:jpeg (rb/render params on-object)
|
||||
:webp (rb/render params on-object)
|
||||
:pdf (rp/render params on-object)
|
||||
:svg (rs/render params on-object)))
|
||||
|
||||
|
||||
@@ -34,7 +34,11 @@
|
||||
(bw/wait-for node)
|
||||
(case type
|
||||
:png (bw/screenshot node {:omit-background? true :type type :path path})
|
||||
:jpeg (bw/screenshot node {:omit-background? false :type type :path path}))
|
||||
:jpeg (bw/screenshot node {:omit-background? false :type type :path path})
|
||||
:webp (p/let [png-path (sh/tempfile :prefix "penpot.tmp.render.bitmap." :suffix ".png")]
|
||||
;; playwright only supports jpg and png, we need to convert it afterwards
|
||||
(bw/screenshot node {:omit-background? true :type :png :path png-path})
|
||||
(sh/run-cmd! (str "convert " png-path " -quality 100 WEBP:" path))))
|
||||
(on-object (assoc object :path path))))
|
||||
|
||||
(render [uri page]
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
(case type
|
||||
:png ".png"
|
||||
:jpeg ".jpg"
|
||||
:webp ".webp"
|
||||
:svg ".svg"
|
||||
:pdf ".pdf"
|
||||
:zip ".zip"))
|
||||
@@ -26,6 +27,7 @@
|
||||
:pdf "application/pdf"
|
||||
:svg "image/svg+xml"
|
||||
:jpeg "image/jpeg"
|
||||
:png "image/png"))
|
||||
:png "image/png"
|
||||
:webp "image/webp"))
|
||||
|
||||
|
||||
|
||||
@@ -38,7 +38,9 @@
|
||||
(declare process-message)
|
||||
|
||||
(defn initialize
|
||||
[]
|
||||
[team-id]
|
||||
(assert (uuid? team-id) "expected uuid instance for `team-id`")
|
||||
|
||||
(ptk/reify ::initialize
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
@@ -46,8 +48,8 @@
|
||||
profile-id (:profile-id state)]
|
||||
|
||||
(->> (rx/merge
|
||||
(rx/of (fetch-projects)
|
||||
(df/fetch-fonts))
|
||||
(rx/of (fetch-projects team-id)
|
||||
(df/fetch-fonts team-id))
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::dws/message))
|
||||
(rx/map deref)
|
||||
@@ -60,8 +62,8 @@
|
||||
(rx/take-until stopper))))))
|
||||
|
||||
(defn finalize
|
||||
[]
|
||||
(ptk/data-event ::finalize {}))
|
||||
[team-id]
|
||||
(ptk/data-event ::finalize {:team-id team-id}))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Data Fetching (context aware: current team)
|
||||
@@ -69,7 +71,7 @@
|
||||
|
||||
;; --- EVENT: fetch-projects
|
||||
|
||||
(defn projects-fetched
|
||||
(defn- projects-fetched
|
||||
[projects]
|
||||
(ptk/reify ::projects-fetched
|
||||
ptk/UpdateEvent
|
||||
@@ -80,13 +82,12 @@
|
||||
projects))))
|
||||
|
||||
(defn fetch-projects
|
||||
[]
|
||||
[team-id]
|
||||
(ptk/reify ::fetch-projects
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (:current-team-id state)]
|
||||
(->> (rp/cmd! :get-projects {:team-id team-id})
|
||||
(rx/map projects-fetched))))))
|
||||
(watch [_ _ _]
|
||||
(->> (rp/cmd! :get-projects {:team-id team-id})
|
||||
(rx/map projects-fetched)))))
|
||||
|
||||
;; --- EVENT: search
|
||||
|
||||
@@ -115,7 +116,7 @@
|
||||
|
||||
;; --- EVENT: recent-files
|
||||
|
||||
(defn recent-files-fetched
|
||||
(defn- recent-files-fetched
|
||||
[files]
|
||||
(ptk/reify ::recent-files-fetched
|
||||
ptk/UpdateEvent
|
||||
@@ -126,13 +127,14 @@
|
||||
(update :files d/merge files))))))
|
||||
|
||||
(defn fetch-recent-files
|
||||
[]
|
||||
(ptk/reify ::fetch-recent-files
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (:current-team-id state)]
|
||||
(->> (rp/cmd! :get-team-recent-files {:team-id team-id})
|
||||
(rx/map recent-files-fetched))))))
|
||||
([] (fetch-recent-files nil))
|
||||
([team-id]
|
||||
(ptk/reify ::fetch-recent-files
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(when-let [team-id (or team-id (:current-team-id state))]
|
||||
(->> (rp/cmd! :get-team-recent-files {:team-id team-id})
|
||||
(rx/map recent-files-fetched)))))))
|
||||
|
||||
;; --- EVENT: fetch-template-files
|
||||
|
||||
|
||||
@@ -266,10 +266,10 @@
|
||||
(defn export-shapes-event
|
||||
[exports origin]
|
||||
(let [types (reduce (fn [counts {:keys [type]}]
|
||||
(if (#{:png :pdf :svg :jpeg} type)
|
||||
(if (#{:png :jpeg :webp :svg :pdf} type)
|
||||
(update counts type inc)
|
||||
counts))
|
||||
{:png 0, :pdf 0, :svg 0, :jpeg 0}
|
||||
{:png 0, :jpeg 0, :webp 0, :pdf 0, :svg 0}
|
||||
exports)]
|
||||
(ptk/event
|
||||
::ev/event (merge types
|
||||
|
||||
@@ -73,13 +73,12 @@
|
||||
(fonts/register! :custom fonts))))))
|
||||
|
||||
(defn fetch-fonts
|
||||
[]
|
||||
(ptk/reify ::load-team-fonts
|
||||
[team-id]
|
||||
(ptk/reify ::fetch-fonts
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (:current-team-id state)]
|
||||
(->> (rp/cmd! :get-font-variants {:team-id team-id})
|
||||
(rx/map fonts-fetched))))))
|
||||
(watch [_ _ _]
|
||||
(->> (rp/cmd! :get-font-variants {:team-id team-id})
|
||||
(rx/map fonts-fetched)))))
|
||||
|
||||
(defn process-upload
|
||||
"Given a seq of blobs and the team id, creates a ready-to-use fonts
|
||||
|
||||
@@ -64,13 +64,14 @@
|
||||
(update :profiles merge (d/index-by :id members))))))
|
||||
|
||||
(defn fetch-members
|
||||
[]
|
||||
(ptk/reify ::fetch-members
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (:current-team-id state)]
|
||||
(->> (rp/cmd! :get-team-members {:team-id team-id})
|
||||
(rx/map (partial members-fetched team-id)))))))
|
||||
([] (fetch-members nil))
|
||||
([team-id]
|
||||
(ptk/reify ::fetch-members
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(when-let [team-id (or team-id (:current-team-id state))]
|
||||
(->> (rp/cmd! :get-team-members {:team-id team-id})
|
||||
(rx/map (partial members-fetched team-id))))))))
|
||||
|
||||
(defn- invitations-fetched
|
||||
[team-id invitations]
|
||||
@@ -88,41 +89,24 @@
|
||||
(->> (rp/cmd! :get-team-invitations {:team-id team-id})
|
||||
(rx/map (partial invitations-fetched team-id)))))))
|
||||
|
||||
(defn set-current-team
|
||||
[{:keys [id permissions features] :as team}]
|
||||
(ptk/reify ::set-current-team
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
;; FIXME: redundant operation, only necessary on workspace
|
||||
;; until workspace initialization is refactored
|
||||
(update-in [:teams id] merge team)
|
||||
(assoc :permissions permissions)
|
||||
;; FIXME: this is a redundant operation that only needed by
|
||||
;; workspace; ti will not be needed after workspace
|
||||
;; bootstrap & urls refactor
|
||||
(assoc :current-team-id id)))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(rx/of (features/initialize (or features #{}))))
|
||||
|
||||
ptk/EffectEvent
|
||||
(effect [_ _ _]
|
||||
(swap! storage/global assoc ::current-team-id id))))
|
||||
|
||||
(defn- team-initialized
|
||||
[]
|
||||
[team-id]
|
||||
(ptk/reify ::team-initialized
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(let [team-id (:current-team-id state)
|
||||
teams (get state :teams)
|
||||
team (get teams team-id)]
|
||||
(let [teams (get state :teams)
|
||||
team (get teams team-id)]
|
||||
(if (not team)
|
||||
(rx/throw (ex/error :type :authentication))
|
||||
(rx/of (set-current-team team)
|
||||
(fetch-members)))))))
|
||||
(let [permissions (get team :permissions)
|
||||
features (get team :features)]
|
||||
(rx/of #(assoc % :permissions permissions)
|
||||
(features/initialize (or features #{}))
|
||||
(fetch-members team-id))))))
|
||||
|
||||
ptk/EffectEvent
|
||||
(effect [_ _ _]
|
||||
(swap! storage/global assoc ::current-team-id team-id))))
|
||||
|
||||
(defn initialize-team
|
||||
[team-id]
|
||||
@@ -138,8 +122,7 @@
|
||||
(rx/of (fetch-teams))
|
||||
(->> stream
|
||||
(rx/filter (ptk/type? ::teams-fetched))
|
||||
(rx/observe-on :async)
|
||||
(rx/map team-initialized)))
|
||||
(rx/map (partial team-initialized team-id))))
|
||||
(rx/take-until stopper))))))
|
||||
|
||||
(defn finalize-team
|
||||
@@ -169,7 +152,7 @@
|
||||
params (assoc params :team-id team-id)]
|
||||
(->> (rp/cmd! :update-team-member-role params)
|
||||
(rx/mapcat (fn [_]
|
||||
(rx/of (fetch-members)
|
||||
(rx/of (fetch-members team-id)
|
||||
(fetch-teams)
|
||||
(ptk/data-event ::ev/event
|
||||
{::ev/name "update-team-member-role"
|
||||
@@ -187,7 +170,7 @@
|
||||
params (assoc params :team-id team-id)]
|
||||
(->> (rp/cmd! :delete-team-member params)
|
||||
(rx/mapcat (fn [_]
|
||||
(rx/of (fetch-members)
|
||||
(rx/of (fetch-members team-id)
|
||||
(fetch-teams)
|
||||
(ptk/data-event ::ev/event
|
||||
{::ev/name "delete-team-member"
|
||||
|
||||
@@ -291,7 +291,8 @@
|
||||
(watch [_ state stream]
|
||||
(let [features (features/get-team-enabled-features state)
|
||||
render-wasm? (contains? features "render-wasm/v1")
|
||||
stopper-s (rx/filter (ptk/type? ::finalize-workspace) stream)]
|
||||
stopper-s (rx/filter (ptk/type? ::finalize-workspace) stream)
|
||||
team-id (:current-team-id state)]
|
||||
|
||||
(->> (rx/concat
|
||||
;; Firstly load wasm module if it is enabled and fonts
|
||||
@@ -305,7 +306,7 @@
|
||||
(rx/filter (ptk/type? ::df/fonts-loaded))
|
||||
(rx/take 1)
|
||||
(rx/ignore))
|
||||
(rx/of (df/fetch-fonts)))
|
||||
(rx/of (df/fetch-fonts team-id)))
|
||||
|
||||
;; Then fetch file and thumbnails
|
||||
(->> (rx/zip (rp/cmd! :get-file {:id file-id :features features})
|
||||
@@ -335,7 +336,7 @@
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(log/debug :hint "initialize-workspace" :file-id file-id)
|
||||
(log/debug :hint "initialize-workspace" :file-id (dm/str file-id))
|
||||
(let [stoper-s (rx/filter (ptk/type? ::finalize-workspace) stream)
|
||||
rparams (rt/get-params state)]
|
||||
|
||||
|
||||
@@ -157,7 +157,8 @@
|
||||
(rt/nav :workspace
|
||||
{:page-id (dm/get-in data [:pages 0])
|
||||
:project-id project-id
|
||||
:file-id id})))
|
||||
:file-id id
|
||||
:team-id team-id})))
|
||||
|
||||
create-file!
|
||||
(fn [plugin]
|
||||
@@ -210,42 +211,45 @@
|
||||
(swap! storage/session dissoc :plugin-url))))))
|
||||
|
||||
(defn use-templates-import
|
||||
[can-edit? template-url default-project-id]
|
||||
(mf/with-layout-effect
|
||||
[can-edit? template-url default-project-id]
|
||||
(when (and (some? template-url) (some? default-project-id))
|
||||
(if can-edit?
|
||||
(let [valid-url? (and (str/ends-with? template-url ".penpot")
|
||||
(str/starts-with? template-url cf/templates-uri))
|
||||
template-name (when valid-url? (subs template-url (count cf/templates-uri)))
|
||||
on-import #(st/emit! (dpj/fetch-files default-project-id)
|
||||
(dd/fetch-recent-files)
|
||||
(dd/fetch-projects)
|
||||
(dd/clear-selected-files)
|
||||
(ptk/event ::ev/event {::ev/name "install-template-from-link-finished"
|
||||
:name template-name
|
||||
:url template-url}))]
|
||||
(if valid-url?
|
||||
(do
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "install-template-from-link" :name template-name :url template-url}))
|
||||
(->> (http/send! {:method :get
|
||||
:uri template-url
|
||||
:response-type :blob
|
||||
:omit-default-headers true})
|
||||
(rx/subs!
|
||||
(fn [result]
|
||||
(if (or (< (:status result) 200) (>= (:status result) 300))
|
||||
(st/emit! (notif/error (tr "dashboard.import.error")))
|
||||
(st/emit! (modal/show
|
||||
{:type :import
|
||||
:project-id default-project-id
|
||||
:entries [{:name template-name :uri (wapi/create-uri (:body result))}]
|
||||
:on-finish-import on-import})))))))
|
||||
(st/emit! (notif/error (tr "dashboard.import.bad-url")))))
|
||||
(st/emit! (notif/error (tr "dashboard.import.no-perms"))))
|
||||
[can-edit? template-url project]
|
||||
(let [project-id (get project :id)
|
||||
team-id (get project :team-id)]
|
||||
(mf/with-layout-effect [can-edit? template-url project-id team-id]
|
||||
(when (and (some? template-url)
|
||||
(some? project-id)
|
||||
(some? team-id))
|
||||
(if can-edit?
|
||||
(let [valid-url? (and (str/ends-with? template-url ".penpot")
|
||||
(str/starts-with? template-url cf/templates-uri))
|
||||
template-name (when valid-url? (subs template-url (count cf/templates-uri)))
|
||||
on-import #(st/emit! (dpj/fetch-files project-id)
|
||||
(dd/fetch-recent-files team-id)
|
||||
(dd/fetch-projects team-id)
|
||||
(dd/clear-selected-files)
|
||||
(ptk/event ::ev/event {::ev/name "install-template-from-link-finished"
|
||||
:name template-name
|
||||
:url template-url}))]
|
||||
(if valid-url?
|
||||
(do
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "install-template-from-link" :name template-name :url template-url}))
|
||||
(->> (http/send! {:method :get
|
||||
:uri template-url
|
||||
:response-type :blob
|
||||
:omit-default-headers true})
|
||||
(rx/subs!
|
||||
(fn [result]
|
||||
(if (or (< (:status result) 200) (>= (:status result) 300))
|
||||
(st/emit! (notif/error (tr "dashboard.import.error")))
|
||||
(st/emit! (modal/show
|
||||
{:type :import
|
||||
:project-id project-id
|
||||
:entries [{:name template-name :uri (wapi/create-uri (:body result))}]
|
||||
:on-finish-import on-import})))))))
|
||||
(st/emit! (notif/error (tr "dashboard.import.bad-url")))))
|
||||
(st/emit! (notif/error (tr "dashboard.import.no-perms"))))
|
||||
|
||||
(binding [storage/*sync* true]
|
||||
(swap! storage/session dissoc :template-url)))))
|
||||
(binding [storage/*sync* true]
|
||||
(swap! storage/session dissoc :template-url))))))
|
||||
|
||||
(mf/defc dashboard*
|
||||
{::mf/props :obj}
|
||||
@@ -270,10 +274,10 @@
|
||||
|
||||
(hooks/use-shortcuts ::dashboard sc/shortcuts)
|
||||
|
||||
(mf/with-effect []
|
||||
(st/emit! (dd/initialize))
|
||||
(mf/with-effect [team-id]
|
||||
(st/emit! (dd/initialize team-id))
|
||||
(fn []
|
||||
(st/emit! (dd/finalize))))
|
||||
(st/emit! (dd/finalize team-id))))
|
||||
|
||||
(mf/with-effect []
|
||||
(let [key (events/listen goog/global "keydown"
|
||||
@@ -285,7 +289,7 @@
|
||||
(events/unlistenByKey key))))
|
||||
|
||||
(use-plugin-register plugin-url team-id (:id default-project))
|
||||
(use-templates-import can-edit? template-url (:id default-project))
|
||||
(use-templates-import can-edit? template-url default-project)
|
||||
|
||||
[:& (mf/provider ctx/current-project-id) {:value project-id}
|
||||
[:> modal-container*]
|
||||
|
||||
@@ -133,7 +133,7 @@
|
||||
(st/emit! (dcm/go-to-dashboard-files
|
||||
{:project-id project-id
|
||||
:team-id team-id}))
|
||||
(st/emit! (dd/fetch-recent-files)
|
||||
(st/emit! (dd/fetch-recent-files team-id)
|
||||
(dd/clear-selected-files))))
|
||||
|
||||
on-move-accept
|
||||
|
||||
@@ -566,8 +566,9 @@
|
||||
|
||||
on-finish-import
|
||||
(mf/use-fn
|
||||
(mf/deps team-id)
|
||||
(fn []
|
||||
(st/emit! (dd/fetch-recent-files)
|
||||
(st/emit! (dd/fetch-recent-files team-id)
|
||||
(dd/clear-selected-files))))
|
||||
|
||||
import-files (use-import-file project-id on-finish-import)
|
||||
@@ -608,9 +609,10 @@
|
||||
|
||||
on-drop-success
|
||||
(mf/use-fn
|
||||
(mf/deps team-id)
|
||||
(fn []
|
||||
(st/emit! (ntf/success (tr "dashboard.success-move-file"))
|
||||
(dd/fetch-recent-files)
|
||||
(dd/fetch-recent-files team-id)
|
||||
(dd/clear-selected-files))))
|
||||
|
||||
on-drop
|
||||
|
||||
@@ -344,11 +344,13 @@
|
||||
|
||||
continue-template
|
||||
(mf/use-fn
|
||||
(mf/deps on-finish-import)
|
||||
(fn [template]
|
||||
(let [on-success
|
||||
(fn [_event]
|
||||
(reset! status* :import-success)
|
||||
(st/emit! (dd/fetch-recent-files)))
|
||||
(when (fn? on-finish-import)
|
||||
(on-finish-import)))
|
||||
|
||||
on-error
|
||||
(fn [cause]
|
||||
@@ -479,8 +481,6 @@
|
||||
[:> import-entry* {:entry (assoc template :status status)
|
||||
:can-be-deleted false}])]
|
||||
|
||||
;; (prn "import-dialog" status)
|
||||
|
||||
[:div {:class (stl/css :modal-footer)}
|
||||
[:div {:class (stl/css :action-buttons)}
|
||||
(when (= :analyze status)
|
||||
|
||||
@@ -105,7 +105,8 @@
|
||||
[{:keys [project is-first team files can-edit]}]
|
||||
(let [locale (mf/deref i18n/locale)
|
||||
|
||||
project-id (:id project)
|
||||
project-id (get project :id)
|
||||
team-id (get team :id)
|
||||
|
||||
file-count (or (:count project) 0)
|
||||
is-draft? (:is-default project)
|
||||
@@ -191,11 +192,11 @@
|
||||
|
||||
on-import
|
||||
(mf/use-fn
|
||||
(mf/deps project-id)
|
||||
(mf/deps project-id team-id)
|
||||
(fn []
|
||||
(st/emit! (dpj/fetch-files project-id)
|
||||
(dd/fetch-recent-files)
|
||||
(dd/fetch-projects)
|
||||
(dd/fetch-recent-files team-id)
|
||||
(dd/fetch-projects team-id)
|
||||
(dd/clear-selected-files))))
|
||||
|
||||
handle-create-click
|
||||
@@ -317,6 +318,8 @@
|
||||
(sort-by :modified-at)
|
||||
(reverse)))
|
||||
|
||||
team-id (get team :id)
|
||||
|
||||
recent-map (mf/deref ref:recent-files)
|
||||
permisions (:permissions team)
|
||||
|
||||
@@ -327,7 +330,7 @@
|
||||
show-team-hero* (mf/use-state #(get storage/global ::show-team-hero true))
|
||||
show-team-hero? (deref show-team-hero*)
|
||||
|
||||
is-my-penpot (= (:default-team-id profile) (:id team))
|
||||
is-my-penpot (= (:default-team-id profile) team-id)
|
||||
is-defalt-team? (:is-default team)
|
||||
|
||||
on-close
|
||||
@@ -346,8 +349,8 @@
|
||||
(:name team))]
|
||||
(dom/set-html-title (tr "title.dashboard.projects" tname))))
|
||||
|
||||
(mf/with-effect []
|
||||
(st/emit! (dd/fetch-recent-files)
|
||||
(mf/with-effect [team-id]
|
||||
(st/emit! (dd/fetch-recent-files team-id)
|
||||
(dd/clear-selected-files)))
|
||||
|
||||
(when (seq projects)
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
[template team-id project-id default-project-id section]
|
||||
(letfn [(on-finish []
|
||||
(st/emit!
|
||||
(dd/fetch-recent-files team-id)
|
||||
(ptk/event ::ev/event {::ev/name "import-template-finish"
|
||||
::ev/origin "dashboard"
|
||||
:template (:name template)
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
scale-enabled?
|
||||
(mf/use-callback
|
||||
(fn [export]
|
||||
(#{:png :jpeg} (:type export))))
|
||||
(#{:png :jpeg :webp} (:type export))))
|
||||
|
||||
in-progress? (:in-progress xstate)
|
||||
|
||||
@@ -123,6 +123,7 @@
|
||||
|
||||
format-options [{:value "png" :label "PNG"}
|
||||
{:value "jpeg" :label "JPG"}
|
||||
{:value "webp" :label "WEBP"}
|
||||
{:value "svg" :label "SVG"}
|
||||
{:value "pdf" :label "PDF"}]]
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
|
||||
.element-group {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(8, 1fr);
|
||||
grid-template-columns: repeat(9, 1fr);
|
||||
column-gap: $s-4;
|
||||
.action-btn {
|
||||
@extend .button-tertiary;
|
||||
@@ -64,13 +64,13 @@
|
||||
}
|
||||
|
||||
.input-wrapper {
|
||||
grid-column: span 7;
|
||||
grid-column: span 8;
|
||||
display: grid;
|
||||
grid-template-columns: subgrid;
|
||||
}
|
||||
|
||||
.format-select {
|
||||
grid-column: span 2;
|
||||
grid-column: span 3;
|
||||
padding: 0;
|
||||
|
||||
.dropdown-upwards {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.main.data.comments :as dcmt]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.data.workspace.comments :as dwcm]
|
||||
[app.main.refs :as refs]
|
||||
@@ -112,9 +113,11 @@
|
||||
|
||||
on-thread-click
|
||||
(mf/use-fn
|
||||
(mf/deps page-id)
|
||||
(mf/deps page-id from-viewer)
|
||||
(fn [thread]
|
||||
(st/emit! (dwcm/navigate-to-comment thread))))]
|
||||
(if from-viewer
|
||||
(st/emit! (with-meta (dcmt/open-thread thread) {::ev/origin "viewer"}))
|
||||
(st/emit! (dwcm/navigate-to-comment thread)))))]
|
||||
|
||||
[:div {:class (stl/css-case :comments-section true
|
||||
:from-viewer from-viewer)}
|
||||
|
||||
@@ -568,7 +568,6 @@
|
||||
[{:keys [starting-tab file-id] :as props :or {starting-tab :libraries}}]
|
||||
(let [files (mf/deref refs/files)
|
||||
file (get files file-id)
|
||||
team-id (:team-id file)
|
||||
shared? (:is-shared file)
|
||||
|
||||
linked-libraries
|
||||
@@ -616,8 +615,8 @@
|
||||
:id "updates"
|
||||
:content updates-tab}]]
|
||||
|
||||
(mf/with-effect [team-id]
|
||||
(st/emit! (dtm/fetch-shared-files team-id)))
|
||||
(mf/with-effect []
|
||||
(st/emit! (dtm/fetch-shared-files)))
|
||||
|
||||
[:div {:class (stl/css :modal-overlay)
|
||||
:on-click close-dialog-outside
|
||||
|
||||
@@ -197,16 +197,25 @@
|
||||
:id "inspect"
|
||||
:content inspect-content}])]
|
||||
|
||||
(mf/with-effect [permissions]
|
||||
(when-not (:can-edit permissions)
|
||||
(on-change-tab :inspect)))
|
||||
|
||||
[:div {:class (stl/css :tool-window)}
|
||||
[:> tab-switcher* {:tabs tabs
|
||||
:default-selected "info"
|
||||
:on-change-tab on-change-tab
|
||||
:selected (name options-mode)
|
||||
:class (stl/css :options-tab-switcher)}]]))
|
||||
(if (:can-edit permissions)
|
||||
[:> tab-switcher* {:tabs tabs
|
||||
:default-selected "info"
|
||||
:on-change-tab on-change-tab
|
||||
:selected (name options-mode)
|
||||
:class (stl/css :options-tab-switcher)}]
|
||||
|
||||
[:div {:class (stl/css-case :element-options true
|
||||
:inspect-options true
|
||||
:read-only true)}
|
||||
[:& hrs/right-sidebar {:page-id page-id
|
||||
:objects objects
|
||||
:file-id file-id
|
||||
:frame shape-parent-frame
|
||||
:shapes selected-shapes
|
||||
:on-change-section on-change-section
|
||||
:on-expand on-expand
|
||||
:from :workspace}]])]))
|
||||
|
||||
;; TODO: this need optimizations, selected-objects and
|
||||
;; selected-objects-with-children are derefed always but they only
|
||||
|
||||
@@ -33,6 +33,11 @@
|
||||
padding-top: $s-8;
|
||||
}
|
||||
|
||||
.read-only {
|
||||
grid-template-areas: "right-sidebar";
|
||||
padding: var(--sp-s);
|
||||
}
|
||||
|
||||
.design-options,
|
||||
.interaction-options {
|
||||
overflow: auto;
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
scale-enabled?
|
||||
(mf/use-fn
|
||||
(fn [export]
|
||||
(#{:png :jpeg} (:type export))))
|
||||
(#{:png :jpeg :webp} (:type export))))
|
||||
|
||||
on-download
|
||||
(mf/use-fn
|
||||
@@ -173,6 +173,7 @@
|
||||
|
||||
format-options [{:value "png" :label "PNG"}
|
||||
{:value "jpeg" :label "JPG"}
|
||||
{:value "webp" :label "WEBP"}
|
||||
{:value "svg" :label "SVG"}
|
||||
{:value "pdf" :label "PDF"}]]
|
||||
|
||||
|
||||
@@ -32,18 +32,18 @@
|
||||
|
||||
.element-group {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(8, 1fr);
|
||||
grid-template-columns: repeat(9, 1fr);
|
||||
column-gap: $s-4;
|
||||
}
|
||||
|
||||
.input-wrapper {
|
||||
grid-column: span 7;
|
||||
grid-column: span 8;
|
||||
display: grid;
|
||||
grid-template-columns: subgrid;
|
||||
}
|
||||
|
||||
.format-select {
|
||||
grid-column: span 2;
|
||||
grid-column: span 3;
|
||||
padding: 0;
|
||||
|
||||
.dropdown-upwards {
|
||||
|
||||
@@ -231,7 +231,7 @@
|
||||
show-selrect? (and selrect (empty? drawing) (not text-editing?))
|
||||
show-measures? (and (not transform)
|
||||
(not node-editing?)
|
||||
(or show-distances? mode-inspect?))
|
||||
(or show-distances? mode-inspect? read-only?))
|
||||
show-artboard-names? (contains? layout :display-artboard-names)
|
||||
hide-ui? (contains? layout :hide-ui)
|
||||
show-rulers? (and (contains? layout :rulers) (not hide-ui?))
|
||||
|
||||
@@ -261,7 +261,7 @@
|
||||
:hidden hidden})))
|
||||
|
||||
;; export interface Export {
|
||||
;; type: 'png' | 'jpeg' | 'svg' | 'pdf';
|
||||
;; type: 'png' | 'jpeg' | 'webp' | 'svg' | 'pdf';
|
||||
;; scale: number;
|
||||
;; suffix: string;
|
||||
;; }
|
||||
|
||||
@@ -243,7 +243,7 @@
|
||||
|
||||
|
||||
;; export interface Export {
|
||||
;; type: 'png' | 'jpeg' | 'svg' | 'pdf';
|
||||
;; type: 'png' | 'jpeg' | 'webp' | 'svg' | 'pdf';
|
||||
;; scale: number;
|
||||
;; suffix: string;
|
||||
;; }
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
[app.common.types.components-list :as ctkl]
|
||||
[app.common.uri :as u]
|
||||
[app.main.data.fonts :as df]
|
||||
[app.main.data.team :as dtm]
|
||||
[app.main.features :as features]
|
||||
[app.main.render :as render]
|
||||
[app.main.repo :as repo]
|
||||
@@ -30,6 +29,20 @@
|
||||
|
||||
(log/setup! {:app :info})
|
||||
|
||||
(defn set-current-team
|
||||
[{:keys [id permissions features] :as team}]
|
||||
(ptk/reify ::set-current-team
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(-> state
|
||||
(assoc :permissions permissions)
|
||||
(update :teams assoc id team)
|
||||
(assoc :current-team-id id)))
|
||||
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(rx/of (features/initialize (or features #{}))))))
|
||||
|
||||
(defn- fetch-team
|
||||
[& {:keys [file-id]}]
|
||||
(ptk/reify ::fetch-team
|
||||
@@ -37,7 +50,7 @@
|
||||
(watch [_ _ _]
|
||||
(->> (repo/cmd! :get-team {:file-id file-id})
|
||||
(rx/mapcat (fn [team]
|
||||
(rx/of (dtm/set-current-team team)
|
||||
(rx/of (set-current-team team)
|
||||
(ptk/data-event ::team-fetched team))))))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
Reference in New Issue
Block a user