mirror of
https://github.com/penpot/penpot.git
synced 2026-01-04 12:28:52 -05:00
Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
44bc4b7fa4 | ||
|
|
5c14f486d7 | ||
|
|
0cbd980b68 | ||
|
|
2e726b62c3 | ||
|
|
b68c426cd1 | ||
|
|
d00de7d5a4 | ||
|
|
2fbd4b07e0 | ||
|
|
523373dfa2 | ||
|
|
b71ec4bfe0 | ||
|
|
51107c3fc9 | ||
|
|
abef9f3cf7 | ||
|
|
40c300fa1a | ||
|
|
5b704faf79 | ||
|
|
d24eab7241 | ||
|
|
c8fef97598 | ||
|
|
44e3e4a641 | ||
|
|
f3616c68a0 | ||
|
|
9ea3f81bc4 | ||
|
|
accd5226d7 | ||
|
|
16a1fd14e5 | ||
|
|
824bb19c7e | ||
|
|
d0f3e0f0b0 | ||
|
|
43ba2b05e8 | ||
|
|
d5ccb704b2 | ||
|
|
6d21fcc9de | ||
|
|
77741b49a7 | ||
|
|
a7e0cfc609 | ||
|
|
50a6355537 | ||
|
|
264aef277d | ||
|
|
78d0e6d059 | ||
|
|
6d41d36b3a |
9
.github/workflows/build-bundles.yml
vendored
9
.github/workflows/build-bundles.yml
vendored
@@ -15,6 +15,7 @@ on:
|
||||
# zip_mode defines how the build artifacts are packaged:
|
||||
# - 'individual': creates one ZIP file per component (frontend, backend, exporter)
|
||||
# - 'all': creates a single ZIP containing all components
|
||||
# - null: for the rest of cases (non-manual events)
|
||||
description: 'Bundle packaging mode'
|
||||
required: false
|
||||
default: 'individual'
|
||||
@@ -62,8 +63,8 @@ jobs:
|
||||
echo "📦 Packaging Penpot 'all' bundles..."
|
||||
zip -r zips/penpot-all-bundles.zip penpot
|
||||
|
||||
- name: Create zip bundles for zip_mode == 'individual'
|
||||
if: ${{ github.event.inputs.zip_mode == 'individual' }}
|
||||
- name: Create zip bundles for zip_mode != 'all'
|
||||
if: ${{ github.event.inputs.zip_mode != 'all' }}
|
||||
run: |
|
||||
echo "📦 Packaging Penpot 'individual' bundles..."
|
||||
zip -r zips/penpot-frontend.zip penpot/frontend
|
||||
@@ -78,7 +79,7 @@ jobs:
|
||||
path: zips/penpot-all-bundles.zip
|
||||
|
||||
- name: Upload individual bundles
|
||||
if: ${{ github.event.inputs.zip_mode == 'individual' }}
|
||||
if: ${{ github.event.inputs.zip_mode != 'all' }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: penpot-individual-bundles
|
||||
@@ -94,7 +95,7 @@ jobs:
|
||||
aws s3 cp zips/penpot-all-bundles.zip s3://${{ secrets.S3_BUCKET }}/penpot-all-bundles-${{ steps.vars.outputs.commit_hash }}.zip
|
||||
|
||||
- name: Upload 'individual' bundles to S3
|
||||
if: ${{ github.event.inputs.zip_mode == 'individual' }}
|
||||
if: ${{ github.event.inputs.zip_mode != 'all' }}
|
||||
run: |
|
||||
for name in penpot-frontend penpot-backend penpot-exporter; do
|
||||
aws s3 cp zips/${name}.zip s3://${{ secrets.S3_BUCKET }}/${name}-${{ steps.vars.outputs.gh_branch }}-latest.zip
|
||||
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -41,6 +41,7 @@
|
||||
/backend/resources/public/assets
|
||||
/backend/resources/public/media
|
||||
/backend/target/
|
||||
/backend/experiments
|
||||
/bundle*
|
||||
/cd.md
|
||||
/clj-profiler/
|
||||
@@ -51,9 +52,6 @@
|
||||
/exporter/target
|
||||
/frontend/.storybook/preview-body.html
|
||||
/frontend/.storybook/preview-head.html
|
||||
/frontend/cypress/fixtures/validuser.json
|
||||
/frontend/cypress/videos/*/
|
||||
/frontend/cypress/videos/*/
|
||||
/frontend/dist/
|
||||
/frontend/npm-debug.log
|
||||
/frontend/out/
|
||||
@@ -70,6 +68,8 @@
|
||||
/vendor/svgclean/bundle*.js
|
||||
/web
|
||||
/library/target/
|
||||
/library/*.zip
|
||||
/external
|
||||
|
||||
clj-profiler/
|
||||
node_modules
|
||||
|
||||
17
CHANGES.md
17
CHANGES.md
@@ -1,6 +1,15 @@
|
||||
# CHANGELOG
|
||||
|
||||
## 2.8.0 (Next / Unreleased)
|
||||
## 2.8.1
|
||||
|
||||
### :bug: Bugs fixed
|
||||
|
||||
- Fix unexpected exception on processing old texts [Github #6889](https://github.com/penpot/penpot/pull/6889)
|
||||
- Fix error on inspect tab when selecting multiple shapes [Taiga #11655](https://tree.taiga.io/project/penpot/issue/11655)
|
||||
- Fix missing package for the penport_exporter Docker image [GitHub #7205](https://github.com/penpot/penpot/issues/7025)
|
||||
|
||||
|
||||
## 2.8.0
|
||||
|
||||
### :rocket: Epics and highlights
|
||||
|
||||
@@ -15,8 +24,8 @@ on [its own changelog](library/CHANGES.md)
|
||||
**Penpot migrate from Redis to Valkey**
|
||||
|
||||
As [Valkey](https://valkey.io/) is an opne-souce fork of [Redis](https://redis.io/)
|
||||
version 7.2.4, this version of Penpot will be compatible with Redis but may diverge
|
||||
in future versions. Therefore, **migration from Redis to ValKey is recommended for all
|
||||
version 7.2.4, this version of Penpot will be compatible with Redis but may diverge
|
||||
in future versions. Therefore, **migration from Redis to ValKey is recommended for all
|
||||
on-premises instances** that want to keep up to date.
|
||||
|
||||
### :heart: Community contributions (Thank you!)
|
||||
@@ -39,6 +48,7 @@ on-premises instances** that want to keep up to date.
|
||||
- Update google fonts (at 2025/05/19) [Taiga 10792](https://tree.taiga.io/project/penpot/us/10792)
|
||||
- Add tooltip component to DS [Taiga 9220](https://tree.taiga.io/project/penpot/us/9220)
|
||||
- Allow multi file token export [Taiga #10144](https://tree.taiga.io/project/penpot/us/10144)
|
||||
- Fix problem when double click on hidden shapes [Taiga #11314](https://tree.taiga.io/project/penpot/issue/11314)
|
||||
|
||||
### :bug: Bugs fixed
|
||||
|
||||
@@ -62,6 +72,7 @@ on-premises instances** that want to keep up to date.
|
||||
- Fix entering long project name [Taiga #11417](https://tree.taiga.io/project/penpot/issue/11417)
|
||||
- Fix slow color picker [Taiga #11019](https://tree.taiga.io/project/penpot/issue/11019)
|
||||
- Fix tooltip position after click [Taiga #11405](https://tree.taiga.io/project/penpot/issue/11405)
|
||||
- Fix incorrect media translation on paste text with fill images [Github #6845](https://github.com/penpot/penpot/pull/6845)
|
||||
|
||||
## 2.7.2
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
[app.binfile.common :as bfc]
|
||||
[app.binfile.migrations :as bfm]
|
||||
[app.common.data :as d]
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.exceptions :as ex]
|
||||
[app.common.features :as cfeat]
|
||||
[app.common.files.migrations :as-alias fmg]
|
||||
@@ -54,7 +53,7 @@
|
||||
[:map {:title "Manifest"}
|
||||
[:version ::sm/int]
|
||||
[:type :string]
|
||||
|
||||
[:referer {:optional true} :string]
|
||||
[:generated-by {:optional true} :string]
|
||||
|
||||
[:files
|
||||
@@ -373,6 +372,7 @@
|
||||
params {:type "penpot/export-files"
|
||||
:version 1
|
||||
:generated-by (str "penpot/" (:full cf/version))
|
||||
:refer "penpot"
|
||||
:files (vec (vals files))
|
||||
:relations rels}]
|
||||
(write-entry! output "manifest.json" params))))
|
||||
@@ -878,13 +878,8 @@
|
||||
(defn- import-files
|
||||
[{:keys [::bfc/timestamp ::bfc/input ::bfc/name] :or {timestamp (dt/now)} :as cfg}]
|
||||
|
||||
(dm/assert!
|
||||
"expected zip file"
|
||||
(instance? ZipFile input))
|
||||
|
||||
(dm/assert!
|
||||
"expected valid instant"
|
||||
(dt/instant? timestamp))
|
||||
(assert (instance? ZipFile input) "expected zip file")
|
||||
(assert (dt/instant? timestamp) "expected valid instant")
|
||||
|
||||
(let [manifest (-> (read-manifest input)
|
||||
(validate-manifest))
|
||||
@@ -896,6 +891,7 @@
|
||||
:hint "unexpected type on manifest"
|
||||
:manifest manifest))
|
||||
|
||||
|
||||
;; Check if all files referenced on manifest are present
|
||||
(doseq [{file-id :id features :features} (:files manifest)]
|
||||
(let [path (str "files/" file-id ".json")]
|
||||
@@ -956,14 +952,13 @@
|
||||
|
||||
[{:keys [::bfc/ids] :as cfg} output]
|
||||
|
||||
(dm/assert!
|
||||
"expected a set of uuid's for `::bfc/ids` parameter"
|
||||
(and (set? ids)
|
||||
(every? uuid? ids)))
|
||||
(assert
|
||||
(and (set? ids) (every? uuid? ids))
|
||||
"expected a set of uuid's for `::bfc/ids` parameter")
|
||||
|
||||
(dm/assert!
|
||||
"expected instance of jio/IOFactory for `input`"
|
||||
(satisfies? jio/IOFactory output))
|
||||
(assert
|
||||
(satisfies? jio/IOFactory output)
|
||||
"expected instance of jio/IOFactory for `input`")
|
||||
|
||||
(let [id (uuid/next)
|
||||
tp (dt/tpoint)
|
||||
@@ -1002,14 +997,14 @@
|
||||
(defn import-files!
|
||||
[{:keys [::bfc/input] :as cfg}]
|
||||
|
||||
(dm/assert!
|
||||
"expected valid profile-id and project-id on `cfg`"
|
||||
(assert
|
||||
(and (uuid? (::bfc/profile-id cfg))
|
||||
(uuid? (::bfc/project-id cfg))))
|
||||
(uuid? (::bfc/project-id cfg)))
|
||||
"expected valid profile-id and project-id on `cfg`")
|
||||
|
||||
(dm/assert!
|
||||
"expected instance of jio/IOFactory for `input`"
|
||||
(io/coercible? input))
|
||||
(assert
|
||||
(io/coercible? input)
|
||||
"expected instance of jio/IOFactory for `input`")
|
||||
|
||||
(let [id (uuid/next)
|
||||
tp (dt/tpoint)
|
||||
@@ -1029,3 +1024,9 @@
|
||||
:id (str id)
|
||||
:elapsed (dt/format-duration (tp))
|
||||
:error? (some? @cs))))))
|
||||
|
||||
(defn get-manifest
|
||||
[path]
|
||||
(with-open [input (ZipFile. (fs/file path))]
|
||||
(-> (read-manifest input)
|
||||
(validate-manifest))))
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
(some-> cause (ex/format-throwable :data? true :explain? false :header? false :summary? false)))}
|
||||
|
||||
(when-let [params (or (:request/params context) (:params context))]
|
||||
{:params (pp/pprint-str params :length 20 :level 15)})
|
||||
{:params (pp/pprint-str params :length 20 :level 20)})
|
||||
|
||||
(when-let [value (:value context)]
|
||||
{:value (pp/pprint-str value :length 30 :level 13)})
|
||||
|
||||
@@ -134,11 +134,18 @@
|
||||
::webhooks/event? true
|
||||
::sse/stream? true
|
||||
::sm/params schema:import-binfile}
|
||||
[{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id project-id version] :as params}]
|
||||
[{:keys [::db/pool] :as cfg} {:keys [::rpc/profile-id project-id version file] :as params}]
|
||||
(projects/check-edition-permissions! pool profile-id project-id)
|
||||
(let [params (-> params
|
||||
(assoc :profile-id profile-id)
|
||||
(assoc :version (or version 1)))]
|
||||
(let [version (or version 1)
|
||||
params (-> params
|
||||
(assoc :profile-id profile-id)
|
||||
(assoc :version version))
|
||||
manifest (case (int version)
|
||||
1 nil
|
||||
3 (bf.v3/get-manifest (:path file)))]
|
||||
|
||||
(with-meta
|
||||
(sse/response (partial import-binfile cfg params))
|
||||
{::audit/props {:file nil}})))
|
||||
{::audit/props {:file nil
|
||||
:generated-by (:generated-by manifest)
|
||||
:referer (:referer manifest)}})))
|
||||
|
||||
@@ -139,7 +139,8 @@
|
||||
'~:status', CASE COALESCE(p.props->'~:subscription'->>'~:type', 'professional')
|
||||
WHEN 'professional' THEN 'active'
|
||||
ELSE COALESCE(p.props->'~:subscription'->>'~:status', 'incomplete')
|
||||
END
|
||||
END,
|
||||
'~:seats', p.props->'~:quantity'
|
||||
) AS subscription
|
||||
FROM team_profile_rel AS tp
|
||||
JOIN team AS t ON (t.id = tp.team_id)
|
||||
|
||||
@@ -1019,8 +1019,8 @@
|
||||
[data _]
|
||||
(let [update-colors
|
||||
(fn [colors]
|
||||
(into {} (filter #(-> % val types.color/valid-color?) colors)))]
|
||||
(update data :colors update-colors)))
|
||||
(into {} (filter #(-> % val types.color/valid-library-color?) colors)))]
|
||||
(d/update-when data :colors update-colors)))
|
||||
|
||||
(defmethod migrate-data "legacy-52"
|
||||
[data _]
|
||||
@@ -1034,7 +1034,6 @@
|
||||
|
||||
(update data :pages-index d/update-vals update-page)))
|
||||
|
||||
|
||||
(defmethod migrate-data "legacy-53"
|
||||
[data _]
|
||||
(migrate-data data "legacy-26"))
|
||||
@@ -1517,6 +1516,17 @@
|
||||
|
||||
(d/update-when data :colors d/update-vals clear-color)))
|
||||
|
||||
(defmethod migrate-data "0009-clean-library-colors"
|
||||
[data _]
|
||||
(d/update-when data :colors
|
||||
(fn [colors]
|
||||
(reduce-kv (fn [colors id color]
|
||||
(if (types.color/valid-library-color? color)
|
||||
colors
|
||||
(dissoc colors id)))
|
||||
colors
|
||||
colors))))
|
||||
|
||||
(def available-migrations
|
||||
(into (d/ordered-set)
|
||||
["legacy-2"
|
||||
@@ -1580,4 +1590,5 @@
|
||||
"0005-deprecate-image-type"
|
||||
"0006-fix-old-texts-fills"
|
||||
"0007-clear-invalid-strokes-and-fills-v2"
|
||||
"0008-fix-library-colors-v4"]))
|
||||
"0008-fix-library-colors-v4"
|
||||
"0009-clean-library-colors"]))
|
||||
|
||||
@@ -170,19 +170,6 @@
|
||||
item))
|
||||
root)))
|
||||
|
||||
(defn xform-nodes
|
||||
"The same as transform but instead of receiving a funcion, receives
|
||||
a transducer."
|
||||
[xf root]
|
||||
(let [rf (fn [_ v] v)]
|
||||
(walk/postwalk
|
||||
(fn [item]
|
||||
(let [rf (xf rf)]
|
||||
(if (is-node? item)
|
||||
(d/nilv (rf nil item) item)
|
||||
item)))
|
||||
root)))
|
||||
|
||||
(defn update-text-content
|
||||
[shape pred-fn update-fn attrs]
|
||||
(let [update-attrs-fn #(update-fn % attrs)
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
[:ref-id {:optional true} ::sm/uuid]
|
||||
[:ref-file {:optional true} ::sm/uuid]])
|
||||
|
||||
;; This schema represent an "applied color"
|
||||
(def schema:color
|
||||
[:and
|
||||
[:merge {:title "Color"}
|
||||
|
||||
@@ -200,24 +200,25 @@
|
||||
contents
|
||||
(sequence extract-content-xf (:shapes shape))]
|
||||
|
||||
(bool/calculate-content (:bool-type shape) contents)))
|
||||
(ex/try!
|
||||
(bool/calculate-content (:bool-type shape) contents)
|
||||
|
||||
:on-exception
|
||||
(fn [cause]
|
||||
(ex/raise :type :internal
|
||||
:code :invalid-path-content
|
||||
:hint (str "unable to calculate bool content for shape " (:id shape))
|
||||
:shapes (:shapes shape)
|
||||
:type (:bool-type shape)
|
||||
:content (vec contents)
|
||||
:cause cause)))))
|
||||
|
||||
(defn calc-bool-content
|
||||
"Calculate the boolean content from shape and objects. Returns a
|
||||
packed PathData instance"
|
||||
[shape objects]
|
||||
(ex/try!
|
||||
(-> (calc-bool-content* shape objects)
|
||||
(impl/path-data))
|
||||
|
||||
:on-exception
|
||||
(fn [cause]
|
||||
(ex/raise :type :internal
|
||||
:code :invalid-path-content
|
||||
:hint (str "unable to create bool content for shape " (:id shape))
|
||||
:content (str (:content shape))
|
||||
:shape-id (:id shape)
|
||||
:cause cause))))
|
||||
(-> (calc-bool-content* shape objects)
|
||||
(impl/path-data)))
|
||||
|
||||
(defn update-bool-shape
|
||||
"Calculates the selrect+points for the boolean shape"
|
||||
|
||||
@@ -27,13 +27,11 @@
|
||||
|
||||
(defn make-move-to [to]
|
||||
{:command :move-to
|
||||
:relative false
|
||||
:params {:x (:x to)
|
||||
:y (:y to)}})
|
||||
|
||||
(defn make-line-to [to]
|
||||
{:command :line-to
|
||||
:relative false
|
||||
:params {:x (:x to)
|
||||
:y (:y to)}})
|
||||
|
||||
@@ -65,7 +63,6 @@
|
||||
(defn make-curve-to
|
||||
[to h1 h2]
|
||||
{:command :curve-to
|
||||
:relative false
|
||||
:params (make-curve-params to h1 h2)})
|
||||
|
||||
(defn prefix->coords [prefix]
|
||||
@@ -98,7 +95,7 @@
|
||||
(defn segment->point
|
||||
([segment] (segment->point segment :x))
|
||||
([segment coord]
|
||||
(when-let [params (get segment :params)]
|
||||
(when-let [params (not-empty (get segment :params))]
|
||||
(case coord
|
||||
:c1 (gpt/point (get params :c1x)
|
||||
(get params :c1y))
|
||||
|
||||
@@ -20,7 +20,8 @@
|
||||
[app.common.schema.generators :as sg]
|
||||
[app.common.svg.path :as svg.path]
|
||||
[app.common.transit :as t]
|
||||
[app.common.types.path :as-alias path])
|
||||
[app.common.types.path :as-alias path]
|
||||
[cuerdas.core :as str])
|
||||
(:import
|
||||
#?(:cljs [goog.string StringBuffer]
|
||||
:clj [java.nio ByteBuffer ByteOrder])))
|
||||
@@ -530,7 +531,9 @@
|
||||
:decode/json (fn [s]
|
||||
(cond
|
||||
(string? s)
|
||||
(from-string s)
|
||||
(if (str/empty? s)
|
||||
(from-plain [])
|
||||
(from-string s))
|
||||
|
||||
(vector? s)
|
||||
(let [decode-fn (deref decoder)]
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
[app.common.pprint :as pp]
|
||||
[app.common.transit :as trans]
|
||||
[app.common.types.path :as path]
|
||||
[app.common.types.path.bool :as path.bool]
|
||||
[app.common.types.path.helpers :as path.helpers]
|
||||
[app.common.types.path.impl :as path.impl]
|
||||
[app.common.types.path.segment :as path.segment]
|
||||
@@ -414,3 +415,89 @@
|
||||
result1 (get-handlers sample-content-large)
|
||||
result2 (path.segment/get-handlers content)]
|
||||
(t/is (= result1 result2))))
|
||||
|
||||
|
||||
(def contents-for-bool
|
||||
[[{:command :move-to, :params {:x 1682.9000244140625, :y 48.0}}
|
||||
{:command :line-to, :params {:x 1682.9000244140625, :y 44.0}}
|
||||
{:command :curve-to, :params {:x 1683.9000244140625, :y 43.0, :c1x 1682.9000244140625, :c1y 43.400001525878906, :c2x 1683.300048828125, :c2y 43.0}}
|
||||
{:command :line-to, :params {:x 1687.9000244140625, :y 43.0}}
|
||||
{:command :curve-to, :params {:x 1688.9000244140625, :y 44.0, :c1x 1688.5, :c1y 43.0, :c2x 1688.9000244140625, :c2y 43.400001525878906}}
|
||||
{:command :line-to, :params {:x 1688.9000244140625, :y 48.0}}
|
||||
{:command :curve-to, :params {:x 1687.9000244140625, :y 49.0, :c1x 1688.9000244140625, :c1y 48.599998474121094, :c2x 1688.5, :c2y 49.0}}
|
||||
{:command :line-to, :params {:x 1683.9000244140625, :y 49.0}}
|
||||
{:command :curve-to, :params {:x 1682.9000244140625, :y 48.0, :c1x 1683.300048828125, :c1y 49.0, :c2x 1682.9000244140625, :c2y 48.599998474121094}}
|
||||
{:command :close-path, :params {}}
|
||||
{:command :close-path, :params {}}
|
||||
{:command :move-to, :params {:x 1684.9000244140625, :y 45.0}}
|
||||
{:command :line-to, :params {:x 1684.9000244140625, :y 47.0}}
|
||||
{:command :line-to, :params {:x 1686.9000244140625, :y 47.0}}
|
||||
{:command :line-to, :params {:x 1686.9000244140625, :y 45.0}}
|
||||
{:command :line-to, :params {:x 1684.9000244140625, :y 45.0}}
|
||||
{:command :close-path, :params {}}
|
||||
{:command :close-path, :params {}}]
|
||||
|
||||
[{:command :move-to, :params {:x 1672.9000244140625, :y 48.0}}
|
||||
{:command :line-to, :params {:x 1672.9000244140625, :y 44.0}}
|
||||
{:command :curve-to, :params {:x 1673.9000244140625, :y 43.0, :c1x 1672.9000244140625, :c1y 43.400001525878906, :c2x 1673.300048828125, :c2y 43.0}}
|
||||
{:command :line-to, :params {:x 1677.9000244140625, :y 43.0}}
|
||||
{:command :curve-to, :params {:x 1678.9000244140625, :y 44.0, :c1x 1678.5, :c1y 43.0, :c2x 1678.9000244140625, :c2y 43.400001525878906}}
|
||||
{:command :line-to, :params {:x 1678.9000244140625, :y 48.0}}
|
||||
{:command :curve-to, :params {:x 1677.9000244140625, :y 49.0, :c1x 1678.9000244140625, :c1y 48.599998474121094, :c2x 1678.5, :c2y 49.0}}
|
||||
{:command :line-to, :params {:x 1673.9000244140625, :y 49.0}}
|
||||
{:command :curve-to, :params {:x 1672.9000244140625, :y 48.0, :c1x 1673.300048828125, :c1y 49.0, :c2x 1672.9000244140625, :c2y 48.599998474121094}}
|
||||
{:command :close-path, :params {}}
|
||||
{:command :close-path, :params {}}
|
||||
{:command :move-to, :params {:x 1674.9000244140625, :y 45.0}}
|
||||
{:command :line-to, :params {:x 1674.9000244140625, :y 47.0}}
|
||||
{:command :line-to, :params {:x 1676.9000244140625, :y 47.0}}
|
||||
{:command :line-to, :params {:x 1676.9000244140625, :y 45.0}}
|
||||
{:command :line-to, :params {:x 1674.9000244140625, :y 45.0}}
|
||||
{:command :close-path, :params {}}
|
||||
{:command :close-path, :params {}}]])
|
||||
|
||||
(def bool-result
|
||||
[{:command :move-to, :params {:x 1682.9000244140625, :y 48.0}}
|
||||
{:command :line-to, :params {:x 1682.9000244140625, :y 44.0}}
|
||||
{:command :curve-to,
|
||||
:params
|
||||
{:x 1683.9000244140625, :y 43.0, :c1x 1682.9000244140625, :c1y 43.400001525878906, :c2x 1683.300048828125, :c2y 43.0}}
|
||||
{:command :line-to, :params {:x 1687.9000244140625, :y 43.0}}
|
||||
{:command :curve-to,
|
||||
:params {:x 1688.9000244140625, :y 44.0, :c1x 1688.5, :c1y 43.0, :c2x 1688.9000244140625, :c2y 43.400001525878906}}
|
||||
{:command :line-to, :params {:x 1688.9000244140625, :y 48.0}}
|
||||
{:command :curve-to,
|
||||
:params {:x 1687.9000244140625, :y 49.0, :c1x 1688.9000244140625, :c1y 48.599998474121094, :c2x 1688.5, :c2y 49.0}}
|
||||
{:command :line-to, :params {:x 1683.9000244140625, :y 49.0}}
|
||||
{:command :curve-to,
|
||||
:params
|
||||
{:x 1682.9000244140625, :y 48.0, :c1x 1683.300048828125, :c1y 49.0, :c2x 1682.9000244140625, :c2y 48.599998474121094}}
|
||||
{:command :move-to, :params {:x 1684.9000244140625, :y 45.0}}
|
||||
{:command :line-to, :params {:x 1684.9000244140625, :y 47.0}}
|
||||
{:command :line-to, :params {:x 1686.9000244140625, :y 47.0}}
|
||||
{:command :line-to, :params {:x 1686.9000244140625, :y 45.0}}
|
||||
{:command :line-to, :params {:x 1684.9000244140625, :y 45.0}}
|
||||
{:command :move-to, :params {:x 1672.9000244140625, :y 48.0}}
|
||||
{:command :line-to, :params {:x 1672.9000244140625, :y 44.0}}
|
||||
{:command :curve-to,
|
||||
:params
|
||||
{:x 1673.9000244140625, :y 43.0, :c1x 1672.9000244140625, :c1y 43.400001525878906, :c2x 1673.300048828125, :c2y 43.0}}
|
||||
{:command :line-to, :params {:x 1677.9000244140625, :y 43.0}}
|
||||
{:command :curve-to,
|
||||
:params {:x 1678.9000244140625, :y 44.0, :c1x 1678.5, :c1y 43.0, :c2x 1678.9000244140625, :c2y 43.400001525878906}}
|
||||
{:command :line-to, :params {:x 1678.9000244140625, :y 48.0}}
|
||||
{:command :curve-to,
|
||||
:params {:x 1677.9000244140625, :y 49.0, :c1x 1678.9000244140625, :c1y 48.599998474121094, :c2x 1678.5, :c2y 49.0}}
|
||||
{:command :line-to, :params {:x 1673.9000244140625, :y 49.0}}
|
||||
{:command :curve-to,
|
||||
:params
|
||||
{:x 1672.9000244140625, :y 48.0, :c1x 1673.300048828125, :c1y 49.0, :c2x 1672.9000244140625, :c2y 48.599998474121094}}
|
||||
{:command :move-to, :params {:x 1674.9000244140625, :y 45.0}}
|
||||
{:command :line-to, :params {:x 1674.9000244140625, :y 47.0}}
|
||||
{:command :line-to, :params {:x 1676.9000244140625, :y 47.0}}
|
||||
{:command :line-to, :params {:x 1676.9000244140625, :y 45.0}}
|
||||
{:command :line-to, :params {:x 1674.9000244140625, :y 45.0}}])
|
||||
|
||||
(t/deftest calculate-bool-content
|
||||
(let [result (path.bool/calculate-content :union contents-for-bool)]
|
||||
(t/is (= result bool-result))))
|
||||
|
||||
91
docker/imagemagick/Dockerfile
Normal file
91
docker/imagemagick/Dockerfile
Normal file
@@ -0,0 +1,91 @@
|
||||
FROM ubuntu:24.04
|
||||
LABEL maintainer="Penpot <docker@penpot.app>"
|
||||
|
||||
ENV LANG='C.UTF-8' \
|
||||
LC_ALL='C.UTF-8' \
|
||||
DEBIAN_FRONTEND=noninteractive \
|
||||
TZ=Etc/UTC
|
||||
|
||||
ARG IMAGEMAGICK_VERSION=7.1.1-47
|
||||
|
||||
RUN set -e; \
|
||||
apt-get -qq update; \
|
||||
apt-get -qq upgrade; \
|
||||
apt-get -qqy --no-install-recommends install \
|
||||
autoconf \
|
||||
binutils \
|
||||
build-essential \
|
||||
ca-certificates \
|
||||
curl \
|
||||
libfftw3-dev \
|
||||
libheif-dev \
|
||||
libjpeg-dev \
|
||||
liblcms2-dev \
|
||||
libltdl-dev \
|
||||
liblzma-dev \
|
||||
libopenexr-dev \
|
||||
libpng-dev \
|
||||
librsvg2-dev \
|
||||
libtiff-dev \
|
||||
libtool \
|
||||
libwebp-dev \
|
||||
libzip-dev \
|
||||
libzstd-dev \
|
||||
pkg-config \
|
||||
; \
|
||||
curl -LfsSo /tmp/magick.tar.gz https://github.com/ImageMagick/ImageMagick/archive/refs/tags/${IMAGEMAGICK_VERSION}.tar.gz; \
|
||||
mkdir -p /tmp/magick; \
|
||||
cd /tmp/magick; \
|
||||
tar -xf /tmp/magick.tar.gz --strip-components=1; \
|
||||
./configure --prefix=/opt/imagick; \
|
||||
make -j 2; \
|
||||
make install; \
|
||||
rm -rf /opt/imagick/lib/libMagick++*; \
|
||||
rm -rf /opt/imagick/include; \
|
||||
rm -rf /opt/imagick/share; \
|
||||
apt-get -qqy --autoremove purge \
|
||||
autoconf \
|
||||
binutils \
|
||||
build-essential \
|
||||
ca-certificates \
|
||||
curl \
|
||||
libfftw3-dev \
|
||||
libheif-dev \
|
||||
libjpeg-dev \
|
||||
liblcms2-dev \
|
||||
libltdl-dev \
|
||||
liblzma-dev \
|
||||
libopenexr-dev \
|
||||
libpng-dev \
|
||||
librsvg2-dev \
|
||||
libtiff-dev \
|
||||
libtool\
|
||||
libwebp-dev \
|
||||
libzip-dev \
|
||||
libzstd-dev \
|
||||
pkg-config \
|
||||
;\
|
||||
apt-get -qqy --no-install-recommends install \
|
||||
libfontconfig1 \
|
||||
libfreetype6 \
|
||||
libglib2.0-0 \
|
||||
libgomp1 \
|
||||
libheif1 \
|
||||
libjpeg-turbo8 \
|
||||
liblcms2-2 \
|
||||
libopenexr-3-1-30 \
|
||||
libopenjp2-7 \
|
||||
libpng16-16 \
|
||||
librsvg2-2 \
|
||||
libtiff6 \
|
||||
libwebp7 \
|
||||
libwebpdemux2 \
|
||||
libwebpmux3 \
|
||||
libxml2 \
|
||||
libzip4t64 \
|
||||
libzstd1 \
|
||||
;\
|
||||
apt-get -qqy clean; \
|
||||
rm -rf /var/lib/apt/lists/*;
|
||||
|
||||
ENTRYPOINT ["/opt/imagick/bin/magick"]
|
||||
@@ -6,37 +6,18 @@ ENV LANG='C.UTF-8' \
|
||||
JAVA_HOME="/opt/jdk" \
|
||||
DEBIAN_FRONTEND=noninteractive \
|
||||
NODE_VERSION=v22.16.0 \
|
||||
IMAGEMAGICK_VERSION=7.1.1-47 \
|
||||
TZ=Etc/UTC
|
||||
|
||||
RUN set -ex; \
|
||||
apt-get -qq update; \
|
||||
apt-get -qq upgrade; \
|
||||
apt-get -qqy --no-install-recommends install \
|
||||
curl \
|
||||
ca-certificates \
|
||||
binutils \
|
||||
build-essential autoconf libtool pkg-config \
|
||||
libltdl-dev \
|
||||
libpng-dev libjpeg-dev libtiff-dev libwebp-dev libopenexr-dev libfftw3-dev \
|
||||
libzip-dev \
|
||||
liblcms2-dev liblzma-dev libzstd-dev \
|
||||
libheif-dev librsvg2-dev \
|
||||
ca-certificates \
|
||||
curl \
|
||||
; \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN set -eux; \
|
||||
curl -LfsSo /tmp/magick.tar.gz https://github.com/ImageMagick/ImageMagick/archive/refs/tags/${IMAGEMAGICK_VERSION}.tar.gz; \
|
||||
mkdir -p /tmp/magick; \
|
||||
cd /tmp/magick; \
|
||||
tar -xf /tmp/magick.tar.gz --strip-components=1; \
|
||||
./configure --prefix=/opt/imagick; \
|
||||
make -j 2; \
|
||||
make install; \
|
||||
rm -rf /opt/imagick/lib/libMagick++*; \
|
||||
rm -rf /opt/imagick/include; \
|
||||
rm -rf /opt/imagick/share;
|
||||
|
||||
RUN set -eux; \
|
||||
ARCH="$(dpkg --print-architecture)"; \
|
||||
case "${ARCH}" in \
|
||||
@@ -105,33 +86,33 @@ RUN set -ex; \
|
||||
apt-get -qq update; \
|
||||
apt-get -qq upgrade; \
|
||||
apt-get -qqy --no-install-recommends install \
|
||||
tzdata \
|
||||
ca-certificates \
|
||||
fontconfig \
|
||||
woff-tools \
|
||||
woff2 \
|
||||
fontforge \
|
||||
python3 \
|
||||
python3-tabulate \
|
||||
fontforge \
|
||||
tzdata \
|
||||
woff-tools \
|
||||
woff2 \
|
||||
\
|
||||
libpng16-16 \
|
||||
libfontconfig1 \
|
||||
libfreetype6 \
|
||||
libglib2.0-0 \
|
||||
libgomp1 \
|
||||
libheif1 \
|
||||
libjpeg-turbo8 \
|
||||
liblcms2-2 \
|
||||
libopenexr-3-1-30 \
|
||||
libopenjp2-7 \
|
||||
libpng16-16 \
|
||||
librsvg2-2 \
|
||||
libtiff6 \
|
||||
libwebp7 \
|
||||
libopenexr-3-1-30 \
|
||||
libfreetype6 \
|
||||
libfontconfig1 \
|
||||
libglib2.0-0 \
|
||||
libxml2 \
|
||||
liblcms2-2 \
|
||||
libheif1 \
|
||||
libopenjp2-7 \
|
||||
libzstd1 \
|
||||
librsvg2-2 \
|
||||
libgomp1 \
|
||||
libwebpmux3 \
|
||||
libwebpdemux2 \
|
||||
libwebpmux3 \
|
||||
libxml2 \
|
||||
libzip4t64 \
|
||||
libzstd1 \
|
||||
; \
|
||||
find tmp/usr/share/zoneinfo/* -type d ! -name 'Etc' |xargs rm -rf; \
|
||||
rm -rf /var/lib /var/cache; \
|
||||
@@ -144,7 +125,7 @@ RUN set -ex; \
|
||||
|
||||
COPY --from=build /opt/jre /opt/jre
|
||||
COPY --from=build /opt/node /opt/node
|
||||
COPY --from=build /opt/imagick /opt/imagick
|
||||
COPY --from=penpotapp/imagemagick:7.1.2-0 /opt/imagick /opt/imagick
|
||||
COPY --chown=penpot:penpot ./bundle-backend/ /opt/penpot/backend/
|
||||
|
||||
USER penpot:penpot
|
||||
|
||||
@@ -39,6 +39,7 @@ RUN set -ex; \
|
||||
fonts-wqy-zenhei \
|
||||
fonts-tlwg-loma-otf \
|
||||
fonts-freefont-ttf \
|
||||
poppler-utils \
|
||||
\
|
||||
libasound2t64 \
|
||||
libatk-bridge2.0-0t64 \
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
#!/usr/bin/env bash
|
||||
set -x
|
||||
|
||||
DOCKER_CLI_EXPERIMENTAL=enabled
|
||||
IMAGE=${1:-backend}
|
||||
|
||||
OUTPUT="type=registry"
|
||||
|
||||
if [ "--local" = "$2" ]; then
|
||||
OUTPUT="type=docker"
|
||||
fi
|
||||
|
||||
ORG=${PENPOT_DOCKER_NAMESPACE:-penpotapp};
|
||||
PLATFORM=${PENPOT_BUILD_PLATFORM:-linux/amd64};
|
||||
|
||||
IMAGE=${PENPOT_BUILD_IMAGE:-backend}
|
||||
PLATFORM=${PENPOT_BUILD_PLATFORM:-linux/amd64};
|
||||
PLATFORM=${PENPOT_BUILD_PLATFORM:-linux/amd64,linux/arm64};
|
||||
VERSION=${PENPOT_BUILD_VERSION:-latest}
|
||||
|
||||
DOCKER_IMAGE="$ORG/$IMAGE";
|
||||
OPTIONS="-t $DOCKER_IMAGE:$VERSION";
|
||||
|
||||
@@ -20,7 +23,7 @@ for element in "${TAGS[@]}"; do
|
||||
done
|
||||
|
||||
docker buildx inspect penpot > /dev/null 2>&1;
|
||||
docker run --privileged --rm tonistiigi/binfmt --install all
|
||||
docker run --privileged --rm tonistiigi/binfmt --install all > /dev/null;
|
||||
|
||||
if [ $? -eq 1 ]; then
|
||||
docker buildx create --name=penpot --use
|
||||
@@ -32,4 +35,5 @@ fi
|
||||
|
||||
unset IFS;
|
||||
|
||||
docker buildx build --platform ${PLATFORM// /,} $OPTIONS -f Dockerfile.$IMAGE "$@" .;
|
||||
shift;
|
||||
docker buildx build --output $OUTPUT --platform ${PLATFORM// /,} $OPTIONS -f Dockerfile.$IMAGE .;
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
(def grid-x-axis 10)
|
||||
(def grid-y-axis 10)
|
||||
|
||||
(def sidebar-default-width 318)
|
||||
(def sidebar-default-max-width 768)
|
||||
|
||||
(def page-metadata
|
||||
"Default data for page metadata."
|
||||
{:grid-x-axis grid-x-axis
|
||||
|
||||
@@ -245,4 +245,4 @@
|
||||
|
||||
(defn event
|
||||
[props]
|
||||
(ptk/data-event ::events props))
|
||||
(ptk/data-event ::event props))
|
||||
|
||||
@@ -673,41 +673,35 @@
|
||||
|
||||
(defn paste-shapes
|
||||
[{in-viewport? :in-viewport :as pdata}]
|
||||
(letfn [(translate-media [mdata media-idx attr-path]
|
||||
(let [id (-> (get-in mdata attr-path)
|
||||
(:id))
|
||||
(letfn [(translate-media [mdata media-idx attr]
|
||||
(let [id (-> (get mdata attr) :id)
|
||||
mobj (get media-idx id)]
|
||||
(if mobj
|
||||
(if (empty? attr-path)
|
||||
(assoc mdata :id (:id mobj))
|
||||
(update-in mdata attr-path assoc :id (:id mobj)))
|
||||
(update mdata attr assoc :id (:id mobj))
|
||||
mdata)))
|
||||
|
||||
(add-obj? [chg]
|
||||
(= (:type chg) :add-obj))
|
||||
|
||||
(process-rchange-shape [obj media-idx]
|
||||
(let [translate-fill-image #(translate-media % media-idx :fill-image)
|
||||
translate-stroke-image #(translate-media % media-idx :stroke-image)
|
||||
translate-fills #(mapv translate-fill-image %)
|
||||
translate-strokes #(mapv translate-stroke-image %)
|
||||
process-text-node #(d/update-when % :fills translate-fills)]
|
||||
|
||||
(-> obj
|
||||
(update :fills translate-fills)
|
||||
(update :strokes translate-strokes)
|
||||
(d/update-when :content #(txt/transform-nodes process-text-node %))
|
||||
(d/update-when :position-data #(mapv process-text-node %)))))
|
||||
|
||||
;; Analyze the rchange and replace staled media and
|
||||
;; references to the new uploaded media-objects.
|
||||
(process-rchange [media-idx change]
|
||||
(let [;; Texts can have different fills for pieces of the text
|
||||
tr-fill-xf (map #(translate-media % media-idx [:fill-image]))
|
||||
tr-stroke-xf (map #(translate-media % media-idx [:stroke-image]))]
|
||||
(if (add-obj? change)
|
||||
(update change :obj (fn [obj]
|
||||
(-> obj
|
||||
(update :fills #(into [] tr-fill-xf %))
|
||||
(update :strokes #(into [] tr-stroke-xf %))
|
||||
(d/update-when :metadata translate-media media-idx [])
|
||||
(d/update-when :fill-image translate-media media-idx [])
|
||||
(d/update-when :content
|
||||
(fn [content]
|
||||
(txt/xform-nodes tr-fill-xf content)))
|
||||
(d/update-when :position-data
|
||||
(fn [position-data]
|
||||
(mapv (fn [pos-data]
|
||||
(update pos-data :fills #(into [] tr-fill-xf %)))
|
||||
position-data))))))
|
||||
change)))
|
||||
(if (add-obj? change)
|
||||
(update change :obj process-rchange-shape media-idx)
|
||||
change))
|
||||
|
||||
(calculate-paste-position [state pobjects selected position]
|
||||
(let [page-objects (dsh/lookup-page-objects state)
|
||||
|
||||
@@ -479,7 +479,7 @@
|
||||
;; We don't have the fills attribute. It's an old text without color
|
||||
;; so need to be black
|
||||
(and (nil? (:fills node)) (empty? color-attrs))
|
||||
(update :fills conj txt/default-text-attrs)
|
||||
(assoc :fills (:fills txt/default-text-attrs))
|
||||
|
||||
;; Remove duplicates from the fills
|
||||
:always
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
[app.main.ui.inspect.attributes.blur :refer [blur-panel]]
|
||||
[app.main.ui.inspect.attributes.fill :refer [fill-panel]]
|
||||
[app.main.ui.inspect.attributes.geometry :refer [geometry-panel]]
|
||||
[app.main.ui.inspect.attributes.image :refer [image-panel]]
|
||||
[app.main.ui.inspect.attributes.layout :refer [layout-panel]]
|
||||
[app.main.ui.inspect.attributes.layout-element :refer [layout-element-panel]]
|
||||
[app.main.ui.inspect.attributes.shadow :refer [shadow-panel]]
|
||||
@@ -27,13 +26,12 @@
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def type->options
|
||||
{:multiple [:fill :stroke :image :text :shadow :blur :layout-element]
|
||||
{:multiple [:fill :stroke :text :shadow :blur :layout-element]
|
||||
:frame [:geometry :fill :stroke :shadow :blur :layout :layout-element]
|
||||
:group [:geometry :svg :layout-element]
|
||||
:rect [:geometry :fill :stroke :shadow :blur :svg :layout-element]
|
||||
:circle [:geometry :fill :stroke :shadow :blur :svg :layout-element]
|
||||
:path [:geometry :fill :stroke :shadow :blur :svg :layout-element]
|
||||
:image [:image :geometry :fill :stroke :shadow :blur :svg :layout-element]
|
||||
:text [:geometry :text :shadow :blur :stroke :layout-element]
|
||||
:variant [:variant :geometry :fill :stroke :shadow :blur :layout :layout-element]})
|
||||
|
||||
@@ -69,7 +67,6 @@
|
||||
:stroke stroke-panel
|
||||
:shadow shadow-panel
|
||||
:blur blur-panel
|
||||
:image image-panel
|
||||
:text text-panel
|
||||
:svg svg-panel
|
||||
:variant variant-panel*)
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
;; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
;; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
;;
|
||||
;; Copyright (c) KALEIDOS INC
|
||||
|
||||
(ns app.main.ui.inspect.attributes.image
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.media :as cm]
|
||||
[app.config :as cf]
|
||||
[app.main.ui.components.copy-button :refer [copy-button*]]
|
||||
[app.util.code-gen.style-css :as css]
|
||||
[app.util.i18n :refer [tr]]
|
||||
[cuerdas.core :as str]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(defn has-image? [shape]
|
||||
(= (:type shape) :image))
|
||||
|
||||
(mf/defc image-panel
|
||||
[{:keys [objects shapes]}]
|
||||
(for [shape (filter cfh/image-shape? shapes)]
|
||||
[:div {:class (stl/css :attributes-block)
|
||||
:key (str "image-" (:id shape))}
|
||||
[:div {:class (stl/css :image-wrapper)}
|
||||
[:img {:src (cf/resolve-file-media (-> shape :metadata))}]]
|
||||
|
||||
[:div {:class (stl/css :image-row)}
|
||||
[:div {:class (stl/css :global/attr-label)}
|
||||
(tr "inspect.attributes.image.width")]
|
||||
[:div {:class (stl/css :global/attr-value)}
|
||||
[:> copy-button* {:data (css/get-css-property objects (:metadata shape) :width)}
|
||||
[:div {:class (stl/css :button-children)} (css/get-css-value objects (:metadata shape) :width)]]]]
|
||||
|
||||
[:div {:class (stl/css :image-row)}
|
||||
[:div {:class (stl/css :global/attr-label)}
|
||||
(tr "inspect.attributes.image.height")]
|
||||
[:div {:class (stl/css :global/attr-value)}
|
||||
[:> copy-button* {:data (css/get-css-property objects (:metadata shape) :height)}
|
||||
[:div {:class (stl/css :button-children)} (css/get-css-value objects (:metadata shape) :height)]]]]
|
||||
|
||||
(let [mtype (-> shape :metadata :mtype)
|
||||
name (:name shape)
|
||||
extension (cm/mtype->extension mtype)]
|
||||
[:a {:class (stl/css :download-button)
|
||||
:target "_blank"
|
||||
:download (cond-> name extension (str/concat extension))
|
||||
:href (cf/resolve-file-media (-> shape :metadata))}
|
||||
(tr "inspect.attributes.image.download")])]))
|
||||
@@ -8,6 +8,7 @@
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.main.constants :refer [sidebar-default-width sidebar-default-max-width]]
|
||||
[app.main.data.common :as dcm]
|
||||
[app.main.data.event :as ev]
|
||||
[app.main.data.workspace :as dw]
|
||||
@@ -210,7 +211,7 @@
|
||||
(= current-section :code)))
|
||||
|
||||
{:keys [on-pointer-down on-lost-pointer-capture on-pointer-move set-size size]}
|
||||
(use-resize-hook :code 276 276 768 :x true :right)
|
||||
(use-resize-hook :code sidebar-default-width sidebar-default-width sidebar-default-max-width :x true :right)
|
||||
|
||||
on-change-section
|
||||
(mf/use-fn
|
||||
@@ -224,7 +225,7 @@
|
||||
(mf/use-fn
|
||||
(mf/deps size)
|
||||
(fn []
|
||||
(set-size (if (> size 276) 276 768))))
|
||||
(set-size (if (> size sidebar-default-width) sidebar-default-width sidebar-default-max-width))))
|
||||
|
||||
props
|
||||
(mf/spread-props props
|
||||
@@ -235,12 +236,12 @@
|
||||
[:aside
|
||||
{:class (stl/css-case :right-settings-bar true
|
||||
:not-expand (not can-be-expanded?)
|
||||
:expanded (> size 276))
|
||||
:expanded (> size sidebar-default-width))
|
||||
|
||||
:id "right-sidebar-aside"
|
||||
:data-testid "right-sidebar"
|
||||
:data-size (str size)
|
||||
:style {"--width" (if can-be-expanded? (dm/str size "px") "276px")}}
|
||||
:style {"--width" (if can-be-expanded? (dm/str size "px") (dm/str sidebar-default-width "px"))}}
|
||||
|
||||
(when can-be-expanded?
|
||||
[:div {:class (stl/css :resize-area)
|
||||
|
||||
@@ -55,15 +55,22 @@
|
||||
|
||||
;; Excluding nil values
|
||||
values (d/without-nils values)
|
||||
fills (if (contains? cfg/flags :frontend-binary-fills)
|
||||
|
||||
fills (get values :fills)
|
||||
fills (if (and (contains? cfg/flags :frontend-binary-fills)
|
||||
(not= fills :multiple))
|
||||
(take types.fill/MAX-FILLS (d/nilv (:fills values) []))
|
||||
(:fills values))
|
||||
fills)
|
||||
|
||||
|
||||
has-fills? (or (= :multiple fills) (some? (seq fills)))
|
||||
|
||||
can-add-fills? (if (contains? cfg/flags :frontend-binary-fills)
|
||||
(and (not (= :multiple fills))
|
||||
(< (count fills) types.fill/MAX-FILLS))
|
||||
(not (= :multiple fills)))
|
||||
|
||||
|
||||
state* (mf/use-state has-fills?)
|
||||
open? (deref state*)
|
||||
|
||||
|
||||
@@ -286,7 +286,8 @@
|
||||
(fn [mod? ids]
|
||||
(let [sorted-ids
|
||||
(into (d/ordered-set)
|
||||
(comp (remove #(dm/get-in objects [% :blocked]))
|
||||
(comp (remove (partial cfh/hidden-parent? objects))
|
||||
(remove #(dm/get-in objects [% :blocked]))
|
||||
(remove (partial cfh/svg-raw-shape? objects)))
|
||||
(ctt/sort-z-index objects ids {:bottom-frames? mod?}))]
|
||||
(mf/set-ref-val! sorted-ids-cache (assoc cached-ids [mod? ids] sorted-ids))
|
||||
@@ -355,7 +356,6 @@
|
||||
hover-shape
|
||||
(->> ids
|
||||
(remove remove-hover?)
|
||||
(remove (partial cfh/hidden-parent? objects))
|
||||
(remove #(and mod? (no-fill-nested-frames? %)))
|
||||
(filter #(or (empty? focus) (cpf/is-in-focus? objects focus %)))
|
||||
(first)
|
||||
@@ -366,7 +366,6 @@
|
||||
(when show-measures?
|
||||
(->> ids
|
||||
(remove remove-measure?)
|
||||
(remove (partial cfh/hidden-parent? objects))
|
||||
(remove #(and mod? (no-fill-nested-frames? %)))
|
||||
(filter #(or (empty? focus) (cpf/is-in-focus? objects focus %)))
|
||||
(first)
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# CHANGELOG
|
||||
|
||||
## 1.0.7
|
||||
|
||||
- Add the ability to provide refereron creating build context
|
||||
|
||||
```js
|
||||
const context = penpot.createBuildContext({referer:"my-referer"});
|
||||
```
|
||||
|
||||
The referer will be added as an additional field on the manifest.json
|
||||
|
||||
|
||||
## 1.0.6
|
||||
|
||||
- Fix unexpected issue on library color decoding
|
||||
|
||||
@@ -21,11 +21,10 @@
|
||||
:dev
|
||||
{:extra-paths ["dev"]
|
||||
:extra-deps
|
||||
{thheller/shadow-cljs {:mvn/version "3.1.4"}
|
||||
{thheller/shadow-cljs {:mvn/version "3.1.7"}
|
||||
com.bhauman/rebel-readline {:mvn/version "RELEASE"}
|
||||
org.clojure/tools.namespace {:mvn/version "RELEASE"}
|
||||
criterium/criterium {:mvn/version "RELEASE"}
|
||||
cider/cider-nrepl {:mvn/version "0.48.0"}}}
|
||||
criterium/criterium {:mvn/version "RELEASE"}}}
|
||||
|
||||
:shadow-cljs
|
||||
{:main-opts ["-m" "shadow.cljs.devtools.cli"]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@penpot/library",
|
||||
"version": "1.0.6",
|
||||
"version": "1.0.7",
|
||||
"license": "MPL-2.0",
|
||||
"author": "Kaleidos INC",
|
||||
"packageManager": "yarn@4.9.1+sha512.f95ce356460e05be48d66401c1ae64ef84d163dd689964962c6888a9810865e39097a5e9de748876c2e0bf89b232d583c33982773e9903ae7a76257270986538",
|
||||
@@ -40,8 +40,7 @@
|
||||
"@zip.js/zip.js": "patch:@zip.js/zip.js@npm%3A2.7.60#~/.yarn/patches/@zip.js-zip.js-npm-2.7.60-b6b814410b.patch",
|
||||
"concurrently": "^9.1.2",
|
||||
"luxon": "^3.6.1",
|
||||
"nodemon": "^3.1.9",
|
||||
"shadow-cljs": "3.1.4"
|
||||
"nodemon": "^3.1.9"
|
||||
},
|
||||
"dependencies": {
|
||||
"source-map-support": "^0.5.21"
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Writable } from "stream";
|
||||
// console.log(penpot);
|
||||
|
||||
(async function () {
|
||||
const context = penpot.createBuildContext();
|
||||
const context = penpot.createBuildContext({referer:"playground"});
|
||||
|
||||
{
|
||||
context.addFile({ name: "Test File 1" });
|
||||
|
||||
@@ -271,11 +271,19 @@
|
||||
(fn []
|
||||
(json/->js @state))))
|
||||
|
||||
(def ^:private schema:context-options
|
||||
[:map {:title "ContextOptions"}
|
||||
[:referer {:optional true} ::sm/text]])
|
||||
|
||||
(def ^:private decode-context-options
|
||||
(sm/decoder schema:context-options sm/json-transformer))
|
||||
|
||||
(defn create-build-context
|
||||
"Create an empty builder state context."
|
||||
[]
|
||||
(let [state (atom {})
|
||||
api (create-builder-api state)]
|
||||
[options]
|
||||
(let [options (some-> options decode-params decode-context-options)
|
||||
state (atom {:options options})
|
||||
api (create-builder-api state)]
|
||||
|
||||
(specify! api
|
||||
cljs.core/IDeref
|
||||
|
||||
@@ -183,17 +183,22 @@
|
||||
|
||||
(defn- generate-manifest-procs
|
||||
[state]
|
||||
(let [files (->> (get state ::fb/files)
|
||||
(mapv (fn [[file-id file]]
|
||||
{:id file-id
|
||||
:name (:name file)
|
||||
:features (:features file)})))
|
||||
(let [opts (get state :options)
|
||||
files (->> (get state ::fb/files)
|
||||
(mapv (fn [[file-id file]]
|
||||
{:id file-id
|
||||
:name (:name file)
|
||||
:features (:features file)})))
|
||||
params {:type "penpot/export-files"
|
||||
:version 1
|
||||
:generated-by "penpot-library/%version%"
|
||||
:referer (get opts :referer)
|
||||
:files files
|
||||
:relations []}]
|
||||
["manifest.json" (delay (json/encode params))]))
|
||||
:relations []}
|
||||
params (d/without-nils params)]
|
||||
|
||||
["manifest.json"
|
||||
(delay (json/encode params))]))
|
||||
|
||||
(defn- generate-procs
|
||||
[state]
|
||||
|
||||
119
manage.sh
119
manage.sh
@@ -7,6 +7,7 @@ export DEVENV_PNAME="penpotdev";
|
||||
export CURRENT_USER_ID=$(id -u);
|
||||
export CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD);
|
||||
|
||||
export IMAGEMAGICK_VERSION=7.1.2-0
|
||||
|
||||
# Safe directory to avoid ownership errors with Git
|
||||
git config --global --add safe.directory /home/penpot/penpot || true
|
||||
@@ -16,16 +17,23 @@ export JAVA_OPTS=${JAVA_OPTS:-"-Xmx1000m -Xms50m"};
|
||||
|
||||
set -e
|
||||
|
||||
ARCH=$(uname -m)
|
||||
|
||||
if [[ "$ARCH" == "x86_64" || "$ARCH" == "i386" || "$ARCH" == "i686" ]]; then
|
||||
ARCH="amd64"
|
||||
elif [[ "$ARCH" == "aarch64" || "$ARCH" == "arm64" ]]; then
|
||||
ARCH="arm64"
|
||||
else
|
||||
echo "Unknown architecture $ARCH"
|
||||
exit -1
|
||||
fi
|
||||
|
||||
|
||||
function print-current-version {
|
||||
echo -n "$(git describe --tags --match "*.*.*")";
|
||||
}
|
||||
|
||||
function build-devenv {
|
||||
set +e;
|
||||
echo "Building development image $DEVENV_IMGNAME:latest..."
|
||||
|
||||
pushd docker/devenv;
|
||||
|
||||
function setup-buildx {
|
||||
docker run --privileged --rm tonistiigi/binfmt --install all
|
||||
docker buildx inspect penpot > /dev/null 2>&1;
|
||||
|
||||
@@ -36,19 +44,28 @@ function build-devenv {
|
||||
docker buildx use penpot;
|
||||
docker buildx inspect --bootstrap > /dev/null 2>&1;
|
||||
fi
|
||||
|
||||
# docker build -t $DEVENV_IMGNAME:latest .
|
||||
docker buildx build --platform linux/amd64 --push -t $DEVENV_IMGNAME:latest .;
|
||||
docker pull $DEVENV_IMGNAME:latest;
|
||||
|
||||
popd;
|
||||
}
|
||||
|
||||
function build-devenv-local {
|
||||
echo "Building local only development image $DEVENV_IMGNAME:latest..."
|
||||
function build-devenv {
|
||||
set +e;
|
||||
|
||||
pushd docker/devenv;
|
||||
docker build -t $DEVENV_IMGNAME:latest .;
|
||||
|
||||
if [ "$1" = "--local" ]; then
|
||||
echo "Build local only $DEVENV_IMGNAME:latest image";
|
||||
docker build -t $DEVENV_IMGNAME:latest .;
|
||||
else
|
||||
echo "Build and push $DEVENV_IMGNAME:latest image";
|
||||
setup-buildx;
|
||||
|
||||
docker buildx build \
|
||||
--platform linux/amd64,linux/arm64 \
|
||||
--output type=registry \
|
||||
-t $DEVENV_IMGNAME:latest .;
|
||||
|
||||
docker pull $DEVENV_IMGNAME:latest;
|
||||
fi
|
||||
|
||||
popd;
|
||||
}
|
||||
|
||||
@@ -124,6 +141,32 @@ function run-devenv-isolated-shell {
|
||||
$DEVENV_IMGNAME:latest sudo -EH -u penpot bash
|
||||
}
|
||||
|
||||
function build-imagemagick-docker-image {
|
||||
set +e;
|
||||
echo "Building image penpotapp/imagemagick:$IMAGEMAGICK_VERSION"
|
||||
|
||||
pushd docker/imagemagick;
|
||||
|
||||
output_option="type=registry";
|
||||
platform="linux/amd64,linux/arm64";
|
||||
|
||||
if [ "$1" = "--local" ]; then
|
||||
output_option="type=docker";
|
||||
platform="linux/$ARCH"
|
||||
fi
|
||||
|
||||
setup-buildx;
|
||||
|
||||
docker buildx build \
|
||||
--build-arg IMAGEMAGICK_VERSION=$IMAGEMAGICK_VERSION \
|
||||
--platform $platform \
|
||||
--output $output_option \
|
||||
-t penpotapp/imagemagick:latest \
|
||||
-t penpotapp/imagemagick:$IMAGEMAGICK_VERSION .;
|
||||
|
||||
popd;
|
||||
}
|
||||
|
||||
function build {
|
||||
echo ">> build start: $1"
|
||||
local version=$(print-current-version);
|
||||
@@ -219,21 +262,21 @@ function build-docs-bundle {
|
||||
echo ">> bundle docs end";
|
||||
}
|
||||
|
||||
function build-frontend-docker-images {
|
||||
function build-frontend-docker-image {
|
||||
rsync -avr --delete ./bundles/frontend/ ./docker/images/bundle-frontend/;
|
||||
pushd ./docker/images;
|
||||
docker build -t penpotapp/frontend:$CURRENT_BRANCH -t penpotapp/frontend:latest -f Dockerfile.frontend .;
|
||||
popd;
|
||||
}
|
||||
|
||||
function build-backend-docker-images {
|
||||
function build-backend-docker-image {
|
||||
rsync -avr --delete ./bundles/backend/ ./docker/images/bundle-backend/;
|
||||
pushd ./docker/images;
|
||||
docker build -t penpotapp/backend:$CURRENT_BRANCH -t penpotapp/backend:latest -f Dockerfile.backend .;
|
||||
popd;
|
||||
}
|
||||
|
||||
function build-exporter-docker-images {
|
||||
function build-exporter-docker-image {
|
||||
rsync -avr --delete ./bundles/exporter/ ./docker/images/bundle-exporter/;
|
||||
pushd ./docker/images;
|
||||
docker build -t penpotapp/exporter:$CURRENT_BRANCH -t penpotapp/exporter:latest -f Dockerfile.exporter .;
|
||||
@@ -246,7 +289,7 @@ function usage {
|
||||
echo "Options:"
|
||||
echo "- pull-devenv Pulls docker development oriented image"
|
||||
echo "- build-devenv Build docker development oriented image"
|
||||
echo "- build-devenv-local Build a local docker development oriented image"
|
||||
echo "- build-devenv --local Build a local docker development oriented image"
|
||||
echo "- create-devenv Create the development oriented docker compose service."
|
||||
echo "- start-devenv Start the development oriented docker compose service."
|
||||
echo "- stop-devenv Stops the development oriented docker compose service."
|
||||
@@ -263,9 +306,9 @@ function usage {
|
||||
echo "- build-docs-bundle Build docs bundle."
|
||||
echo ""
|
||||
echo "- build-docker-images Build all docker images (frontend, backend and exporter)."
|
||||
echo "- build-frontend-docker-images Build frontend docker images."
|
||||
echo "- build-backend-docker-images Build backend docker images."
|
||||
echo "- build-exporter-docker-images Build exporter docker images."
|
||||
echo "- build-frontend-docker-image Build frontend docker images."
|
||||
echo "- build-backend-docker-image Build backend docker images."
|
||||
echo "- build-exporter-docker-image Build exporter docker images."
|
||||
echo ""
|
||||
echo "- version Show penpot's version."
|
||||
}
|
||||
@@ -281,11 +324,8 @@ case $1 in
|
||||
;;
|
||||
|
||||
build-devenv)
|
||||
build-devenv ${@:2}
|
||||
;;
|
||||
|
||||
build-devenv-local)
|
||||
build-devenv-local ${@:2}
|
||||
shift;
|
||||
build-devenv $@;
|
||||
;;
|
||||
|
||||
create-devenv)
|
||||
@@ -339,25 +379,30 @@ case $1 in
|
||||
build-docs-bundle;
|
||||
;;
|
||||
|
||||
build-imagemagick-docker-image)
|
||||
shift;
|
||||
build-imagemagick-docker-image $@;
|
||||
;;
|
||||
|
||||
build-docker-images)
|
||||
build-frontend-docker-images
|
||||
build-backend-docker-images
|
||||
build-exporter-docker-images
|
||||
build-frontend-docker-image
|
||||
build-backend-docker-image
|
||||
build-exporter-docker-image
|
||||
;;
|
||||
|
||||
build-frontend-docker-images)
|
||||
build-frontend-docker-images
|
||||
build-frontend-docker-image)
|
||||
build-frontend-docker-image
|
||||
;;
|
||||
|
||||
build-backend-docker-images)
|
||||
build-backend-docker-images
|
||||
build-backend-docker-image)
|
||||
build-backend-docker-image
|
||||
;;
|
||||
|
||||
build-exporter-docker-images)
|
||||
build-exporter-docker-images
|
||||
build-exporter-docker-image)
|
||||
build-exporter-docker-image
|
||||
;;
|
||||
|
||||
*)
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
esac
|
||||
|
||||
Reference in New Issue
Block a user