mirror of
https://github.com/penpot/penpot.git
synced 2025-12-11 22:14:05 +01:00
Merge remote-tracking branch 'origin/staging' into develop
This commit is contained in:
@@ -77,6 +77,7 @@ on-premises instances** that want to keep up to date.
|
||||
- Fix mixed letter spacing and line height [Taiga #11178](https://tree.taiga.io/project/penpot/issue/11178)
|
||||
- Fix snap nodes shortcut [Taiga #11054](https://tree.taiga.io/project/penpot/issue/11054)
|
||||
- Fix changing a text property in a text layer does not unapply the previously applied token in the same property [Taiga #11337}(https://tree.taiga.io/project/penpot/issue/11337)
|
||||
- Fix shortcut error pressing G+W from the View Mode [Taiga #11061](https://tree.taiga.io/project/penpot/issue/11061)
|
||||
|
||||
## 2.7.2
|
||||
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
{:mvn/version "1.3.1002"}
|
||||
metosin/reitit-core {:mvn/version "0.9.1"}
|
||||
nrepl/nrepl {:mvn/version "1.3.1"}
|
||||
cider/cider-nrepl {:mvn/version "0.56.0"}
|
||||
|
||||
org.postgresql/postgresql {:mvn/version "42.7.6"}
|
||||
org.xerial/sqlite-jdbc {:mvn/version "3.49.1.0"}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
[{:id "wireframing-kit"
|
||||
[{:id "tokens-starter-kit"
|
||||
:name "Design tokens starter kit"
|
||||
:file-uri "https://github.com/penpot/penpot-files/raw/refs/heads/main/Tokens%20starter%20kit.penpot"},
|
||||
{:id "wireframing-kit"
|
||||
:name "Wireframe library"
|
||||
:file-uri "https://github.com/penpot/penpot-files/raw/refs/heads/main/Wireframing%20kit%20v1.1.penpot"}
|
||||
{:id "prototype-examples"
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
[app.svgo :as-alias svgo]
|
||||
[app.util.time :as dt]
|
||||
[app.worker :as-alias wrk]
|
||||
[cider.nrepl :refer [cider-nrepl-handler]]
|
||||
[clojure.test :as test]
|
||||
[clojure.tools.namespace.repl :as repl]
|
||||
[cuerdas.core :as str]
|
||||
@@ -605,7 +604,7 @@
|
||||
(let [p (promise)]
|
||||
(when (contains? cf/flags :nrepl-server)
|
||||
(l/inf :hint "start nrepl server" :port 6064)
|
||||
(nrepl/start-server :bind "0.0.0.0" :port 6064 :handler cider-nrepl-handler))
|
||||
(nrepl/start-server :bind "0.0.0.0" :port 6064))
|
||||
|
||||
(start)
|
||||
(deref p))
|
||||
|
||||
@@ -595,7 +595,11 @@
|
||||
(teams/check-read-permissions! conn profile-id team-id)
|
||||
(->> (db/exec! conn [sql:team-shared-files team-id])
|
||||
(into #{} (comp
|
||||
(map decode-row)
|
||||
;; NOTE: this decode operation is a workaround for a
|
||||
;; fast fix, this should be approached with a more
|
||||
;; efficient implementation, for now it loads all
|
||||
;; the files in memory.
|
||||
(map (partial bfc/decode-file cfg))
|
||||
(map (fn [row]
|
||||
(if-let [media-id (:media-id row)]
|
||||
(-> row
|
||||
|
||||
@@ -95,22 +95,33 @@
|
||||
(defn migrate-file
|
||||
[file libs]
|
||||
(binding [cfeat/*new* (atom #{})]
|
||||
(let [version (or (:version file)
|
||||
(-> file :data :version))]
|
||||
(-> file
|
||||
(assoc :version cfd/version)
|
||||
(update :migrations
|
||||
(fn [migrations]
|
||||
(if (nil? migrations)
|
||||
(generate-migrations-from-version version)
|
||||
migrations)))
|
||||
;; NOTE: in some future we can consider to apply
|
||||
;; a migration to the whole database and remove
|
||||
;; this code from this function that executes on
|
||||
;; each file migration operation
|
||||
(update :features cfeat/migrate-legacy-features)
|
||||
(migrate libs)
|
||||
(update :features (fnil into #{}) (deref cfeat/*new*))))))
|
||||
(let [version
|
||||
(or (:version file) (-> file :data :version))
|
||||
|
||||
migrations
|
||||
(not-empty (get file :migrations))
|
||||
|
||||
file
|
||||
(-> file
|
||||
(assoc :version cfd/version)
|
||||
(assoc :migrations
|
||||
(if migrations
|
||||
migrations
|
||||
(generate-migrations-from-version version)))
|
||||
;; NOTE: in some future we can consider to apply a
|
||||
;; migration to the whole database and remove this code
|
||||
;; from this function that executes on each file
|
||||
;; migration operation
|
||||
(update :features cfeat/migrate-legacy-features)
|
||||
(migrate libs)
|
||||
(update :features (fnil into #{}) (deref cfeat/*new*)))]
|
||||
|
||||
;; NOTE: When we have no previous migrations, we report all
|
||||
;; migrations as migrated in order to correctly persist them all
|
||||
;; and not only the really applied migrations
|
||||
(if (not migrations)
|
||||
(vary-meta file assoc ::migrated (:migrations file))
|
||||
file))))
|
||||
|
||||
(defn migrated?
|
||||
[file]
|
||||
@@ -1274,7 +1285,8 @@
|
||||
;; rollback, we still need to perform an other migration
|
||||
;; for properly delete the bool-content prop from shapes
|
||||
;; once the know the migration was OK
|
||||
(if (cfh/bool-shape? object)
|
||||
(if (and (cfh/bool-shape? object)
|
||||
(not (contains? object :content)))
|
||||
(if-let [content (:bool-content object)]
|
||||
(assoc object :content content)
|
||||
object)
|
||||
@@ -1469,14 +1481,22 @@
|
||||
(update :pages-index d/update-vals update-container)
|
||||
(d/update-when :components d/update-vals update-container))))
|
||||
|
||||
(defmethod migrate-data "0008-fix-library-colors-opacity"
|
||||
(defmethod migrate-data "0008-fix-library-colors-v2"
|
||||
[data _]
|
||||
(letfn [(update-color [color]
|
||||
(letfn [(clear-color-opacity [color]
|
||||
(if (and (contains? color :opacity)
|
||||
(nil? (get color :opacity)))
|
||||
(assoc color :opacity 1)
|
||||
color))]
|
||||
(d/update-when data :colors d/update-vals update-color)))
|
||||
color))
|
||||
|
||||
(clear-color [color]
|
||||
(-> color
|
||||
(select-keys types.color/library-color-attrs)
|
||||
(d/without-nils)
|
||||
(d/without-qualified)
|
||||
(clear-color-opacity)))]
|
||||
|
||||
(d/update-when data :colors d/update-vals clear-color)))
|
||||
|
||||
(defmethod migrate-data "0009-add-partial-text-touched-flags"
|
||||
[data _]
|
||||
@@ -1566,5 +1586,5 @@
|
||||
"0005-deprecate-image-type"
|
||||
"0006-fix-old-texts-fills"
|
||||
"0007-clear-invalid-strokes-and-fills-v2"
|
||||
"0008-fix-library-colors-opacity"
|
||||
"0008-fix-library-colors-v2"
|
||||
"0009-add-partial-text-touched-flags"]))
|
||||
|
||||
@@ -150,6 +150,9 @@
|
||||
(sm/optional-keys schema:image-color)]
|
||||
[:fn has-valid-color-attrs?]])
|
||||
|
||||
(def library-color-attrs
|
||||
(sm/keys schema:library-color-attrs))
|
||||
|
||||
(def valid-color?
|
||||
(sm/lazy-validator schema:color))
|
||||
|
||||
|
||||
BIN
docs/img/design-tokens/22-tokens-export-multiple.webp
Normal file
BIN
docs/img/design-tokens/22-tokens-export-multiple.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
BIN
docs/img/design-tokens/23-tokens-export-single.webp
Normal file
BIN
docs/img/design-tokens/23-tokens-export-single.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
@@ -367,12 +367,97 @@ title: 10· Design Tokens
|
||||
|
||||
<h2 id="design-tokens-import-export">Importing and Exporting Tokens</h2>
|
||||
<p>You can export Tokens from Penpot and import them from your computer to a Penpot file. Tokens can be imported from the <strong>Tools</strong> option at the bottom of the <strong>Tokens</strong> tab.</p>
|
||||
<p>The <strong>Import</strong> functionality allows you to upload and replace the global token set using a single file, while the <strong>Export</strong> functionality lets you download the current global token set using a single file to your system.</p>
|
||||
<p>The <strong>Import</strong> functionality allows you to upload and replace the global token set using a single file or a folder with multiple files in it.</p>
|
||||
<p>These features support JSON files formatted according to specific guidelines and preserve the ability to undo changes if needed.</p>
|
||||
<figure>
|
||||
<img src="/img/design-tokens/21-tokens-import-export.webp" alt="Tokens import export" />
|
||||
</figure>
|
||||
<ol>
|
||||
<li><strong>Import:</strong> At the <strong>Tools</strong> option, select <strong>Import</strong>, then select your <code class="language-js">tokens.json</code> file. </li>
|
||||
<li><strong>Export:</strong> At the <strong>Tools</strong> option, select <strong>Export</strong>. This will export all the tokens, including token sets and themes.</li>
|
||||
<li><strong>Import:</strong> Click <strong>Tools</strong>, then select <strong>Import</strong> to view import options. </li>
|
||||
<li><strong>Export:</strong> Click <strong>Tools</strong>, then select <strong>Export</strong> to view export options.</li>
|
||||
</ol>
|
||||
|
||||
<h3 id="design-tokens-import-options">Import Options</h3>
|
||||
<h4>Single file</h4>
|
||||
|
||||
<p>You can import a JSON file comprising all tokens, token sets and token themes.</p>
|
||||
<p>When importing a single file, the first-level keys of the json file will be interpreted as the set name.</p>
|
||||
|
||||
<pre class="language-json">
|
||||
<code class="language-json">
|
||||
{
|
||||
"Global": {
|
||||
// first-level key will be interpreted as set name
|
||||
"color": {
|
||||
"300": {
|
||||
"$value": "red",
|
||||
"$type": "color",
|
||||
"$description": "my token description"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Brands/A": {
|
||||
// first-level key will be interpreted as set name
|
||||
"color": {
|
||||
"accent": {
|
||||
"$value": "{red}",
|
||||
"$type": "color",
|
||||
"$description": "my token description"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Brands/B": {
|
||||
// first-level key will be interpreted as set name
|
||||
"color": {
|
||||
"accent": {
|
||||
"$value": "#fabada",
|
||||
"$type": "color",
|
||||
"$description": "my token description"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</code>
|
||||
</pre>
|
||||
|
||||
<h4>Multifile</h4>
|
||||
<p>Imports a folder containing multiple JSON files (one per Token Set) and additional files like <code class="language-json">$themes.json</code> or <code class="language-json">$metadata.json</code> configurations. When importing multiple files, the name and path of the individual json files inside the folder will be interpreted as set names. These files should only contain tokens.</p>
|
||||
<p>Multifile folder structure example:</p>
|
||||
<code>
|
||||
<pre>
|
||||
folder/
|
||||
├── global/
|
||||
│ ├── colors.json // can only contain tokens
|
||||
│ └── dimension.json // can only contain tokens
|
||||
├── mode/
|
||||
│ ├── dark.json // can only contain tokens
|
||||
│ └── light.json // can only contain tokens
|
||||
├── $themes.json // themes config
|
||||
└── $metadata.json // other metadata config
|
||||
</code>
|
||||
</pre>
|
||||
<figcaption>The main folder name won’t be used to build token set names, so in this example, <strong>folder</strong> will be ignored in the set names.</figcaption>
|
||||
|
||||
<h3 id="design-tokens-export-options">Export Options</h3>
|
||||
<p>Just like with importing, you can export tokens, themes and sets either in a single JSON file or in multiple files. There is no difference in the content being exported; the choice depends on your team's preferences for file organization: a single file with all the tokens, sets and themes, or a folder structure with separated JSON files organized by sets.</p>
|
||||
<p>In both cases you can preview the result of the export options:</p>
|
||||
|
||||
<figure>
|
||||
<img src="/img/design-tokens/22-tokens-export-multiple.webp" alt="Tokens export with multiple files" />
|
||||
<figcaption>Exporting tokens as multiple files.</figcaption>
|
||||
</figure>
|
||||
|
||||
<figure>
|
||||
<img src="/img/design-tokens/23-tokens-export-single.webp" alt="Tokens export with single file" />
|
||||
<figcaption>Exporting tokens as a single file.</figcaption>
|
||||
</figure>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 404 KiB |
File diff suppressed because it is too large
Load Diff
@@ -679,14 +679,8 @@
|
||||
mobj (get media-idx id)]
|
||||
(if mobj
|
||||
(if (empty? attr-path)
|
||||
(-> mdata
|
||||
(assoc :id (:id mobj))
|
||||
(assoc :path (:path mobj)))
|
||||
(update-in mdata attr-path (fn [value]
|
||||
(-> value
|
||||
(assoc :id (:id mobj))
|
||||
(assoc :path (:path mobj))))))
|
||||
|
||||
(assoc mdata :id (:id mobj))
|
||||
(update-in mdata attr-path assoc :id (:id mobj)))
|
||||
mdata)))
|
||||
|
||||
(add-obj? [chg]
|
||||
|
||||
@@ -148,13 +148,14 @@
|
||||
"Given the current layout flags, and updates them with the data
|
||||
stored in Storage."
|
||||
[layout]
|
||||
(reduce (fn [layout [flag key]]
|
||||
(condp = (get storage/user key ::none)
|
||||
::none layout
|
||||
false (disj layout flag)
|
||||
true (conj layout flag)))
|
||||
layout
|
||||
layout-flags-persistence-mapping))
|
||||
(let [layout (set (or layout #{}))]
|
||||
(reduce-kv (fn [layout flag key]
|
||||
(condp = (get storage/user key ::none)
|
||||
::none layout
|
||||
false (disj layout flag)
|
||||
true (conj layout flag)))
|
||||
layout
|
||||
layout-flags-persistence-mapping)))
|
||||
|
||||
(defn persist-layout-flags!
|
||||
"Given a set of layout flags, and persist a subset of them to the Storage."
|
||||
|
||||
@@ -304,11 +304,8 @@
|
||||
(ptk/reify ::handle-drawing-end
|
||||
ptk/UpdateEvent
|
||||
(update [_ state]
|
||||
(let [content (dm/get-in state [:workspace-drawing :object :content])]
|
||||
|
||||
(assert (path/check-path-content content)
|
||||
"expected valid path content instance")
|
||||
|
||||
(let [content (some-> (dm/get-in state [:workspace-drawing :object :content])
|
||||
(path/check-path-content))]
|
||||
(if (> (count content) 1)
|
||||
(assoc-in state [:workspace-drawing :object :initialized?] true)
|
||||
state)))
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
(ns app.main.data.workspace.path.tools
|
||||
(:require
|
||||
[app.common.data.macros :as dm]
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.types.path :as path]
|
||||
[app.common.types.path.segment :as path.segment]
|
||||
[app.main.data.changes :as dch]
|
||||
@@ -48,12 +47,10 @@
|
||||
(changes/generate-path-changes it objects page-id shape (:content shape) new-content)]
|
||||
|
||||
(rx/concat
|
||||
(if (cfh/path-shape? shape)
|
||||
(rx/empty)
|
||||
(rx/of (dwsh/update-shapes [id] path/convert-to-path)))
|
||||
(rx/of (dch/commit-changes changes)
|
||||
(when (empty? new-content)
|
||||
(dwe/clear-edition-mode)))))))))))
|
||||
(rx/of (dwsh/update-shapes [id] path/convert-to-path)
|
||||
(dch/commit-changes changes))
|
||||
(when (empty? new-content)
|
||||
(rx/of (dwe/clear-edition-mode)))))))))))
|
||||
|
||||
(defn make-corner
|
||||
([]
|
||||
|
||||
@@ -91,7 +91,8 @@
|
||||
on-change
|
||||
(fn [index]
|
||||
(fn [color]
|
||||
(st/emit! (dc/change-fill ids color index))))
|
||||
(let [color (select-keys color ctc/color-attrs)]
|
||||
(st/emit! (dc/change-fill ids color index)))))
|
||||
|
||||
on-reorder
|
||||
(fn [new-index]
|
||||
|
||||
Reference in New Issue
Block a user