mirror of
https://github.com/penpot/penpot.git
synced 2025-12-24 06:58:34 -05:00
Compare commits
72 Commits
niwinz-dev
...
staging
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
01ecde3bfa | ||
|
|
4000ec8762 | ||
|
|
bb5568e15a | ||
|
|
5cbcec3db6 | ||
|
|
fe44c14bac | ||
|
|
336173645e | ||
|
|
83bb4bf221 | ||
|
|
15ed25ca79 | ||
|
|
9aa387a473 | ||
|
|
67ba91b4b9 | ||
|
|
f67f1a6a0e | ||
|
|
82d3e2024e | ||
|
|
4bd846c16d | ||
|
|
94f95ca6b8 | ||
|
|
507bf7445b | ||
|
|
81b72c5acd | ||
|
|
974495e08f | ||
|
|
2ed39e43c3 | ||
|
|
50dbe6ab12 | ||
|
|
2f46cbc0d4 | ||
|
|
53be6f996b | ||
|
|
5a260294a1 | ||
|
|
3f6e44316e | ||
|
|
77ef8e6fe6 | ||
|
|
916b7709dc | ||
|
|
443e41fea4 | ||
|
|
c7c9b04095 | ||
|
|
c61a0c0332 | ||
|
|
8707ff6511 | ||
|
|
3d8a251741 | ||
|
|
34e84ee3c8 | ||
|
|
e8201402a7 | ||
|
|
8a22477b96 | ||
|
|
3e684ea54f | ||
|
|
98039f13d8 | ||
|
|
40c27591f6 | ||
|
|
91d20a46d1 | ||
|
|
50bead7c56 | ||
|
|
b75b999903 | ||
|
|
810f1721c8 | ||
|
|
a4646373cf | ||
|
|
f111cbb2a4 | ||
|
|
a614207f7e | ||
|
|
6ce3249c6d | ||
|
|
b0351be724 | ||
|
|
b8392b3731 | ||
|
|
77dba477ca | ||
|
|
b6598d1f07 | ||
|
|
bf1dc21c75 | ||
|
|
46c20a993f | ||
|
|
0e0106f69a | ||
|
|
19bb69cc60 | ||
|
|
504eb70988 | ||
|
|
75a2331edf | ||
|
|
c2b4c9907d | ||
|
|
bd5bbcae26 | ||
|
|
84273508ad | ||
|
|
9245ba6bc2 | ||
|
|
4be046406d | ||
|
|
84c747cd31 | ||
|
|
0036a9a0cd | ||
|
|
2105c3a68c | ||
|
|
38efa88460 | ||
|
|
6e254c2cf4 | ||
|
|
94af978be8 | ||
|
|
feababe2a8 | ||
|
|
5ef06685fc | ||
|
|
57fcec5afc | ||
|
|
58f82da61e | ||
|
|
a28c5b61ca | ||
|
|
95b7784a42 | ||
|
|
4690f740b9 |
18
.github/workflows/build-tag.yml
vendored
18
.github/workflows/build-tag.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
secrets: inherit
|
||||
with:
|
||||
gh_ref: ${{ github.ref_name }}
|
||||
build_wasm: "no"
|
||||
build_wasm: "yes"
|
||||
build_storybook: "yes"
|
||||
|
||||
build-docker:
|
||||
@@ -21,6 +21,22 @@ jobs:
|
||||
with:
|
||||
gh_ref: ${{ github.ref_name }}
|
||||
|
||||
notify:
|
||||
name: Notifications
|
||||
runs-on: ubuntu-24.04
|
||||
needs: build-docker
|
||||
|
||||
steps:
|
||||
- name: Notify Mattermost
|
||||
uses: mattermost/action-mattermost-notify@master
|
||||
with:
|
||||
MATTERMOST_WEBHOOK_URL: ${{ secrets.MATTERMOST_WEBHOOK }}
|
||||
MATTERMOST_CHANNEL: bot-alerts-cicd
|
||||
TEXT: |
|
||||
🐳 *[PENPOT] Docker image available.*
|
||||
🔗 Run: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
@infra
|
||||
|
||||
publish-final-tag:
|
||||
if: ${{ !contains(github.ref_name, '-RC') && !contains(github.ref_name, '-alpha') && !contains(github.ref_name, '-beta') && contains(github.ref_name, '.') }}
|
||||
needs: build-docker
|
||||
|
||||
@@ -62,6 +62,7 @@ example. It's still usable as before, we just removed the example.
|
||||
|
||||
- Ensure consistent snap behavior across all zoom levels [Github #7774](https://github.com/penpot/penpot/pull/7774) by [@Tokytome](https://github.com/Tokytome)
|
||||
- Fix crash in token grid view due to tooltip validation (by @dfelinto) [Github #7887](https://github.com/penpot/penpot/pull/7887)
|
||||
- Enable Hindi translations on the application
|
||||
|
||||
### :sparkles: New features & Enhancements
|
||||
|
||||
@@ -90,6 +91,12 @@ example. It's still usable as before, we just removed the example.
|
||||
- Fix copy/pasting application/transit+json [Taiga #12721](https://tree.taiga.io/project/penpot/issue/12721)
|
||||
- Fix problem with plugins content attribute [Plugins #209](https://github.com/penpot/penpot-plugins/issues/209)
|
||||
- Fix U and E icon displayed in project list [Taiga #12806](https://tree.taiga.io/project/penpot/issue/12806)
|
||||
- Fix unpublish library modal not scrolling a long file list [Taiga #12285](https://tree.taiga.io/project/penpot/issue/12285)
|
||||
- Fix incorrect interaction betwen hower and scroll on assets sidebar [Taiga #12389](https://tree.taiga.io/project/penpot/issue/12389)
|
||||
- Fix switch variants with paths [Taiga #12841](https://tree.taiga.io/project/penpot/issue/12841)
|
||||
- Fix referencing typography tokens on font-family tokens [Taiga #12492](https://tree.taiga.io/project/penpot/issue/12492)
|
||||
- Fix horizontal scroll on layer panel [Taiga #12843](https://tree.taiga.io/project/penpot/issue/12843)
|
||||
- Fix unicode handling on email template abbreviation filter [Github #7966](https://github.com/penpot/penpot/pull/7966)
|
||||
|
||||
## 2.11.1
|
||||
|
||||
|
||||
@@ -240,4 +240,4 @@
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
:file-uri "https://github.com/penpot/penpot-files/raw/refs/heads/main/Tokens%20starter%20kit.penpot"}
|
||||
{:id "penpot-design-system"
|
||||
:name "Penpot Design System | Pencil"
|
||||
:file-uri "https://github.com/penpot/penpot-files/raw/refs/heads/main/penpot-app.penpot"}
|
||||
:file-uri "https://github.com/penpot/penpot-files/raw/refs/heads/main/Pencil-Penpot-Design-System.penpot"}
|
||||
{:id "wireframing-kit"
|
||||
:name "Wireframe library"
|
||||
:file-uri "https://github.com/penpot/penpot-files/raw/refs/heads/main/Wireframing%20kit%20v1.1.penpot"}
|
||||
|
||||
@@ -821,9 +821,10 @@
|
||||
entries (keep (match-storage-entry-fn) entries)]
|
||||
|
||||
(doseq [{:keys [id entry]} entries]
|
||||
(let [object (->> (read-entry input entry)
|
||||
(decode-storage-object)
|
||||
(validate-storage-object))
|
||||
(let [object (-> (read-entry input entry)
|
||||
(decode-storage-object)
|
||||
(update :bucket d/nilv sto/default-bucket)
|
||||
(validate-storage-object))
|
||||
|
||||
ext (cmedia/mtype->extension (:content-type object))
|
||||
path (str "objects/" id ext)
|
||||
|
||||
@@ -106,17 +106,17 @@
|
||||
(let [content-part (MimeBodyPart.)
|
||||
alternative-mpart (MimeMultipart. "alternative")]
|
||||
|
||||
(when-let [content (get body "text/plain")]
|
||||
(let [text-part (MimeBodyPart.)]
|
||||
(.setText text-part ^String content ^String charset)
|
||||
(.addBodyPart alternative-mpart text-part)))
|
||||
|
||||
(when-let [content (get body "text/html")]
|
||||
(let [html-part (MimeBodyPart.)]
|
||||
(.setContent html-part ^String content
|
||||
(str "text/html; charset=" charset))
|
||||
(.addBodyPart alternative-mpart html-part)))
|
||||
|
||||
(when-let [content (get body "text/plain")]
|
||||
(let [text-part (MimeBodyPart.)]
|
||||
(.setText text-part ^String content ^String charset)
|
||||
(.addBodyPart alternative-mpart text-part)))
|
||||
|
||||
(.setContent content-part alternative-mpart)
|
||||
(.addBodyPart mixed-mpart content-part))
|
||||
|
||||
|
||||
@@ -79,18 +79,6 @@
|
||||
(remove #(contains? reserved-props (key %))))
|
||||
props))
|
||||
|
||||
(defn event-from-rpc-params
|
||||
"Create a base event skeleton with pre-filled some important
|
||||
data that can be extracted from RPC params object"
|
||||
[params]
|
||||
(let [context {:external-session-id (::rpc/external-session-id params)
|
||||
:external-event-origin (::rpc/external-event-origin params)
|
||||
:triggered-by (::rpc/handler-name params)}]
|
||||
{::type "action"
|
||||
::profile-id (::rpc/profile-id params)
|
||||
::ip-addr (::rpc/ip-addr params)
|
||||
::context (d/without-nils context)}))
|
||||
|
||||
(defn get-external-session-id
|
||||
[request]
|
||||
(when-let [session-id (yreq/get-header request "x-external-session-id")]
|
||||
@@ -99,13 +87,24 @@
|
||||
(str/blank? session-id))
|
||||
session-id)))
|
||||
|
||||
(defn- get-external-event-origin
|
||||
(defn- get-client-event-origin
|
||||
[request]
|
||||
(when-let [origin (yreq/get-header request "x-event-origin")]
|
||||
(when-not (or (> (count origin) 256)
|
||||
(= origin "null")
|
||||
(when-not (or (= origin "null")
|
||||
(str/blank? origin))
|
||||
origin)))
|
||||
(str/prune origin 200))))
|
||||
|
||||
(defn get-client-user-agent
|
||||
[request]
|
||||
(when-let [user-agent (yreq/get-header request "user-agent")]
|
||||
(str/prune user-agent 500)))
|
||||
|
||||
(defn- get-client-version
|
||||
[request]
|
||||
(when-let [origin (yreq/get-header request "x-frontend-version")]
|
||||
(when-not (or (= origin "null")
|
||||
(str/blank? origin))
|
||||
(str/prune origin 100))))
|
||||
|
||||
;; --- SPECS
|
||||
|
||||
@@ -134,6 +133,33 @@
|
||||
(def ^:private check-event
|
||||
(sm/check-fn schema:event))
|
||||
|
||||
(defn- prepare-context-from-request
|
||||
[request]
|
||||
(let [client-event-origin (get-client-event-origin request)
|
||||
client-version (get-client-version request)
|
||||
client-user-agent (get-client-user-agent request)
|
||||
session-id (get-external-session-id request)
|
||||
token-id (::actoken/id request)]
|
||||
(d/without-nils
|
||||
{:external-session-id session-id
|
||||
:access-token-id (some-> token-id str)
|
||||
:client-event-origin client-event-origin
|
||||
:client-user-agent client-user-agent
|
||||
:client-version client-version
|
||||
:version (:full cf/version)})))
|
||||
|
||||
(defn event-from-rpc-params
|
||||
"Create a base event skeleton with pre-filled some important
|
||||
data that can be extracted from RPC params object"
|
||||
[params]
|
||||
(let [context (some-> params meta ::http/request prepare-context-from-request)
|
||||
event {::type "action"
|
||||
::profile-id (or (::rpc/profile-id params) uuid/zero)
|
||||
::ip-addr (::rpc/ip-addr params)}]
|
||||
(cond-> event
|
||||
(some? context)
|
||||
(assoc ::context context))))
|
||||
|
||||
(defn prepare-event
|
||||
[cfg mdata params result]
|
||||
(let [resultm (meta result)
|
||||
@@ -148,18 +174,10 @@
|
||||
(merge (::props resultm))
|
||||
(dissoc :profile-id)
|
||||
(dissoc :type)))
|
||||
|
||||
(clean-props))
|
||||
|
||||
token-id (::actoken/id request)
|
||||
context (-> (::context resultm)
|
||||
(assoc :external-session-id
|
||||
(get-external-session-id request))
|
||||
(assoc :external-event-origin
|
||||
(get-external-event-origin request))
|
||||
(assoc :access-token-id (some-> token-id str))
|
||||
(d/without-nils))
|
||||
|
||||
context (merge (::context resultm)
|
||||
(prepare-context-from-request request))
|
||||
ip-addr (inet/parse-request request)]
|
||||
|
||||
{::type (or (::type resultm)
|
||||
|
||||
@@ -307,7 +307,8 @@
|
||||
:content-type (:mtype input)})]
|
||||
(:id sobject))
|
||||
(catch Throwable cause
|
||||
(l/err :hint "unable to import profile picture"
|
||||
(l/wrn :hint "unable to import profile picture"
|
||||
:uri uri
|
||||
:cause cause)
|
||||
nil)))
|
||||
|
||||
|
||||
@@ -104,28 +104,29 @@
|
||||
(def ^:private schema:limit
|
||||
[:and
|
||||
[:map
|
||||
[::name :any]
|
||||
[::name :keyword]
|
||||
[::strategy schema:strategy]
|
||||
[::key :string]
|
||||
[::opts :string]]
|
||||
[:or
|
||||
[:map
|
||||
[::capacity ::sm/int]
|
||||
[::rate ::sm/int]
|
||||
[::internal ::ct/duration]
|
||||
[::params [::sm/vec :any]]]
|
||||
[:map
|
||||
[::nreq ::sm/int]
|
||||
[::unit [:enum :days :hours :minutes :seconds :weeks]]]]])
|
||||
[::opts :string]
|
||||
[::capacity {:optional true} ::sm/int]
|
||||
[::rate {:optional true} ::sm/int]
|
||||
[::interval {:optional true} ::ct/duration]
|
||||
[::params {:optional true} [::sm/vec :any]]
|
||||
[::permits {:optional true} ::sm/int]
|
||||
[::unit {:optional true} [:enum :days :hours :minutes :seconds :weeks]]]
|
||||
[:fn (fn [attrs]
|
||||
(let [contains-fn (partial contains? attrs)]
|
||||
(or (every? contains-fn [::capacity ::rate ::interval])
|
||||
(every? contains-fn [::permits ::unit]))))]])
|
||||
|
||||
(def ^:private schema:limits
|
||||
[:map-of :keyword [::sm/vec schema:limit]])
|
||||
|
||||
(def ^:private valid-limit-tuple?
|
||||
(sm/lazy-validator schema:limit-tuple))
|
||||
(sm/validator schema:limit-tuple))
|
||||
|
||||
(def ^:private valid-rlimit-instance?
|
||||
(sm/lazy-validator ::rpc/rlimit))
|
||||
(sm/validator ::rpc/rlimit))
|
||||
|
||||
(defmethod parse-limit :window
|
||||
[[name strategy opts :as vlimit]]
|
||||
@@ -134,16 +135,16 @@
|
||||
(merge
|
||||
{::name name
|
||||
::strategy strategy}
|
||||
(if-let [[_ nreq unit] (re-find window-opts-re opts)]
|
||||
(let [nreq (parse-long nreq)]
|
||||
{::nreq nreq
|
||||
(if-let [[_ permits unit] (re-find window-opts-re opts)]
|
||||
(let [permits (parse-long permits)]
|
||||
{::permits permits
|
||||
::unit (case unit
|
||||
"d" :days
|
||||
"h" :hours
|
||||
"m" :minutes
|
||||
"s" :seconds
|
||||
"w" :weeks)
|
||||
::key (str "ratelimit.window." (d/name name))
|
||||
::key (str "penpot.rlimit." (cf/get :tenant) ".window." (d/name name))
|
||||
::opts opts})
|
||||
(ex/raise :type :validation
|
||||
:code :invalid-window-limit-opts
|
||||
@@ -164,15 +165,15 @@
|
||||
::interval interval
|
||||
::opts opts
|
||||
::params [(->seconds interval) rate capacity]
|
||||
::key (str "ratelimit.bucket." (d/name name))})
|
||||
::key (str "penpot.rlimit." (cf/get :tenant) ".bucket." (d/name name))})
|
||||
(ex/raise :type :validation
|
||||
:code :invalid-bucket-limit-opts
|
||||
:hint (str/ffmt "looks like '%' does not have a valid format" opts))))
|
||||
|
||||
(defmethod process-limit :bucket
|
||||
[rconn user-id now {:keys [::key ::params ::service ::capacity ::interval ::rate] :as limit}]
|
||||
[rconn profile-id now {:keys [::key ::params ::service ::capacity ::interval ::rate] :as limit}]
|
||||
(let [script (-> bucket-rate-limit-script
|
||||
(assoc ::rscript/keys [(str key "." service "." user-id)])
|
||||
(assoc ::rscript/keys [(str key "." service "." profile-id)])
|
||||
(assoc ::rscript/vals (conj params (->seconds now))))
|
||||
result (rds/eval rconn script)
|
||||
allowed? (boolean (nth result 0))
|
||||
@@ -192,18 +193,18 @@
|
||||
(assoc ::lresult/remaining remaining))))
|
||||
|
||||
(defmethod process-limit :window
|
||||
[rconn user-id now {:keys [::nreq ::unit ::key ::service] :as limit}]
|
||||
[rconn profile-id now {:keys [::permits ::unit ::key ::service] :as limit}]
|
||||
(let [ts (ct/truncate now unit)
|
||||
ttl (ct/diff now (ct/plus ts {unit 1}))
|
||||
script (-> window-rate-limit-script
|
||||
(assoc ::rscript/keys [(str key "." service "." user-id "." (ct/format-inst ts))])
|
||||
(assoc ::rscript/vals [nreq (->seconds ttl)]))
|
||||
(assoc ::rscript/keys [(str key "." service "." profile-id "." (ct/format-inst ts))])
|
||||
(assoc ::rscript/vals [permits (->seconds ttl)]))
|
||||
result (rds/eval rconn script)
|
||||
allowed? (boolean (nth result 0))
|
||||
remaining (nth result 1)]
|
||||
(l/trace :hint "limit processed"
|
||||
:service service
|
||||
:limit (name (::name limit))
|
||||
:name (name (::name limit))
|
||||
:strategy (name (::strategy limit))
|
||||
:opts (::opts limit)
|
||||
:allowed allowed?
|
||||
@@ -214,8 +215,8 @@
|
||||
(assoc ::lresult/reset (ct/plus ts {unit 1})))))
|
||||
|
||||
(defn- process-limits
|
||||
[rconn user-id limits now]
|
||||
(let [results (into [] (map (partial process-limit rconn user-id now)) limits)
|
||||
[rconn profile-id limits now]
|
||||
(let [results (into [] (map (partial process-limit rconn profile-id now)) limits)
|
||||
remaining (->> results
|
||||
(d/index-by ::name ::lresult/remaining)
|
||||
(uri/map->query-string))
|
||||
@@ -227,7 +228,7 @@
|
||||
|
||||
(when rejected
|
||||
(l/warn :hint "rejected rate limit"
|
||||
:user-id (str user-id)
|
||||
:profile-id (str profile-id)
|
||||
:limit-service (-> rejected ::service name)
|
||||
:limit-name (-> rejected ::name name)
|
||||
:limit-strategy (-> rejected ::strategy name)))
|
||||
@@ -371,12 +372,9 @@
|
||||
(defn- on-refresh-error
|
||||
[_ cause]
|
||||
(when-not (instance? java.util.concurrent.RejectedExecutionException cause)
|
||||
(if-let [explain (-> cause ex-data ex/explain)]
|
||||
(l/warn ::l/raw (str "unable to refresh config, invalid format:\n" explain)
|
||||
::l/sync? true)
|
||||
(l/warn :hint "unexpected exception on loading config"
|
||||
:cause cause
|
||||
::l/sync? true))))
|
||||
(l/warn :hint "unexpected exception on loading config"
|
||||
:cause cause
|
||||
::l/sync? true)))
|
||||
|
||||
(defn- get-config-path
|
||||
[]
|
||||
|
||||
@@ -25,9 +25,9 @@ local allowed = filled >= requested
|
||||
local newTokens = filled
|
||||
if allowed then
|
||||
newTokens = filled - requested
|
||||
redis.call("hset", tokensKey, "tokens", newTokens, "timestamp", timestamp)
|
||||
end
|
||||
|
||||
redis.call("hset", tokensKey, "tokens", newTokens, "timestamp", timestamp)
|
||||
redis.call("expire", tokensKey, ttl)
|
||||
|
||||
return { allowed, newTokens }
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
:assets-s3 :s3
|
||||
nil)))
|
||||
|
||||
(def default-bucket
|
||||
"file-media-object")
|
||||
|
||||
(def valid-buckets
|
||||
#{"file-media-object"
|
||||
"team-font-variant"
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
[app.common.time :as ct]
|
||||
[app.config :as cf]
|
||||
[app.db :as db]
|
||||
[app.storage :as-alias sto]
|
||||
[app.storage :as sto]
|
||||
[app.storage.impl :as impl]
|
||||
[integrant.core :as ig]))
|
||||
|
||||
@@ -130,7 +130,7 @@
|
||||
[{:keys [metadata]}]
|
||||
(or (some-> metadata :bucket)
|
||||
(some-> metadata :reference d/name)
|
||||
"file-media-object"))
|
||||
sto/default-bucket))
|
||||
|
||||
(defn- process-objects!
|
||||
[conn has-refs? bucket objects]
|
||||
|
||||
@@ -7,10 +7,18 @@
|
||||
(ns app.util.template
|
||||
(:require
|
||||
[app.common.exceptions :as ex]
|
||||
[cuerdas.core :as str]
|
||||
[selmer.filters :as sf]
|
||||
[selmer.parser :as sp]))
|
||||
|
||||
;; (sp/cache-off!)
|
||||
|
||||
(sf/add-filter! :abbreviate
|
||||
(fn [s n]
|
||||
(let [n (parse-long n)]
|
||||
(str/abbreviate s n))))
|
||||
|
||||
|
||||
(defn render
|
||||
[path context]
|
||||
(try
|
||||
|
||||
@@ -137,33 +137,34 @@ RETURNING task.id, task.queue")
|
||||
::wait)))
|
||||
|
||||
(run-batch []
|
||||
(let [rconn (rds/connect cfg)]
|
||||
(try
|
||||
(-> cfg
|
||||
(assoc ::rds/conn rconn)
|
||||
(db/tx-run! run-batch'))
|
||||
(try
|
||||
(let [rconn (rds/connect cfg)]
|
||||
(try
|
||||
(-> cfg
|
||||
(assoc ::rds/conn rconn)
|
||||
(db/tx-run! run-batch'))
|
||||
(finally
|
||||
(.close ^AutoCloseable rconn))))
|
||||
|
||||
(catch InterruptedException cause
|
||||
(throw cause))
|
||||
(catch Exception cause
|
||||
(cond
|
||||
(rds/exception? cause)
|
||||
(do
|
||||
(l/wrn :hint "redis exception (will retry in an instant)" :cause cause)
|
||||
(px/sleep timeout))
|
||||
(catch InterruptedException cause
|
||||
(throw cause))
|
||||
|
||||
(db/sql-exception? cause)
|
||||
(do
|
||||
(l/wrn :hint "database exception (will retry in an instant)" :cause cause)
|
||||
(px/sleep timeout))
|
||||
(catch Exception cause
|
||||
(cond
|
||||
(rds/exception? cause)
|
||||
(do
|
||||
(l/wrn :hint "redis exception (will retry in an instant)" :cause cause)
|
||||
(px/sleep timeout))
|
||||
|
||||
:else
|
||||
(do
|
||||
(l/err :hint "unhandled exception (will retry in an instant)" :cause cause)
|
||||
(px/sleep timeout))))
|
||||
(db/sql-exception? cause)
|
||||
(do
|
||||
(l/wrn :hint "database exception (will retry in an instant)" :cause cause)
|
||||
(px/sleep timeout))
|
||||
|
||||
(finally
|
||||
(.close ^AutoCloseable rconn)))))
|
||||
:else
|
||||
(do
|
||||
(l/err :hint "unhandled exception (will retry in an instant)" :cause cause)
|
||||
(px/sleep timeout))))))
|
||||
|
||||
(dispatcher []
|
||||
(l/inf :hint "started")
|
||||
@@ -176,7 +177,7 @@ RETURNING task.id, task.queue")
|
||||
(catch InterruptedException _
|
||||
(l/trc :hint "interrupted"))
|
||||
(catch Throwable cause
|
||||
(l/err :hint " unexpected exception" :cause cause))
|
||||
(l/err :hint "unexpected exception" :cause cause))
|
||||
(finally
|
||||
(l/inf :hint "terminated"))))]
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
integrant/integrant {:mvn/version "1.0.0"}
|
||||
|
||||
funcool/tubax {:mvn/version "2021.05.20-0"}
|
||||
funcool/cuerdas {:mvn/version "2025.06.16-414"}
|
||||
funcool/cuerdas {:mvn/version "2026.415"}
|
||||
funcool/promesa
|
||||
{:git/sha "46048fc0d4bf5466a2a4121f5d52aefa6337f2e8"
|
||||
:git/url "https://github.com/funcool/promesa"}
|
||||
|
||||
@@ -12,8 +12,11 @@
|
||||
[app.common.files.changes-builder :as pcb]
|
||||
[app.common.files.helpers :as cfh]
|
||||
[app.common.files.variant :as cfv]
|
||||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.geom.rect :as grc]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.geom.shapes.common :as gco]
|
||||
[app.common.logging :as log]
|
||||
[app.common.logic.shapes :as cls]
|
||||
[app.common.logic.variant-properties :as clvp]
|
||||
@@ -26,6 +29,7 @@
|
||||
[app.common.types.library :as ctl]
|
||||
[app.common.types.page :as ctp]
|
||||
[app.common.types.pages-list :as ctpl]
|
||||
[app.common.types.path.segment :as segment]
|
||||
[app.common.types.shape :as cts]
|
||||
[app.common.types.shape-tree :as ctst]
|
||||
[app.common.types.shape.interactions :as ctsi]
|
||||
@@ -1876,6 +1880,44 @@
|
||||
roperations'
|
||||
uoperations')))))))
|
||||
|
||||
(defn- set-path-new-values
|
||||
[current-shape prev-shape transform]
|
||||
(let [new-content (segment/transform-content
|
||||
(:content current-shape)
|
||||
(gmt/transform-in (gpt/point 0 0) transform))
|
||||
new-points (-> (segment/content->selrect new-content)
|
||||
(grc/rect->points))
|
||||
points-center (gco/points->center new-points)
|
||||
new-selrect (gsh/calculate-selrect new-points points-center)
|
||||
shape (assoc current-shape
|
||||
:content new-content
|
||||
:points new-points
|
||||
:selrect new-selrect)
|
||||
|
||||
prev-center (segment/content-center (:content prev-shape))
|
||||
delta (gpt/subtract points-center (first new-points))
|
||||
new-pos (gpt/subtract prev-center delta)]
|
||||
(gsh/absolute-move shape new-pos)))
|
||||
|
||||
(defn- switch-path-change-value
|
||||
[prev-shape ;; The shape before the switch
|
||||
current-shape ;; The shape after the switch (a clean copy)
|
||||
ref-shape ;; The referenced shape on the main component
|
||||
;; before the switch
|
||||
attr]
|
||||
(let [old-width (-> ref-shape :selrect :width)
|
||||
new-width (-> prev-shape :selrect :width)
|
||||
|
||||
old-height (-> ref-shape :selrect :height)
|
||||
new-height (-> prev-shape :selrect :height)
|
||||
|
||||
transform (-> (gpt/point (/ new-width old-width)
|
||||
(/ new-height old-height))
|
||||
(gmt/scale-matrix))
|
||||
|
||||
shape (set-path-new-values current-shape prev-shape transform)]
|
||||
(get shape attr)))
|
||||
|
||||
|
||||
(defn- switch-text-change-value
|
||||
[prev-content ;; The :content of the text before the switch
|
||||
@@ -2027,6 +2069,10 @@
|
||||
(= :content attr)
|
||||
(touched attr-group))
|
||||
|
||||
path-change?
|
||||
(and (= :path (:type current-shape))
|
||||
(contains? #{:points :selrect :content} attr))
|
||||
|
||||
;; position-data is a special case because can be affected by :geometry-group and :content-group
|
||||
;; so, if the position-data changes but the geometry is touched we need to reset the position-data
|
||||
;; so it's calculated again
|
||||
@@ -2055,6 +2101,12 @@
|
||||
(:content origin-ref-shape)
|
||||
touched)
|
||||
|
||||
path-change?
|
||||
(switch-path-change-value previous-shape
|
||||
current-shape
|
||||
origin-ref-shape
|
||||
attr)
|
||||
|
||||
:else
|
||||
(get previous-shape attr)))
|
||||
|
||||
|
||||
@@ -281,7 +281,20 @@
|
||||
(defn check-fn
|
||||
"Create a predefined check function"
|
||||
[s & {:keys [hint type code]}]
|
||||
(let [s (schema s)
|
||||
(let [s #?(:clj
|
||||
(schema s)
|
||||
:cljs
|
||||
(try
|
||||
(schema s)
|
||||
(catch :default cause
|
||||
(let [data (ex-data cause)]
|
||||
(if (= :malli.core/invalid-schema (:type data))
|
||||
(throw (ex-info
|
||||
(str "Invalid schema\n"
|
||||
(pp/pprint-str (:data data)))
|
||||
{}))
|
||||
(throw cause))))))
|
||||
|
||||
validator* (delay (m/validator s))
|
||||
explainer* (delay (m/explainer s))
|
||||
hint (or ^boolean hint "check error")
|
||||
|
||||
@@ -362,24 +362,24 @@
|
||||
component (ctkl/get-component component-file (:component-id top-instance) true)
|
||||
remote-shape (get-ref-shape component-file component shape)
|
||||
component-container (get-component-container component-file component)
|
||||
[remote-shape component-container]
|
||||
[remote-shape component-container component-file]
|
||||
(if (some? remote-shape)
|
||||
[remote-shape component-container]
|
||||
[remote-shape component-container component-file]
|
||||
;; If not found, try the case of this being a fostered or swapped children
|
||||
(let [head-instance (ctn/get-head-shape (:objects container) shape)
|
||||
component-file (get-in libraries [(:component-file head-instance) :data])
|
||||
head-component (ctkl/get-component component-file (:component-id head-instance) true)
|
||||
remote-shape' (get-ref-shape component-file head-component shape)
|
||||
component-container (get-component-container component-file component)]
|
||||
[remote-shape' component-container]))]
|
||||
(let [head-instance (ctn/get-head-shape (:objects container) shape)
|
||||
component-file (get-in libraries [(:component-file head-instance) :data])
|
||||
head-component (ctkl/get-component component-file (:component-id head-instance) true)
|
||||
remote-shape' (get-ref-shape component-file head-component shape)
|
||||
component-container' (get-component-container component-file head-component)]
|
||||
[remote-shape' component-container' component-file]))]
|
||||
|
||||
(if (nil? remote-shape)
|
||||
nil
|
||||
(if (nil? (:shape-ref remote-shape))
|
||||
(cond-> remote-shape
|
||||
(and remote-shape with-context?)
|
||||
(with-meta {:file {:id (:id file-data)
|
||||
:data file-data}
|
||||
(with-meta {:file {:id (:id component-file)
|
||||
:data component-file}
|
||||
:container component-container}))
|
||||
(find-remote-shape component-container libraries remote-shape :with-context? with-context?)))))
|
||||
|
||||
|
||||
@@ -1410,8 +1410,8 @@ Will return a value that matches this schema:
|
||||
;; NOTE: we can't assign statically at eval time the value of a
|
||||
;; function that is declared but not defined; so we need to pass
|
||||
;; an anonymous function and delegate the resolution to runtime
|
||||
{:encode/json #(export-dtcg-json %)
|
||||
:decode/json #(read-multi-set-dtcg %)
|
||||
{:encode/json #(some-> % export-dtcg-json)
|
||||
:decode/json #(some-> % read-multi-set-dtcg)
|
||||
;; FIXME: add better, more reallistic generator
|
||||
:gen/gen (->> (sg/small-int)
|
||||
(sg/fmap (fn [_]
|
||||
|
||||
@@ -223,16 +223,19 @@ http {
|
||||
add_header X-Cache-Status $upstream_cache_status;
|
||||
}
|
||||
|
||||
location ~ ^/(/|css|fonts|images|js|wasm|mjs|map) {
|
||||
location ~* \.(jpg|png|svg|ttf|woff|woff2)$ {
|
||||
add_header Cache-Control "public, max-age=604800" always; # 7 days
|
||||
}
|
||||
|
||||
location ~* \.(js|css|wasm)$ {
|
||||
add_header Cache-Control "no-store" always;
|
||||
}
|
||||
|
||||
location ~ ^/[^/]+/(.*)$ {
|
||||
return 301 " /404";
|
||||
}
|
||||
|
||||
add_header Cache-Control "no-store";
|
||||
# This header is what we need to use on prod
|
||||
# add_header Cache-Control "public, must-revalidate, max-age=0";
|
||||
add_header Cache-Control "no-store" always;
|
||||
try_files $uri /index.html$is_args$args /index.html =404;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
"raw-body": "^3.0.1",
|
||||
"source-map-support": "^0.5.21",
|
||||
"svgo": "penpot/svgo#v3.1",
|
||||
"undici": "^7.16.0",
|
||||
"xml-js": "^1.6.11",
|
||||
"xregexp": "^5.1.2"
|
||||
},
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
|
||||
(def browser-pool-factory
|
||||
(letfn [(create []
|
||||
(p/let [opts #js {:args #js ["--font-render-hinting=none"]}
|
||||
(p/let [opts #js {:args #js ["--allow-insecure-localhost" "--font-render-hinting=none"]}
|
||||
browser (.launch pw/chromium opts)
|
||||
id (swap! pool-browser-id inc)]
|
||||
(l/info :origin "factory" :action "create" :browser-id id)
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
(p/fmap (fn [resource]
|
||||
(assoc exchange :response/body resource)))
|
||||
(p/merr (fn [cause]
|
||||
(l/error :hint "unexpected error on export multiple"
|
||||
(l/error :hint "unexpected error on single export"
|
||||
:cause cause)
|
||||
(p/rejected cause))))))
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
(redis/pub! topic data))))
|
||||
|
||||
on-error (fn [cause]
|
||||
(l/error :hint "unexpected error on multiple exportation" :cause cause)
|
||||
(l/error :hint "unexpected error on multiple export" :cause cause)
|
||||
(if wait
|
||||
(p/rejected cause)
|
||||
(redis/pub! topic {:type :export-update
|
||||
@@ -107,12 +107,12 @@
|
||||
:on-progress on-progress)
|
||||
|
||||
append (fn [{:keys [filename path] :as resource}]
|
||||
(rsc/add-to-zip! zip path (str/replace filename sanitize-file-regex "_")))
|
||||
(rsc/add-to-zip zip path (str/replace filename sanitize-file-regex "_")))
|
||||
|
||||
proc (->> exports
|
||||
(map (fn [export] (rd/render export append)))
|
||||
(p/all)
|
||||
(p/fnly (fn [_] (.finalize zip)))
|
||||
(p/mcat (fn [_] (rsc/close-zip zip)))
|
||||
(p/fmap (constantly resource))
|
||||
(p/mcat (partial rsc/upload-resource auth-token))
|
||||
(p/fmap (fn [resource]
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
["node:fs" :as fs]
|
||||
["node:fs/promises" :as fsp]
|
||||
["node:path" :as path]
|
||||
["undici" :as http]
|
||||
[app.common.exceptions :as ex]
|
||||
[app.common.transit :as t]
|
||||
[app.common.uri :as u]
|
||||
@@ -53,30 +54,40 @@
|
||||
(.pipe zip out)
|
||||
zip))
|
||||
|
||||
(defn add-to-zip!
|
||||
(defn add-to-zip
|
||||
[zip path name]
|
||||
(.file ^js zip path #js {:name name}))
|
||||
|
||||
(defn close-zip!
|
||||
(defn close-zip
|
||||
[zip]
|
||||
(.finalize ^js zip))
|
||||
(p/create (fn [resolve]
|
||||
(.on ^js zip "close" resolve)
|
||||
(.finalize ^js zip))))
|
||||
|
||||
(defn upload-resource
|
||||
[auth-token resource]
|
||||
(->> (fsp/readFile (:path resource))
|
||||
(p/fmap (fn [buffer]
|
||||
(js/console.log buffer)
|
||||
(new js/Blob #js [buffer] #js {:type (:mtype resource)})))
|
||||
(p/mcat (fn [blob]
|
||||
(let [fdata (new js/FormData)
|
||||
uri (-> (cf/get :public-uri)
|
||||
(u/ensure-path-slash)
|
||||
(u/join "api/management/methods/upload-tempfile")
|
||||
(str))]
|
||||
(let [fdata (new http/FormData)
|
||||
agent (new http/Agent #js {:connect #js {:rejectUnauthorized false}})
|
||||
headers #js {"X-Shared-Key" cf/management-key
|
||||
"Authorization" (str "Bearer " auth-token)}
|
||||
|
||||
request #js {:headers headers
|
||||
:method "POST"
|
||||
:body fdata
|
||||
:dispatcher agent}
|
||||
uri (-> (cf/get :public-uri)
|
||||
(u/ensure-path-slash)
|
||||
(u/join "api/management/methods/upload-tempfile")
|
||||
(str))]
|
||||
|
||||
(.append fdata "content" blob (:filename resource))
|
||||
(js/fetch uri #js {:headers #js {"X-Shared-Key" cf/management-key
|
||||
"Authorization" (str "Bearer " auth-token)}
|
||||
:method "POST"
|
||||
:body fdata}))))
|
||||
(http/fetch uri request))))
|
||||
|
||||
(p/mcat (fn [response]
|
||||
(if (not= (.-status response) 200)
|
||||
(ex/raise :type :internal
|
||||
|
||||
@@ -75,7 +75,8 @@
|
||||
[path]
|
||||
(->> (.stat fs/promises path)
|
||||
(p/fmap (fn [data]
|
||||
{:created-at (inst-ms (.-ctime ^js data))
|
||||
{:path path
|
||||
:created-at (inst-ms (.-ctime ^js data))
|
||||
:size (.-size data)}))
|
||||
(p/merr (fn [_cause]
|
||||
(p/resolved nil)))))
|
||||
|
||||
@@ -582,6 +582,7 @@ __metadata:
|
||||
raw-body: "npm:^3.0.1"
|
||||
source-map-support: "npm:^0.5.21"
|
||||
svgo: "penpot/svgo#v3.1"
|
||||
undici: "npm:^7.16.0"
|
||||
ws: "npm:^8.18.3"
|
||||
xml-js: "npm:^1.6.11"
|
||||
xregexp: "npm:^5.1.2"
|
||||
@@ -1513,6 +1514,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"undici@npm:^7.16.0":
|
||||
version: 7.16.0
|
||||
resolution: "undici@npm:7.16.0"
|
||||
checksum: 10c0/efd867792e9f233facf9efa0a087e2d9c3e4415c0b234061b9b40307ca4fa01d945fee4d43c7b564e1b80e0d519bcc682f9f6e0de13c717146c00a80e2f1fb0f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"unique-filename@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "unique-filename@npm:4.0.0"
|
||||
|
||||
@@ -50,5 +50,8 @@
|
||||
|
||||
:shadow-cljs
|
||||
{:main-opts ["-m" "shadow.cljs.devtools.cli"]
|
||||
:jvm-opts ["--sun-misc-unsafe-memory-access=allow" "-Dpenpot.wasm.profile-marks=true"]}
|
||||
:jvm-opts ["--sun-misc-unsafe-memory-access=allow"
|
||||
"-Dpenpot.wasm.profile-marks=true"
|
||||
"-XX:+UnlockExperimentalVMOptions"
|
||||
"-XX:CompileCommand=blackhole,criterium.blackhole.Blackhole::consume"]}
|
||||
}}
|
||||
|
||||
@@ -45,9 +45,9 @@
|
||||
"translations": "node ./scripts/translations.js",
|
||||
"watch:app:assets": "node ./scripts/watch.js",
|
||||
"watch:app:libs": "node ./scripts/build-libs.js --watch",
|
||||
"watch:app:main": "clojure -M:dev:shadow-cljs watch main storybook",
|
||||
"watch:app:main": "clojure -M:dev:shadow-cljs watch main worker storybook",
|
||||
"clear:shadow-cache": "rm -rf .shadow-cljs",
|
||||
"watch:app": "yarn run clear:shadow-cache && yarn run build:app:worker && concurrently \"yarn run watch:app:main\" \"yarn run watch:app:libs\"",
|
||||
"watch:app": "yarn run clear:shadow-cache && concurrently \"yarn run watch:app:main\" \"yarn run watch:app:libs\"",
|
||||
"watch": "yarn run watch:app:assets",
|
||||
"watch:storybook": "yarn run build:storybook:assets && concurrently \"storybook dev -p 6006 --no-open\" \"yarn run watch:storybook:assets\"",
|
||||
"watch:storybook:assets": "node ./scripts/watch-storybook.js"
|
||||
@@ -106,7 +106,7 @@
|
||||
"@penpot/hljs": "portal:./vendor/hljs",
|
||||
"@penpot/mousetrap": "portal:./vendor/mousetrap",
|
||||
"@penpot/plugins-runtime": "1.3.2",
|
||||
"@penpot/svgo": "penpot/svgo#v3.1",
|
||||
"@penpot/svgo": "penpot/svgo#v3.2",
|
||||
"@penpot/text-editor": "portal:./text-editor",
|
||||
"@tokens-studio/sd-transforms": "1.2.11",
|
||||
"@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",
|
||||
|
||||
@@ -180,8 +180,8 @@ export async function watch(baseDir, predicate, callback) {
|
||||
});
|
||||
}
|
||||
|
||||
async function readManifestFile() {
|
||||
const manifestPath = "resources/public/js/manifest.json";
|
||||
async function readManifestFile(resource) {
|
||||
const manifestPath = "resources/public/" + resource;
|
||||
let content = await fs.readFile(manifestPath, { encoding: "utf8" });
|
||||
return JSON.parse(content);
|
||||
}
|
||||
@@ -189,19 +189,23 @@ async function readManifestFile() {
|
||||
async function readShadowManifest() {
|
||||
const ts = Date.now();
|
||||
try {
|
||||
const content = await readManifestFile();
|
||||
const content = await readManifestFile("js/manifest.json");
|
||||
|
||||
const index = {
|
||||
ts: ts,
|
||||
config: "js/config.js?ts=" + ts,
|
||||
polyfills: "js/polyfills.js?ts=" + ts,
|
||||
worker_main: "js/worker/main.js?ts=" + ts,
|
||||
};
|
||||
|
||||
for (let item of content) {
|
||||
index[item.name] = "js/" + item["output-name"];
|
||||
}
|
||||
|
||||
const content2 = await readManifestFile("js/worker/manifest.json");
|
||||
for (let item of content2) {
|
||||
index["worker_" + item.name] = "js/worker/" + item["output-name"];
|
||||
}
|
||||
|
||||
return index;
|
||||
} catch (cause) {
|
||||
return {
|
||||
@@ -274,6 +278,7 @@ async function readTranslations() {
|
||||
"id",
|
||||
"ru",
|
||||
"tr",
|
||||
"hi",
|
||||
"zh_CN",
|
||||
"zh_Hant",
|
||||
"hr",
|
||||
|
||||
@@ -20,21 +20,24 @@ echo $PATH
|
||||
set -ex
|
||||
|
||||
corepack enable;
|
||||
corepack install || exit 1;
|
||||
corepack install;
|
||||
yarn install || exit 1;
|
||||
|
||||
rm -rf resources/public;
|
||||
rm -rf target/dist;
|
||||
rm -rf resources/public;
|
||||
|
||||
yarn run build:app:main --config-merge "{:release-version \"${CURRENT_HASH}-${TS}\"}" $EXTRA_PARAMS || exit 1
|
||||
mkdir -p resources/public;
|
||||
|
||||
if [ "$INCLUDE_WASM" = "yes" ]; then
|
||||
yarn run build:wasm || exit 1;
|
||||
fi
|
||||
pushd ../render-wasm;
|
||||
./build
|
||||
popd
|
||||
|
||||
yarn run build:app:main --config-merge "{:release-version \"${CURRENT_HASH}-${TS}\"}" $EXTRA_PARAMS;
|
||||
yarn run build:app:libs || exit 1;
|
||||
yarn run build:app:assets || exit 1;
|
||||
|
||||
sed -i "s/\.\/render.js/.\/render.js?version=$CURRENT_VERSION/g" resources/public/js/worker/main*.js
|
||||
|
||||
mkdir -p target/dist;
|
||||
rsync -avr resources/public/ target/dist/
|
||||
|
||||
@@ -44,10 +47,6 @@ sed -i -re "s/\%version\%/$CURRENT_VERSION/g" ./target/dist/rasterizer.html;
|
||||
sed -i -re "s/\%buildDate\%/$BUILD_DATE/g" ./target/dist/index.html;
|
||||
sed -i -re "s/\%buildDate\%/$BUILD_DATE/g" ./target/dist/rasterizer.html;
|
||||
|
||||
if [ "$INCLUDE_WASM" = "yes" ]; then
|
||||
sed -i "s/version=develop/version=$CURRENT_VERSION/g" ./target/dist/js/render_wasm.js;
|
||||
fi
|
||||
|
||||
if [ "$INCLUDE_STORYBOOK" = "yes" ]; then
|
||||
# build storybook
|
||||
yarn run build:storybook || exit 1;
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
:source-map-detail-level :all}}}
|
||||
|
||||
:worker
|
||||
{:target :esm
|
||||
{:target :browser
|
||||
:output-dir "resources/public/js/worker/"
|
||||
:asset-path "/js/worker"
|
||||
:devtools {:browser-inject :main
|
||||
@@ -94,6 +94,7 @@
|
||||
{:main
|
||||
{:entries [app.worker]
|
||||
:web-worker true
|
||||
:prepend-js "importScripts('./render.js');"
|
||||
:depends-on #{}}}
|
||||
|
||||
:js-options
|
||||
|
||||
@@ -127,7 +127,7 @@
|
||||
public-uri))
|
||||
|
||||
(def worker-uri
|
||||
(obj/get global "penpotWorkerURI" "/js/worker.js"))
|
||||
(obj/get global "penpotWorkerURI" "/js/worker/main.js"))
|
||||
|
||||
(defn external-feature-flag
|
||||
[flag value]
|
||||
@@ -189,7 +189,11 @@
|
||||
(true? thumbnail?) (u/join (dm/str id "/thumbnail"))
|
||||
(false? thumbnail?) (u/join (dm/str id)))))))
|
||||
|
||||
(defn resolve-static-asset
|
||||
[path]
|
||||
(let [uri (u/join public-uri path)]
|
||||
(assoc uri :query (dm/str "version=" (:full version)))))
|
||||
(defn resolve-href
|
||||
[resource]
|
||||
(let [version (get version :full)
|
||||
href (-> public-uri
|
||||
(u/ensure-path-slash)
|
||||
(u/join resource)
|
||||
(get :path))]
|
||||
(str href "?version=" version)))
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
[]
|
||||
(let [uagent (new ua/UAParser)]
|
||||
(merge
|
||||
{:app-version (:full cf/version)
|
||||
{:version (:full cf/version)
|
||||
:locale @i18n/locale}
|
||||
(let [browser (.getBrowser uagent)]
|
||||
{:browser (obj/get browser "name")
|
||||
|
||||
@@ -255,14 +255,19 @@
|
||||
|
||||
(defn- parse-sd-token-font-family-value
|
||||
[value]
|
||||
(let [missing-references (seq (some cto/find-token-value-references value))]
|
||||
(let [value (-> (js->clj value) (flatten))
|
||||
valid-font-family (or (string? value) (every? string? value))
|
||||
missing-references (seq (some cto/find-token-value-references value))]
|
||||
(cond
|
||||
(not valid-font-family)
|
||||
{:errors [(wte/error-with-value :error.style-dictionary/invalid-token-value-font-family value)]}
|
||||
|
||||
missing-references
|
||||
{:errors [(wte/error-with-value :error.style-dictionary/missing-reference missing-references)]
|
||||
:references missing-references}
|
||||
|
||||
:else
|
||||
{:value (-> (js->clj value) (flatten))})))
|
||||
{:value value})))
|
||||
|
||||
(defn parse-atomic-typography-value [token-type token-value]
|
||||
(case token-type
|
||||
|
||||
@@ -351,19 +351,31 @@
|
||||
(on-success))))
|
||||
(rx/catch on-error))))))
|
||||
|
||||
|
||||
(def ^:private schema:create-invitation
|
||||
[:and
|
||||
[:map
|
||||
[:emails {:optional true} [::sm/set ::sm/email]]
|
||||
[:invitations {:optional true}
|
||||
[:vector
|
||||
[:map
|
||||
[:email ::sm/email]
|
||||
[:role [::sm/one-of ctt/valid-roles]]]]]
|
||||
[:team-id ::sm/uuid]
|
||||
[:resend? {:optional true} ::sm/boolean]]
|
||||
[:fn (fn [attrs]
|
||||
(or (contains? attrs :emails)
|
||||
(contains? attrs :invitations)))]])
|
||||
|
||||
(def ^:private check-create-invitations-params
|
||||
(sm/check-fn schema:create-invitation))
|
||||
|
||||
(defn create-invitations
|
||||
"Unified function to create invitations. Supports two parameter formats:
|
||||
1. {:emails #{...} :role :admin :team-id uuid} - single role for all emails
|
||||
2. {:invitations [{:email ... :role ...}] :team-id uuid} - individual roles per email"
|
||||
[{:keys [emails role team-id invitations resend?] :as params}]
|
||||
|
||||
(assert (uuid? team-id))
|
||||
;; Validate input format - must have either emails+role OR invitations
|
||||
(assert (or (and emails role (sm/check-set-of-emails emails) (keyword? role))
|
||||
(and invitations
|
||||
(sm/check-set-of-emails (map :email invitations))
|
||||
(every? #(contains? ctt/valid-roles (:role %)) invitations)))
|
||||
"Must provide either emails+role or invitations with individual roles")
|
||||
(check-create-invitations-params params)
|
||||
|
||||
(ptk/reify ::create-invitations
|
||||
ev/Event
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
[app.common.types.fills :as types.fills]
|
||||
[app.common.types.library :as ctl]
|
||||
[app.common.types.shape :as shp]
|
||||
[app.common.types.shape.shadow :refer [check-shadow]]
|
||||
[app.common.types.shape.shadow :as types.shadow]
|
||||
[app.common.types.text :as txt]
|
||||
[app.main.broadcast :as mbc]
|
||||
[app.main.data.helpers :as dsh]
|
||||
@@ -406,30 +406,30 @@
|
||||
|
||||
(defn change-shadow
|
||||
[ids attrs index]
|
||||
(ptk/reify ::change-shadow
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(rx/of (dwsh/update-shapes
|
||||
ids
|
||||
(fn [shape]
|
||||
(let [;; If we try to set a gradient to a shadow (for
|
||||
;; example using the color selection from
|
||||
;; multiple shapes) let's use the first stop
|
||||
;; color
|
||||
attrs (cond-> attrs
|
||||
(:gradient attrs)
|
||||
(dm/get-in [:gradient :stops 0]))
|
||||
(letfn [(update-shadow [shape]
|
||||
(let [;; If we try to set a gradient to a shadow (for
|
||||
;; example using the color selection from
|
||||
;; multiple shapes) let's use the first stop
|
||||
;; color
|
||||
attrs (cond-> attrs
|
||||
(:gradient attrs)
|
||||
(-> (dm/get-in [:gradient :stops 0])
|
||||
(select-keys types.shadow/color-attrs)))
|
||||
|
||||
attrs' (-> (dm/get-in shape [:shadow index :color])
|
||||
(merge attrs)
|
||||
(d/without-nils))]
|
||||
(assoc-in shape [:shadow index :color] attrs'))))))))
|
||||
attrs' (-> (dm/get-in shape [:shadow index :color])
|
||||
(merge attrs)
|
||||
(d/without-nils))]
|
||||
(assoc-in shape [:shadow index :color] attrs')))]
|
||||
(ptk/reify ::change-shadow
|
||||
ptk/WatchEvent
|
||||
(watch [_ _ _]
|
||||
(rx/of (dwsh/update-shapes ids update-shadow))))))
|
||||
|
||||
(defn add-shadow
|
||||
[ids shadow]
|
||||
|
||||
(assert
|
||||
(check-shadow shadow)
|
||||
(types.shadow/check-shadow shadow)
|
||||
"expected a valid shadow struct")
|
||||
|
||||
(assert
|
||||
@@ -1146,16 +1146,16 @@
|
||||
(defn- shadow->color-attr
|
||||
"Given a stroke map enriched with :shape-id, :index, and optionally
|
||||
:has-token-applied / :token-name, returns a color attribute map.
|
||||
|
||||
|
||||
If :has-token-applied is true, adds token metadata to :attrs:
|
||||
{:has-token-applied true
|
||||
:token-name <token-name>}
|
||||
|
||||
|
||||
Args:
|
||||
- stroke: map with stroke info, including :shape-id and :index
|
||||
- file-id: current file UUID
|
||||
- libraries: map of shared color libraries
|
||||
|
||||
|
||||
Returns:
|
||||
A map like:
|
||||
{:attrs {...color data...}
|
||||
@@ -1260,12 +1260,12 @@
|
||||
will include extra attributes in its :attrs map:
|
||||
{:has-token-applied true
|
||||
:token-name <token-name>}
|
||||
|
||||
|
||||
Args:
|
||||
- shapes: vector of shape maps
|
||||
- file-id: current file UUID
|
||||
- libraries: map of shared color libraries
|
||||
|
||||
|
||||
Returns:
|
||||
A vector of color attribute maps with metadata for each shape."
|
||||
[shapes file-id libraries]
|
||||
|
||||
@@ -88,6 +88,10 @@
|
||||
{:error/code :error.style-dictionary/invalid-token-value-font-weight
|
||||
:error/fn #(tr "workspace.tokens.invalid-font-weight-token-value" %)}
|
||||
|
||||
:error.style-dictionary/invalid-token-value-font-family
|
||||
{:error/code :error.style-dictionary/invalid-token-value-font-family
|
||||
:error/fn #(tr "workspace.tokens.invalid-font-family-token-value" %)}
|
||||
|
||||
:error.style-dictionary/invalid-token-value-typography
|
||||
{:error/code :error.style-dictionary/invalid-token-value-typography
|
||||
:error/fn #(tr "workspace.tokens.invalid-token-value-typography" %)}
|
||||
|
||||
@@ -238,12 +238,12 @@
|
||||
:always
|
||||
(ctm/resize scalev resize-origin shape-transform shape-transform-inverse)
|
||||
|
||||
(and (ctl/any-layout-immediate-child? objects shape)
|
||||
(and (or (ctl/any-layout-immediate-child? objects shape) (ctl/any-layout? shape))
|
||||
(not= (:layout-item-h-sizing shape) :fix)
|
||||
^boolean change-width?)
|
||||
(ctm/change-property :layout-item-h-sizing :fix)
|
||||
|
||||
(and (ctl/any-layout-immediate-child? objects shape)
|
||||
(and (or (ctl/any-layout-immediate-child? objects shape) (ctl/any-layout? shape))
|
||||
(not= (:layout-item-v-sizing shape) :fix)
|
||||
^boolean change-height?)
|
||||
(ctm/change-property :layout-item-v-sizing :fix)
|
||||
|
||||
@@ -106,14 +106,14 @@
|
||||
(when (not= 0 count-libraries)
|
||||
(if (pos? (count references))
|
||||
[:*
|
||||
[:div
|
||||
(when (and (string? scd-msg) (not= scd-msg ""))
|
||||
[:h3 {:class (stl/css :modal-scd-msg)} scd-msg])
|
||||
[:ul {:class (stl/css :element-list)}
|
||||
(for [[file-id file-name] references]
|
||||
[:li {:class (stl/css :list-item)
|
||||
:key (dm/str file-id)}
|
||||
[:span "- " file-name]])]]
|
||||
(when (and (string? scd-msg) (not= scd-msg ""))
|
||||
[:p {:class (stl/css :modal-scd-msg)} scd-msg])
|
||||
|
||||
[:ul {:class (stl/css :element-list)}
|
||||
(for [[file-id file-name] references]
|
||||
[:li {:class (stl/css :list-item)
|
||||
:key (dm/str file-id)}
|
||||
[:span "- " file-name]])]
|
||||
(when (and (string? hint) (not= hint ""))
|
||||
[:> context-notification* {:level :info
|
||||
:appearance :ghost}
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
//
|
||||
// Copyright (c) KALEIDOS INC
|
||||
|
||||
@use "refactor/common-refactor.scss" as deprecated;
|
||||
@use "refactor/basic-rules.scss" as *;
|
||||
@use "ds/typography.scss" as t;
|
||||
|
||||
.modal-overlay {
|
||||
@extend .modal-overlay-base;
|
||||
@@ -15,14 +16,19 @@
|
||||
|
||||
.modal-container {
|
||||
@extend .modal-container-base;
|
||||
display: grid;
|
||||
gap: var(--sp-xxl);
|
||||
grid-template-rows: auto minmax(0, 1fr) auto;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
margin-bottom: deprecated.$s-24;
|
||||
.list-wrapper {
|
||||
display: grid;
|
||||
grid-template-rows: auto 1fr auto;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
@include deprecated.headlineMediumTypography;
|
||||
@include t.use-typography("headline-medium");
|
||||
color: var(--modal-title-foreground-color);
|
||||
}
|
||||
|
||||
@@ -31,13 +37,16 @@
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
@include deprecated.bodySmallTypography;
|
||||
margin-bottom: deprecated.$s-24;
|
||||
@include t.use-typography("body-small");
|
||||
display: grid;
|
||||
gap: var(--sp-s);
|
||||
}
|
||||
|
||||
.element-list {
|
||||
@include deprecated.bodyLargeTypography;
|
||||
@include t.use-typography("body-large");
|
||||
color: var(--modal-text-foreground-color);
|
||||
overflow-y: auto;
|
||||
margin-block: 0;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
@@ -55,10 +64,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
.modal-scd-msg {
|
||||
margin-block: 0;
|
||||
}
|
||||
|
||||
.modal-scd-msg,
|
||||
.modal-subtitle,
|
||||
.modal-msg {
|
||||
@include deprecated.bodyLargeTypography;
|
||||
@include t.use-typography("body-large");
|
||||
color: var(--modal-text-foreground-color);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
@@ -223,24 +223,30 @@
|
||||
circ (* 2 Math/PI 12)
|
||||
pct (- circ (* circ (/ progress total)))
|
||||
|
||||
pwidth (if error?
|
||||
280
|
||||
(/ (* progress 280) total))
|
||||
color (cond
|
||||
error? clr/new-danger
|
||||
healthy? (if is-default-theme?
|
||||
clr/new-primary
|
||||
clr/new-primary-light)
|
||||
(not healthy?) clr/new-warning)
|
||||
pwidth
|
||||
(if error?
|
||||
280
|
||||
(/ (* progress 280) total))
|
||||
|
||||
background-clr (if is-default-theme?
|
||||
clr/background-quaternary
|
||||
clr/background-quaternary-light)
|
||||
title (cond
|
||||
error? (tr "workspace.options.exporting-object-error")
|
||||
complete? (tr "workspace.options.exporting-complete")
|
||||
healthy? (tr "workspace.options.exporting-object")
|
||||
(not healthy?) (tr "workspace.options.exporting-object-slow"))
|
||||
color
|
||||
(cond
|
||||
error? clr/new-danger
|
||||
healthy? (if is-default-theme?
|
||||
clr/new-primary
|
||||
clr/new-primary-light)
|
||||
(not healthy?) clr/new-warning)
|
||||
|
||||
background-clr
|
||||
(if is-default-theme?
|
||||
clr/background-quaternary
|
||||
clr/background-quaternary-light)
|
||||
|
||||
title
|
||||
(cond
|
||||
error? (tr "workspace.options.exporting-object-error")
|
||||
complete? (tr "workspace.options.exporting-complete")
|
||||
healthy? (tr "workspace.options.exporting-object")
|
||||
(not healthy?) (tr "workspace.options.exporting-object-slow"))
|
||||
|
||||
retry-last-export
|
||||
(mf/use-fn #(st/emit! (de/retry-last-export)))
|
||||
@@ -284,7 +290,7 @@
|
||||
:on-click retry-last-export}
|
||||
(tr "workspace.options.retry")]
|
||||
|
||||
[:p {:class (stl/css :progress)}
|
||||
[:span {:class (stl/css :progress)}
|
||||
(dm/str progress " / " total)])]
|
||||
|
||||
[:button {:class (stl/css :progress-close-button)
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
:text [:visibility :geometry :text :shadow :blur :stroke :layout-element]
|
||||
:variant [:variant :geometry :fill :stroke :shadow :blur :layout :layout-element]})
|
||||
|
||||
(mf/defc attributes
|
||||
(mf/defc attributes*
|
||||
[{:keys [page-id file-id shapes frame from libraries share-id objects color-space]}]
|
||||
(let [shapes (hooks/use-equal-memo shapes)
|
||||
first-shape (first shapes)
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
embed-images? (replace-map images-data))]
|
||||
(str/format page-template style-code markup-code)))
|
||||
|
||||
(mf/defc code
|
||||
(mf/defc code*
|
||||
[{:keys [shapes frame on-expand from]}]
|
||||
(let [style-type* (mf/use-state "css")
|
||||
markup-type* (mf/use-state "html")
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
[app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i]
|
||||
[app.main.ui.ds.layout.tab-switcher :refer [tab-switcher*]]
|
||||
[app.main.ui.icons :as deprecated-icon]
|
||||
[app.main.ui.inspect.attributes :refer [attributes]]
|
||||
[app.main.ui.inspect.code :refer [code]]
|
||||
[app.main.ui.inspect.attributes :refer [attributes*]]
|
||||
[app.main.ui.inspect.code :refer [code*]]
|
||||
[app.main.ui.inspect.selection-feedback :refer [resolve-shapes]]
|
||||
[app.main.ui.inspect.styles :refer [styles-tab*]]
|
||||
[app.util.dom :as dom]
|
||||
@@ -122,8 +122,7 @@
|
||||
(fn []
|
||||
(if (seq shapes)
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "inspect-mode-click-element"}))
|
||||
(handle-change-tab (if (contains? cf/flags :inspect-styles) :styles :info)))
|
||||
(reset! color-space* "hex")))
|
||||
(handle-change-tab (if (contains? cf/flags :inspect-styles) :styles :info)))))
|
||||
|
||||
[:aside {:class (stl/css-case :settings-bar-right true
|
||||
:viewer-code (= from :viewer))}
|
||||
@@ -189,41 +188,41 @@
|
||||
:libraries libraries
|
||||
:file-id file-id}]
|
||||
:computed
|
||||
[:& attributes {:color-space color-space
|
||||
:page-id page-id
|
||||
:objects objects
|
||||
:file-id file-id
|
||||
:frame frame
|
||||
:shapes shapes
|
||||
:from from
|
||||
:libraries libraries
|
||||
:share-id share-id}]
|
||||
[:> attributes* {:color-space color-space
|
||||
:page-id page-id
|
||||
:objects objects
|
||||
:file-id file-id
|
||||
:frame frame
|
||||
:shapes shapes
|
||||
:from from
|
||||
:libraries libraries
|
||||
:share-id share-id}]
|
||||
|
||||
:code
|
||||
[:& code {:frame frame
|
||||
:shapes shapes
|
||||
:on-expand handle-expand
|
||||
:from from}])]
|
||||
[:> code* {:frame frame
|
||||
:shapes shapes
|
||||
:on-expand handle-expand
|
||||
:from from}])]
|
||||
[:> tab-switcher* {:tabs tabs
|
||||
:selected (name @section)
|
||||
:on-change handle-change-tab
|
||||
:class (stl/css :viewer-tab-switcher)}
|
||||
(case @section
|
||||
:info
|
||||
[:& attributes {:page-id page-id
|
||||
:objects objects
|
||||
:file-id file-id
|
||||
:frame frame
|
||||
:shapes shapes
|
||||
:from from
|
||||
:libraries libraries
|
||||
:share-id share-id}]
|
||||
[:> attributes* {:page-id page-id
|
||||
:objects objects
|
||||
:file-id file-id
|
||||
:frame frame
|
||||
:shapes shapes
|
||||
:from from
|
||||
:libraries libraries
|
||||
:share-id share-id}]
|
||||
|
||||
:code
|
||||
[:& code {:frame frame
|
||||
:shapes shapes
|
||||
:on-expand handle-expand
|
||||
:from from}])])]]
|
||||
[:> code* {:frame frame
|
||||
:shapes shapes
|
||||
:on-expand handle-expand
|
||||
:from from}])])]]
|
||||
[:div {:class (stl/css :empty)}
|
||||
[:div {:class (stl/css :code-info)}
|
||||
[:span {:class (stl/css :placeholder-icon)}
|
||||
|
||||
@@ -133,7 +133,7 @@
|
||||
(swap! shorthands* assoc (:panel shorthand) (:property shorthand))))]
|
||||
[:ol {:class (stl/css :styles-tab) :aria-label (tr "labels.styles")}
|
||||
;; TOKENS PANEL
|
||||
(when (or active-themes active-sets)
|
||||
(when (or (seq active-themes) (seq active-sets))
|
||||
[:li
|
||||
[:> style-box* {:panel :token}
|
||||
[:> tokens-panel* {:theme-paths active-themes :set-names active-sets}]]])
|
||||
|
||||
@@ -6,6 +6,15 @@
|
||||
|
||||
@use "ds/typography.scss" as *;
|
||||
|
||||
// TODO: this must be a custom property in the design system
|
||||
:global(.light) {
|
||||
--low-emphasis-background: #fafafa;
|
||||
}
|
||||
|
||||
:global(.default) {
|
||||
--low-emphasis-background: #121214;
|
||||
}
|
||||
|
||||
.style-box {
|
||||
--title-gap: var(--sp-xs);
|
||||
--title-padding: var(--sp-s);
|
||||
@@ -13,12 +22,9 @@
|
||||
--arrow-color: var(--color-foreground-secondary);
|
||||
--box-border-color: var(--color-background-primary);
|
||||
|
||||
// TODO: this must be a custom property in the design system
|
||||
--lowEmphasis-background: #121214;
|
||||
|
||||
padding-block: var(--sp-s);
|
||||
padding-inline: var(--sp-m);
|
||||
background-color: var(--lowEmphasis-background);
|
||||
background-color: var(--low-emphasis-background);
|
||||
|
||||
border-block-end: 2px solid var(--box-border-color);
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
[:button {:class (stl/css :cta-button :bottom-link)
|
||||
:on-click cta-link-trial} cta-text-trial])])
|
||||
|
||||
(defn schema:seats-form [min-editors]
|
||||
(defn- make-management-form-schema [min-editors]
|
||||
[:map {:title "SeatsForm"}
|
||||
[:min-members [::sm/number {:min min-editors
|
||||
:max 9999}]]
|
||||
@@ -87,7 +87,6 @@
|
||||
{::mf/register modal/components
|
||||
::mf/register-as :management-dialog}
|
||||
[{:keys [subscription-type current-subscription editors subscribe-to-trial]}]
|
||||
|
||||
(let [unlimited-modal-step*
|
||||
(mf/use-state 1)
|
||||
|
||||
@@ -112,9 +111,12 @@
|
||||
{:min-members min-editors
|
||||
:redirect-to-payment-details false})
|
||||
|
||||
schema
|
||||
(mf/with-memo [min-editors]
|
||||
(make-management-form-schema min-editors))
|
||||
|
||||
form
|
||||
(fm/use-form :schema (schema:seats-form min-editors)
|
||||
:initial initial)
|
||||
(fm/use-form :schema schema :initial initial)
|
||||
|
||||
submit-in-progress
|
||||
(mf/use-ref false)
|
||||
@@ -334,11 +336,15 @@
|
||||
[:> raw-svg* {:id (if (= "light" (:theme profile)) "logo-subscription-light" "logo-subscription")}]]
|
||||
|
||||
[:div {:class (stl/css :modal-end)}
|
||||
[:div {:class (stl/css :modal-title)} (tr "subscription.settings.sucess.dialog.title" subscription-name)]
|
||||
[:div {:class (stl/css :modal-title)}
|
||||
(tr "subscription.settings.sucess.dialog.title" subscription-name)]
|
||||
(when (not= subscription-name "professional")
|
||||
[:p {:class (stl/css :modal-text-large)} (tr "subscription.settings.success.dialog.thanks" subscription-name)])
|
||||
[:p {:class (stl/css :modal-text-large)} (tr "subscription.settings.success.dialog.description")]
|
||||
[:p {:class (stl/css :modal-text-large)} (tr "subscription.settings.sucess.dialog.footer")]
|
||||
[:p {:class (stl/css :modal-text-large)}
|
||||
(tr "subscription.settings.success.dialog.thanks" subscription-name)])
|
||||
[:p {:class (stl/css :modal-text-large)}
|
||||
(tr "subscription.settings.success.dialog.description")]
|
||||
[:p {:class (stl/css :modal-text-large)}
|
||||
(tr "subscription.settings.sucess.dialog.footer")]
|
||||
|
||||
[:div {:class (stl/css :success-action-buttons)}
|
||||
[:input
|
||||
@@ -418,7 +424,11 @@
|
||||
(mf/with-effect []
|
||||
(dom/set-html-title (tr "subscription.labels")))
|
||||
|
||||
(mf/with-effect [authenticated? show-subscription-success-modal? show-trial-subscription-modal? success-modal-is-trial? subscription]
|
||||
(mf/with-effect [authenticated?
|
||||
show-subscription-success-modal?
|
||||
show-trial-subscription-modal?
|
||||
success-modal-is-trial?
|
||||
subscription]
|
||||
(when ^boolean authenticated?
|
||||
(cond
|
||||
^boolean show-trial-subscription-modal?
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
[app.main.ui.workspace.coordinates :as coordinates]
|
||||
[app.main.ui.workspace.libraries]
|
||||
[app.main.ui.workspace.nudge]
|
||||
[app.main.ui.workspace.palette :refer [palette]]
|
||||
[app.main.ui.workspace.palette :refer [palette*]]
|
||||
[app.main.ui.workspace.plugins]
|
||||
[app.main.ui.workspace.sidebar :refer [sidebar*]]
|
||||
[app.main.ui.workspace.sidebar.history :refer [history-toolbox*]]
|
||||
@@ -84,8 +84,8 @@
|
||||
node-ref (use-resize-observer on-resize)]
|
||||
[:*
|
||||
(when (not ^boolean hide-ui?)
|
||||
[:& palette {:layout layout
|
||||
:on-change-palette-size on-resize-palette}])
|
||||
[:> palette* {:layout layout
|
||||
:on-change-size on-resize-palette}])
|
||||
|
||||
[:section
|
||||
{:key (dm/str "workspace-" page-id)
|
||||
|
||||
@@ -156,7 +156,7 @@
|
||||
(let [{:keys [modal title]} (get dwta/token-properties :color)
|
||||
window-size (dom/get-window-size)
|
||||
left-sidebar (dom/get-element "left-sidebar-aside")
|
||||
x-size (dom/get-data left-sidebar "left-sidebar-width")
|
||||
x-size (dom/get-data left-sidebar "width")
|
||||
modal-height 392
|
||||
x (- (int x-size) 30)
|
||||
y (- (/ (:height window-size) 2) (/ modal-height 2))]
|
||||
|
||||
@@ -33,12 +33,13 @@
|
||||
[okulary.core :as l]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(def viewport
|
||||
(def ^:private ref:viewport
|
||||
(l/derived :vport refs/workspace-local))
|
||||
|
||||
(defn calculate-palette-padding [rulers?]
|
||||
(defn- calculate-palette-style
|
||||
[rulers?]
|
||||
(let [left-sidebar (dom/get-element "left-sidebar-aside")
|
||||
left-sidebar-size (-> (dom/get-data left-sidebar "left-sidebar-width")
|
||||
left-sidebar-size (-> (dom/get-data left-sidebar "width")
|
||||
(d/parse-integer))
|
||||
rulers-width (if rulers? 22 0)
|
||||
min-left-sidebar-width left-sidebar-default-width
|
||||
@@ -48,36 +49,46 @@
|
||||
#js {"paddingLeft" (dm/str calculate-padding-left "px")
|
||||
"paddingRight" "322px"}))
|
||||
|
||||
(mf/defc palette
|
||||
[{:keys [layout on-change-palette-size]}]
|
||||
(let [color-palette? (:colorpalette layout)
|
||||
text-palette? (:textpalette layout)
|
||||
hide-palettes? (:hide-palettes layout)
|
||||
workspace-read-only? (mf/use-ctx ctx/workspace-read-only?)
|
||||
container (mf/use-ref nil)
|
||||
state* (mf/use-state {:show-menu false})
|
||||
state (deref state*)
|
||||
show-menu? (:show-menu state)
|
||||
selected (h/use-shared-state mdc/colorpalette-selected-broadcast-key :recent)
|
||||
selected-text* (mf/use-state :file)
|
||||
selected-text (deref selected-text*)
|
||||
on-select (mf/use-fn #(reset! selected %))
|
||||
rulers? (mf/deref refs/rulers?)
|
||||
{:keys [on-pointer-down on-lost-pointer-capture on-pointer-move parent-ref size]}
|
||||
(r/use-resize-hook :palette 72 54 80 :y true :bottom on-change-palette-size)
|
||||
(mf/defc palette*
|
||||
[{:keys [layout on-change-size]}]
|
||||
(let [color-palette? (:colorpalette layout)
|
||||
text-palette? (:textpalette layout)
|
||||
hide-palettes? (:hide-palettes layout)
|
||||
|
||||
vport (mf/deref viewport)
|
||||
vport-width (:width vport)
|
||||
read-only? (mf/use-ctx ctx/workspace-read-only?)
|
||||
container (mf/use-ref nil)
|
||||
|
||||
state* (mf/use-state #(-> {:show-menu false}))
|
||||
state (deref state*)
|
||||
show-menu? (:show-menu state)
|
||||
|
||||
selected (h/use-shared-state mdc/colorpalette-selected-broadcast-key :recent)
|
||||
|
||||
selected-text* (mf/use-state :file)
|
||||
selected-text (deref selected-text*)
|
||||
|
||||
on-select (mf/use-fn #(reset! selected %))
|
||||
|
||||
rulers? (mf/deref refs/rulers?)
|
||||
vport (mf/deref ref:viewport)
|
||||
vport-width (get vport :width)
|
||||
|
||||
{:keys [on-pointer-down
|
||||
on-lost-pointer-capture
|
||||
on-pointer-move
|
||||
parent-ref
|
||||
size]}
|
||||
(r/use-resize-hook :palette 72 54 80 :y true :bottom on-change-size)
|
||||
|
||||
on-resize
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(fn [_]
|
||||
(let [dom (mf/ref-val container)
|
||||
width (obj/get dom "clientWidth")]
|
||||
(swap! state* assoc :width width))))
|
||||
|
||||
on-close-menu
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(fn [_]
|
||||
(swap! state* assoc :show-menu false)))
|
||||
|
||||
@@ -100,7 +111,7 @@
|
||||
(reset! selected-text* (:id lib)))))
|
||||
|
||||
toggle-palettes
|
||||
(mf/use-callback
|
||||
(mf/use-fn
|
||||
(fn [_]
|
||||
(r/set-resize-type! :top)
|
||||
(dom/add-class! (dom/get-element-by-class "color-palette") "fade-out-down")
|
||||
@@ -131,7 +142,9 @@
|
||||
(vary-meta assoc ::ev/origin "workspace-left-toolbar"))))
|
||||
(dom/blur! node))))
|
||||
|
||||
any-palette? (or color-palette? text-palette?)
|
||||
any-palette?
|
||||
(or color-palette? text-palette?)
|
||||
|
||||
size-classname
|
||||
(cond
|
||||
(<= size 64) (stl/css :small-palette)
|
||||
@@ -142,16 +155,16 @@
|
||||
(let [key1 (events/listen js/window "resize" on-resize)]
|
||||
#(events/unlistenByKey key1)))
|
||||
|
||||
(mf/use-layout-effect
|
||||
#(let [dom (mf/ref-val parent-ref)
|
||||
(mf/with-layout-effect []
|
||||
(let [dom (mf/ref-val parent-ref)
|
||||
width (obj/get dom "clientWidth")]
|
||||
(swap! state* assoc :width width)))
|
||||
|
||||
[:div {:class (stl/css :palette-wrapper)
|
||||
:id "palette-wrapper"
|
||||
:style (calculate-palette-padding rulers?)
|
||||
:style (calculate-palette-style rulers?)
|
||||
:data-testid "palette"}
|
||||
(when-not workspace-read-only?
|
||||
(when-not ^boolean read-only?
|
||||
[:div {:ref parent-ref
|
||||
:class (dm/str size-classname " " (stl/css-case :palettes true
|
||||
:wide any-palette?
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
[app.main.ui.workspace.left-header :refer [left-header*]]
|
||||
[app.main.ui.workspace.right-header :refer [right-header*]]
|
||||
[app.main.ui.workspace.sidebar.assets :refer [assets-toolbox*]]
|
||||
[app.main.ui.workspace.sidebar.collapsable-button :refer [collapsed-button*]]
|
||||
[app.main.ui.workspace.sidebar.debug :refer [debug-panel*]]
|
||||
[app.main.ui.workspace.sidebar.debug-shape-info :refer [debug-shape-info*]]
|
||||
[app.main.ui.workspace.sidebar.history :refer [history-toolbox*]]
|
||||
@@ -44,19 +43,34 @@
|
||||
|
||||
;; --- Left Sidebar (Component)
|
||||
|
||||
(defn- on-collapse-left-sidebar
|
||||
[]
|
||||
(st/emit! (dw/toggle-layout-flag :collapse-left-sidebar)))
|
||||
(def ^:private toggle-collapse-left-sidebar
|
||||
(partial st/emit! (dw/toggle-layout-flag :collapse-left-sidebar)))
|
||||
|
||||
(mf/defc collapse-button*
|
||||
{::mf/private true}
|
||||
[]
|
||||
;; NOTE: This custom button may be replace by an action button when this variant is designed
|
||||
[:button {:class (stl/css :collapse-sidebar-button)
|
||||
:on-click on-collapse-left-sidebar}
|
||||
:on-click toggle-collapse-left-sidebar}
|
||||
[:> icon* {:icon-id i/arrow
|
||||
:size "s"
|
||||
:aria-label (tr "workspace.sidebar.collapse")}]])
|
||||
|
||||
(mf/defc collapsed-button*
|
||||
{::mf/memo true
|
||||
::mf/private true}
|
||||
[]
|
||||
[:div {:id "left-sidebar-aside"
|
||||
:data-width "0"
|
||||
:class (stl/css :collapsed-sidebar)}
|
||||
[:div {:class (stl/css :collapsed-title)}
|
||||
[:button {:class (stl/css :collapsed-button)
|
||||
:title (tr "workspace.sidebar.expand")
|
||||
:on-click toggle-collapse-left-sidebar}
|
||||
[:> icon* {:icon-id i/arrow
|
||||
:size "s"
|
||||
:aria-label (tr "workspace.sidebar.expand")}]]]])
|
||||
|
||||
(mf/defc layers-content*
|
||||
{::mf/private true
|
||||
::mf/memo true}
|
||||
@@ -97,6 +111,7 @@
|
||||
|
||||
[:> layers-toolbox* {:size-parent width}]]))
|
||||
|
||||
|
||||
(mf/defc left-sidebar*
|
||||
{::mf/memo true}
|
||||
[{:keys [layout file page-id tokens-lib active-tokens resolved-active-tokens]}]
|
||||
@@ -161,7 +176,7 @@
|
||||
[:aside {:ref parent-ref
|
||||
:id "left-sidebar-aside"
|
||||
:data-testid "left-sidebar"
|
||||
:data-left-sidebar-width (str width)
|
||||
:data-width (str width)
|
||||
:class aside-class
|
||||
:style {:--left-sidebar-width (dm/str width "px")}}
|
||||
|
||||
|
||||
@@ -116,6 +116,44 @@
|
||||
}
|
||||
}
|
||||
|
||||
.collapsed-sidebar {
|
||||
@include deprecated.flexCenter;
|
||||
position: absolute;
|
||||
top: deprecated.$s-48;
|
||||
left: 0;
|
||||
padding: deprecated.$s-4;
|
||||
border-radius: deprecated.$br-8;
|
||||
background: var(--color-background-primary);
|
||||
margin-inline-start: var(--sp-m);
|
||||
}
|
||||
.collapsed-title {
|
||||
@include deprecated.flexCenter;
|
||||
height: deprecated.$s-36;
|
||||
width: deprecated.$s-24;
|
||||
border-radius: deprecated.$br-8;
|
||||
background: var(--color-background-secondary);
|
||||
}
|
||||
.collapsed-button {
|
||||
@include deprecated.buttonStyle;
|
||||
height: deprecated.$s-24;
|
||||
width: deprecated.$s-16;
|
||||
padding: 0;
|
||||
border-radius: deprecated.$br-5;
|
||||
svg {
|
||||
@include deprecated.flexCenter;
|
||||
height: deprecated.$s-16;
|
||||
width: deprecated.$s-16;
|
||||
color: transparent;
|
||||
fill: none;
|
||||
stroke: var(--icon-foreground);
|
||||
}
|
||||
&:hover {
|
||||
svg {
|
||||
stroke: var(--icon-foreground-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.versions-tab {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
@@ -56,9 +56,8 @@
|
||||
(update file :data dissoc :pages-index))
|
||||
refs/file))
|
||||
|
||||
(mf/defc assets-local-library
|
||||
{::mf/wrap [mf/memo]
|
||||
::mf/wrap-props false}
|
||||
(mf/defc assets-local-library*
|
||||
{::mf/private true}
|
||||
[{:keys [filters]}]
|
||||
(let [file (mf/deref ref:local-library)]
|
||||
[:> file-library*
|
||||
@@ -68,7 +67,7 @@
|
||||
:filters filters}]))
|
||||
|
||||
(defn- toggle-values
|
||||
[v [a b]]
|
||||
[v a b]
|
||||
(if (= v a) b a))
|
||||
|
||||
(mf/defc assets-toolbox*
|
||||
@@ -97,7 +96,7 @@
|
||||
(mf/use-fn
|
||||
(mf/deps ordering)
|
||||
(fn []
|
||||
(let [new-value (toggle-values ordering [:asc :desc])]
|
||||
(let [new-value (toggle-values ordering :asc :desc)]
|
||||
(swap! filters* assoc :ordering new-value)
|
||||
(dwa/set-current-assets-ordering! new-value))))
|
||||
|
||||
@@ -105,7 +104,7 @@
|
||||
(mf/use-fn
|
||||
(mf/deps list-style)
|
||||
(fn []
|
||||
(let [new-value (toggle-values list-style [:thumbs :list])]
|
||||
(let [new-value (toggle-values list-style :thumbs :list)]
|
||||
(swap! filters* assoc :list-style new-value)
|
||||
(dwa/set-current-assets-list-style! new-value))))
|
||||
|
||||
@@ -209,5 +208,5 @@
|
||||
[:& (mf/provider cmm/assets-toggle-ordering) {:value toggle-ordering}
|
||||
[:& (mf/provider cmm/assets-toggle-list-style) {:value toggle-list-style}
|
||||
[:*
|
||||
[:& assets-local-library {:filters filters}]
|
||||
[:> assets-local-library* {:filters filters}]
|
||||
[:> assets-libraries* {:filters filters}]]]]]]))
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
cursor: pointer;
|
||||
|
||||
.title-menu {
|
||||
display: block;
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@
|
||||
}
|
||||
|
||||
.title-menu {
|
||||
display: none;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.group-title {
|
||||
|
||||
@@ -1,29 +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.workspace.sidebar.collapsable-button
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.store :as st]
|
||||
[app.main.ui.ds.foundations.assets.icon :refer [icon*] :as i]
|
||||
[app.util.i18n :refer [tr]]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(mf/defc collapsed-button*
|
||||
{::mf/memo true}
|
||||
[]
|
||||
(let [on-click (mf/use-fn #(st/emit! (dw/toggle-layout-flag :collapse-left-sidebar)))]
|
||||
[:div {:id "left-sidebar-aside"
|
||||
:data-size "0"
|
||||
:class (stl/css :collapsed-sidebar)}
|
||||
[:div {:class (stl/css :collapsed-title)}
|
||||
[:button {:class (stl/css :collapsed-button)
|
||||
:title (tr "workspace.sidebar.expand")
|
||||
:on-click on-click}
|
||||
[:> icon* {:icon-id i/arrow
|
||||
:size "s"
|
||||
:aria-label (tr "workspace.sidebar.expand")}]]]]))
|
||||
@@ -1,45 +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
|
||||
|
||||
@use "refactor/common-refactor.scss" as deprecated;
|
||||
|
||||
.collapsed-sidebar {
|
||||
@include deprecated.flexCenter;
|
||||
position: absolute;
|
||||
top: deprecated.$s-48;
|
||||
left: 0;
|
||||
padding: deprecated.$s-4;
|
||||
border-radius: deprecated.$br-8;
|
||||
background: var(--color-background-primary);
|
||||
margin-inline-start: var(--sp-m);
|
||||
}
|
||||
.collapsed-title {
|
||||
@include deprecated.flexCenter;
|
||||
height: deprecated.$s-36;
|
||||
width: deprecated.$s-24;
|
||||
border-radius: deprecated.$br-8;
|
||||
background: var(--color-background-secondary);
|
||||
}
|
||||
.collapsed-button {
|
||||
@include deprecated.buttonStyle;
|
||||
height: deprecated.$s-24;
|
||||
width: deprecated.$s-16;
|
||||
padding: 0;
|
||||
border-radius: deprecated.$br-5;
|
||||
svg {
|
||||
@include deprecated.flexCenter;
|
||||
height: deprecated.$s-16;
|
||||
width: deprecated.$s-16;
|
||||
color: transparent;
|
||||
fill: none;
|
||||
stroke: var(--icon-foreground);
|
||||
}
|
||||
&:hover {
|
||||
svg {
|
||||
stroke: var(--icon-foreground-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
// Copyright (c) KALEIDOS INC
|
||||
|
||||
@use "refactor/common-refactor.scss" as deprecated;
|
||||
@use "ds/_utils.scss" as *;
|
||||
|
||||
.layer-row {
|
||||
--layer-indentation-size: calc(#{deprecated.$s-4} * 6);
|
||||
@@ -87,7 +88,7 @@
|
||||
height: deprecated.$s-32;
|
||||
width: calc(100% - (var(--depth) * var(--layer-indentation-size)));
|
||||
cursor: pointer;
|
||||
|
||||
min-width: px2rem(140);
|
||||
&.filtered {
|
||||
width: calc(100% - deprecated.$s-12);
|
||||
}
|
||||
|
||||
@@ -211,9 +211,7 @@
|
||||
overflow-x: auto;
|
||||
overflow-y: overlay;
|
||||
scrollbar-gutter: stable;
|
||||
|
||||
.element-list {
|
||||
width: var(--left-sidebar-width);
|
||||
display: grid;
|
||||
}
|
||||
}
|
||||
.element-list {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
@@ -687,7 +687,7 @@
|
||||
(str/upper (tr "workspace.assets.local-library"))
|
||||
(dm/get-in libraries [current-library-id :name]))
|
||||
|
||||
current-lib-data (mf/with-memo [libraries]
|
||||
current-lib-data (mf/with-memo [libraries current-library-id]
|
||||
(get-in libraries [current-library-id :data]))
|
||||
|
||||
current-lib-counts (mf/with-memo [current-lib-data]
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
|
||||
(mf/defc color-token-row*
|
||||
{::mf/private true}
|
||||
[{:keys [active-tokens color-token color on-swatch-click-token detach-token open-modal-from-token]}]
|
||||
[{:keys [active-tokens applied-token-name color on-swatch-click-token detach-token open-modal-from-token]}]
|
||||
(let [;; `active-tokens` may be provided as a `delay` (lazy computation).
|
||||
;; In that case we must deref it (`@active-tokens`) to force evaluation
|
||||
;; and obtain the actual value. If it’s already realized (not a delay),
|
||||
@@ -77,21 +77,22 @@
|
||||
@active-tokens
|
||||
active-tokens)
|
||||
|
||||
color-tokens (:color active-tokens)
|
||||
active-color-tokens (:color active-tokens)
|
||||
|
||||
token (some #(when (= (:name %) color-token) %) color-tokens)
|
||||
token (some #(when (= (:name %) applied-token-name) %) active-color-tokens)
|
||||
|
||||
on-detach-token
|
||||
(mf/use-fn
|
||||
(mf/deps detach-token token color-token)
|
||||
(mf/deps detach-token token applied-token-name)
|
||||
(fn []
|
||||
(let [token (or token color-token)]
|
||||
(let [token (or token applied-token-name)]
|
||||
(detach-token token))))
|
||||
|
||||
has-errors (some? (:errors token))
|
||||
token-name (:name token)
|
||||
resolved (:resolved-value token)
|
||||
not-active (and (some? active-tokens) (nil? token))
|
||||
not-active (and (empty? active-tokens)
|
||||
(nil? token))
|
||||
id (dm/str (:id token) "-name")
|
||||
swatch-tooltip-content (cond
|
||||
not-active
|
||||
@@ -109,7 +110,7 @@
|
||||
#(mf/html
|
||||
[:div
|
||||
[:span (dm/str (tr "workspace.tokens.token-name") ": ")]
|
||||
[:span {:class (stl/css :token-name-tooltip)} color-token]]))]
|
||||
[:span {:class (stl/css :token-name-tooltip)} applied-token-name]]))]
|
||||
|
||||
[:div {:class (stl/css :color-info)}
|
||||
[:div {:class (stl/css-case :token-color-wrapper true
|
||||
@@ -128,7 +129,7 @@
|
||||
:class (stl/css :token-tooltip)}
|
||||
[:div {:class (stl/css :token-name)
|
||||
:aria-labelledby id}
|
||||
(or token-name color-token)]]
|
||||
(or token-name applied-token-name)]]
|
||||
[:div {:class (stl/css :token-actions)}
|
||||
[:> icon-button*
|
||||
{:variant "action"
|
||||
@@ -146,7 +147,11 @@
|
||||
on-change on-reorder on-detach on-open on-close on-remove origin on-detach-token
|
||||
disable-drag on-focus on-blur select-only select-on-focus on-token-change applied-token]}]
|
||||
|
||||
(let [token-color (contains? cfg/flags :token-color)
|
||||
(let [;; TODO: Remove this workaround fixing `get-attrs*` fn on sidebar/options/shapes/multiple.cljs
|
||||
applied-token (if (= :multiple applied-token)
|
||||
nil
|
||||
applied-token)
|
||||
token-color (contains? cfg/flags :token-color)
|
||||
libraries (mf/deref refs/files)
|
||||
|
||||
color-without-hash (mf/use-memo
|
||||
@@ -177,7 +182,6 @@
|
||||
(-> (deref active-tokens*)
|
||||
(select-keys (get tk/tokens-by-input origin))
|
||||
(not-empty)))))
|
||||
|
||||
on-focus'
|
||||
(mf/use-fn
|
||||
(mf/deps on-focus)
|
||||
@@ -352,7 +356,7 @@
|
||||
(cond
|
||||
(and token-color applied-token)
|
||||
[:> color-token-row* {:active-tokens tokens
|
||||
:color-token applied-token
|
||||
:applied-token-name applied-token
|
||||
:color (dissoc color :ref-id :ref-file)
|
||||
:on-swatch-click-token on-swatch-click-token
|
||||
:detach-token detach-token
|
||||
|
||||
@@ -63,7 +63,8 @@
|
||||
:data {:index index})
|
||||
[nil nil])
|
||||
|
||||
stroke-color-token (:stroke-color applied-tokens)
|
||||
stroke-color-token
|
||||
(:stroke-color applied-tokens)
|
||||
|
||||
on-color-change-refactor
|
||||
(mf/use-fn
|
||||
|
||||
@@ -20,15 +20,21 @@
|
||||
|
||||
;; Component -------------------------------------------------------------------
|
||||
|
||||
(defn calculate-position
|
||||
(defn- calculate-position
|
||||
"Calculates the style properties for the given coordinates and position"
|
||||
[{vh :height} position x y color?]
|
||||
(let [;; picker height in pixels
|
||||
;; TODO: Revisit these harcoded values
|
||||
h (if color? 610 510)
|
||||
[{vh :height} position x y token-type]
|
||||
(let [; TODO: Revisit these harcoded values
|
||||
modal-height (case token-type
|
||||
:color
|
||||
500
|
||||
:typography
|
||||
660
|
||||
:shadow
|
||||
660
|
||||
400)
|
||||
;; Checks for overflow outside the viewport height
|
||||
max-y (- vh h)
|
||||
overflow-fix (max 0 (+ y (- 50) h (- vh)))
|
||||
max-y (- vh modal-height)
|
||||
overflow-fix (max 0 (+ y (- 50) modal-height (- vh)))
|
||||
bottom-offset "1rem"
|
||||
top-offset (dm/str (- y 70) "px")
|
||||
max-height-top (str "calc(100vh - " top-offset)
|
||||
@@ -61,17 +67,19 @@
|
||||
:top (dm/str (- y 70 overflow-fix) "px")
|
||||
:maxHeight max-height-top}))))
|
||||
|
||||
(defn use-viewport-position-style [x y position color?]
|
||||
(defn use-viewport-position-style [x y position token-type]
|
||||
(let [vport (-> (l/derived :vport refs/workspace-local)
|
||||
(mf/deref))]
|
||||
(-> (calculate-position vport position x y color?)
|
||||
(-> (calculate-position vport position x y token-type)
|
||||
(clj->js))))
|
||||
|
||||
(mf/defc token-update-create-modal
|
||||
{::mf/wrap-props false}
|
||||
[{:keys [x y position token token-type action selected-token-set-id] :as _args}]
|
||||
(let [wrapper-style (use-viewport-position-style x y position (= token-type :color))
|
||||
modal-size-large* (mf/use-state (= token-type :typography))
|
||||
(let [wrapper-style (use-viewport-position-style x y position token-type)
|
||||
modal-size-large* (mf/use-state (or (= token-type :typography)
|
||||
(= token-type :color)
|
||||
(= token-type :shadow)))
|
||||
modal-size-large? (deref modal-size-large*)
|
||||
close-modal (mf/use-fn
|
||||
(fn []
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
padding: deprecated.$s-8 deprecated.$s-16;
|
||||
border-radius: deprecated.$s-8;
|
||||
border: deprecated.$s-2 solid var(--panel-border-color);
|
||||
z-index: deprecated.$z-index-3;
|
||||
z-index: deprecated.$z-index-1;
|
||||
background-color: var(--color-background-primary);
|
||||
transition:
|
||||
top 0.3s,
|
||||
|
||||
@@ -149,9 +149,9 @@
|
||||
|
||||
canvas-ref (mf/use-ref nil)
|
||||
|
||||
;; VARS
|
||||
disable-paste (mf/use-var false)
|
||||
in-viewport? (mf/use-var false)
|
||||
;; STATE REFS
|
||||
disable-paste-ref (mf/use-ref false)
|
||||
in-viewport-ref (mf/use-ref false)
|
||||
|
||||
;; STREAMS
|
||||
move-stream (mf/use-memo #(rx/subject))
|
||||
@@ -210,10 +210,10 @@
|
||||
on-pointer-down (actions/on-pointer-down @hover selected edition drawing-tool text-editing? path-editing? grid-editing?
|
||||
path-drawing? create-comment? space? panning z? read-only?)
|
||||
|
||||
on-pointer-up (actions/on-pointer-up disable-paste)
|
||||
on-pointer-up (actions/on-pointer-up disable-paste-ref)
|
||||
|
||||
on-pointer-enter (actions/on-pointer-enter in-viewport?)
|
||||
on-pointer-leave (actions/on-pointer-leave in-viewport?)
|
||||
on-pointer-enter (actions/on-pointer-enter in-viewport-ref)
|
||||
on-pointer-leave (actions/on-pointer-leave in-viewport-ref)
|
||||
on-pointer-move (actions/on-pointer-move move-stream)
|
||||
on-move-selected (actions/on-move-selected hover hover-ids selected space? z? read-only?)
|
||||
on-menu-selected (actions/on-menu-selected hover hover-ids selected read-only?)
|
||||
@@ -304,7 +304,7 @@
|
||||
#(st/emit!
|
||||
(dwv/add-new-variant (:id first-shape))))]
|
||||
|
||||
(hooks/setup-dom-events zoom disable-paste in-viewport? read-only? drawing-tool path-drawing?)
|
||||
(hooks/setup-dom-events zoom disable-paste-ref in-viewport-ref read-only? drawing-tool path-drawing?)
|
||||
(hooks/setup-viewport-size vport viewport-ref)
|
||||
(hooks/setup-cursor cursor alt? mod? space? panning drawing-tool path-drawing? path-editing? z? read-only?)
|
||||
(hooks/setup-keyboard alt? mod? space? z? shift?)
|
||||
|
||||
@@ -266,7 +266,7 @@
|
||||
(st/emit! (dw/show-shape-context-menu {:position position :hover-ids @hover-ids})))))))
|
||||
|
||||
(defn on-pointer-up
|
||||
[disable-paste]
|
||||
[disable-paste-ref]
|
||||
(mf/use-callback
|
||||
(fn [event]
|
||||
(dom/stop-propagation event)
|
||||
@@ -291,21 +291,19 @@
|
||||
(dom/prevent-default event)
|
||||
|
||||
;; We store this so in Firefox the middle button won't do a paste of the content
|
||||
(reset! disable-paste true)
|
||||
(ts/schedule #(reset! disable-paste false)))
|
||||
(mf/set-ref-val! disable-paste-ref true)
|
||||
(ts/schedule #(mf/set-ref-val! disable-paste-ref false)))
|
||||
|
||||
(st/emit! (dw/finish-panning)
|
||||
(dw/finish-zooming))))))
|
||||
|
||||
(defn on-pointer-enter [in-viewport?]
|
||||
(mf/use-callback
|
||||
(fn []
|
||||
(reset! in-viewport? true))))
|
||||
(defn on-pointer-enter
|
||||
[in-viewport-ref]
|
||||
(mf/use-fn #(mf/set-ref-val! in-viewport-ref true)))
|
||||
|
||||
(defn on-pointer-leave [in-viewport?]
|
||||
(mf/use-callback
|
||||
(fn []
|
||||
(reset! in-viewport? false))))
|
||||
(defn on-pointer-leave
|
||||
[in-viewport-ref]
|
||||
(mf/use-fn #(mf/set-ref-val! in-viewport-ref false)))
|
||||
|
||||
(defn on-key-down []
|
||||
(mf/use-callback
|
||||
@@ -524,15 +522,22 @@
|
||||
:blobs (seq files)}]
|
||||
(st/emit! (dwm/upload-media-workspace params))))))))
|
||||
|
||||
(def ^:private invalid-paste-targets
|
||||
#{"INPUT" "TEXTAREA"})
|
||||
|
||||
(defn on-paste
|
||||
[disable-paste in-viewport? read-only?]
|
||||
[disable-paste-ref in-viewport-ref read-only?]
|
||||
(mf/use-fn
|
||||
(mf/deps read-only?)
|
||||
(fn [event]
|
||||
;; We disable the paste just after mouse-up of a middle button so
|
||||
;; when panning won't paste the content into the workspace
|
||||
(let [tag-name (-> event dom/get-target dom/get-tag-name)]
|
||||
(when (and (not (#{"INPUT" "TEXTAREA"} tag-name))
|
||||
(not @disable-paste)
|
||||
;; We disable the paste when: 1. just after mouse-up of a middle
|
||||
;; button (so when panning won't paste the content into the
|
||||
;; workspace); 2. when we paste content in an input on the
|
||||
;; sidebar
|
||||
(let [tag-name (-> event dom/get-target dom/get-tag-name)
|
||||
disable-paste? (mf/ref-val disable-paste-ref)
|
||||
in-viewport? (mf/ref-val in-viewport-ref)]
|
||||
(when (and (not (contains? invalid-paste-targets tag-name))
|
||||
(not disable-paste?)
|
||||
(not read-only?))
|
||||
(st/emit! (dw/paste-from-event event @in-viewport?)))))))
|
||||
(st/emit! (dw/paste-from-event event in-viewport?)))))))
|
||||
|
||||
@@ -42,11 +42,12 @@
|
||||
[rumext.v2 :as mf])
|
||||
(:import goog.events.EventType))
|
||||
|
||||
(defn setup-dom-events [zoom disable-paste in-viewport? workspace-read-only? drawing-tool drawing-path?]
|
||||
(defn setup-dom-events
|
||||
[zoom disable-paste-ref in-viewport-ref workspace-read-only? drawing-tool drawing-path?]
|
||||
(let [on-key-down (actions/on-key-down)
|
||||
on-key-up (actions/on-key-up)
|
||||
on-mouse-wheel (actions/on-mouse-wheel zoom)
|
||||
on-paste (actions/on-paste disable-paste in-viewport? workspace-read-only?)
|
||||
on-paste (actions/on-paste disable-paste-ref in-viewport-ref workspace-read-only?)
|
||||
on-pointer-down (mf/use-fn
|
||||
(mf/deps drawing-tool drawing-path?)
|
||||
(fn [e]
|
||||
@@ -56,27 +57,27 @@
|
||||
(st/emit! (dwe/clear-edition-mode))))))
|
||||
on-blur (mf/use-fn #(st/emit! (mse/->BlurEvent)))]
|
||||
|
||||
(mf/use-effect
|
||||
(mf/deps drawing-tool drawing-path?)
|
||||
(fn []
|
||||
(let [keys [(events/listen js/window EventType.POINTERDOWN on-pointer-down)]]
|
||||
(fn []
|
||||
(doseq [key keys]
|
||||
(events/unlistenByKey key))))))
|
||||
(mf/with-effect [drawing-tool drawing-path?]
|
||||
(let [key (events/listen js/window EventType.POINTERDOWN on-pointer-down)]
|
||||
|
||||
(mf/use-layout-effect
|
||||
(mf/deps on-key-down on-key-up on-mouse-wheel on-paste workspace-read-only?)
|
||||
(fn []
|
||||
(let [keys [(events/listen js/document EventType.KEYDOWN on-key-down)
|
||||
(events/listen js/document EventType.KEYUP on-key-up)
|
||||
;; bind with passive=false to allow the event to be cancelled
|
||||
;; https://stackoverflow.com/a/57582286/3219895
|
||||
(events/listen js/window EventType.WHEEL on-mouse-wheel #js {:passive false})
|
||||
(events/listen js/window EventType.PASTE on-paste)
|
||||
(events/listen js/window EventType.BLUR on-blur)]]
|
||||
(fn []
|
||||
(doseq [key keys]
|
||||
(events/unlistenByKey key))))))))
|
||||
;; We need to disable workspace paste when we on comments
|
||||
(if (= drawing-tool :comments)
|
||||
(mf/set-ref-val! disable-paste-ref true)
|
||||
(mf/set-ref-val! disable-paste-ref false))
|
||||
|
||||
#(events/unlistenByKey key)))
|
||||
|
||||
(mf/with-layout-effect [on-key-down on-key-up on-mouse-wheel on-paste workspace-read-only?]
|
||||
(let [keys [(events/listen js/document EventType.KEYDOWN on-key-down)
|
||||
(events/listen js/document EventType.KEYUP on-key-up)
|
||||
;; bind with passive=false to allow the event to be cancelled
|
||||
;; https://stackoverflow.com/a/57582286/3219895
|
||||
(events/listen js/window EventType.WHEEL on-mouse-wheel #js {:passive false})
|
||||
(events/listen js/window EventType.PASTE on-paste)
|
||||
(events/listen js/window EventType.BLUR on-blur)]]
|
||||
(fn []
|
||||
(doseq [key keys]
|
||||
(events/unlistenByKey key)))))))
|
||||
|
||||
(defn setup-viewport-size [vport viewport-ref]
|
||||
(mf/with-effect [vport]
|
||||
|
||||
@@ -142,9 +142,9 @@
|
||||
canvas-ref (mf/use-ref nil)
|
||||
text-editor-ref (mf/use-ref nil)
|
||||
|
||||
;; VARS
|
||||
disable-paste (mf/use-var false)
|
||||
in-viewport? (mf/use-var false)
|
||||
;; STATE REFS
|
||||
disable-paste-ref (mf/use-ref false)
|
||||
in-viewport-ref (mf/use-ref false)
|
||||
|
||||
;; STREAMS
|
||||
move-stream (mf/use-memo #(rx/subject))
|
||||
@@ -204,10 +204,10 @@
|
||||
on-pointer-down (actions/on-pointer-down @hover selected edition drawing-tool text-editing? path-editing? grid-editing?
|
||||
path-drawing? create-comment? space? panning z? read-only?)
|
||||
|
||||
on-pointer-up (actions/on-pointer-up disable-paste)
|
||||
on-pointer-up (actions/on-pointer-up disable-paste-ref)
|
||||
|
||||
on-pointer-enter (actions/on-pointer-enter in-viewport?)
|
||||
on-pointer-leave (actions/on-pointer-leave in-viewport?)
|
||||
on-pointer-enter (actions/on-pointer-enter in-viewport-ref)
|
||||
on-pointer-leave (actions/on-pointer-leave in-viewport-ref)
|
||||
on-pointer-move (actions/on-pointer-move move-stream)
|
||||
on-move-selected (actions/on-move-selected hover hover-ids selected space? z? read-only?)
|
||||
on-menu-selected (actions/on-menu-selected hover hover-ids selected read-only?)
|
||||
@@ -349,7 +349,7 @@
|
||||
(wasm.api/show-grid @hover-top-frame-id)
|
||||
(wasm.api/clear-grid))))
|
||||
|
||||
(hooks/setup-dom-events zoom disable-paste in-viewport? read-only? drawing-tool path-drawing?)
|
||||
(hooks/setup-dom-events zoom disable-paste-ref in-viewport-ref read-only? drawing-tool path-drawing?)
|
||||
(hooks/setup-viewport-size vport viewport-ref)
|
||||
(hooks/setup-cursor cursor alt? mod? space? panning drawing-tool path-drawing? path-editing? z? read-only?)
|
||||
(hooks/setup-keyboard alt? mod? space? z? shift?)
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
[app.plugins.ruler-guides :as rg]
|
||||
[app.plugins.text :as text]
|
||||
[app.plugins.utils :as u]
|
||||
[app.util.http :as http]
|
||||
[app.util.object :as obj]
|
||||
[beicon.v2.core :as rx]
|
||||
[cuerdas.core :as str]))
|
||||
@@ -1196,7 +1197,12 @@
|
||||
(js/Promise.
|
||||
(fn [resolve reject]
|
||||
(->> (rp/cmd! :export payload)
|
||||
(rx/mapcat #(rp/cmd! :export {:cmd :get-resource :wait true :id (:id %) :blob? true}))
|
||||
(rx/mapcat (fn [{:keys [uri]}]
|
||||
(->> (http/send! {:method :get
|
||||
:uri uri
|
||||
:response-type :blob
|
||||
:omit-default-headers true})
|
||||
(rx/map :body))))
|
||||
(rx/mapcat #(.arrayBuffer %))
|
||||
(rx/map #(js/Uint8Array. %))
|
||||
(rx/subs! resolve reject))))))))
|
||||
|
||||
@@ -1316,51 +1316,16 @@
|
||||
(mem/free)
|
||||
content)))
|
||||
|
||||
|
||||
(defn init-wasm-module
|
||||
[module]
|
||||
(let [default-fn (unchecked-get module "default")
|
||||
serializers
|
||||
#js
|
||||
{:blur-type (unchecked-get module "RawBlurType")
|
||||
:blend-mode (unchecked-get module "RawBlendMode")
|
||||
:bool-type (unchecked-get module "RawBoolType")
|
||||
:font-style (unchecked-get module "RawFontStyle")
|
||||
:flex-direction (unchecked-get module "RawFlexDirection")
|
||||
:grid-direction (unchecked-get module "RawGridDirection")
|
||||
:grow-type (unchecked-get module "RawGrowType")
|
||||
:align-items (unchecked-get module "RawAlignItems")
|
||||
:align-self (unchecked-get module "RawAlignSelf")
|
||||
:align-content (unchecked-get module "RawAlignContent")
|
||||
:justify-items (unchecked-get module "RawJustifyItems")
|
||||
:justify-content (unchecked-get module "RawJustifyContent")
|
||||
:justify-self (unchecked-get module "RawJustifySelf")
|
||||
:wrap-type (unchecked-get module "RawWrapType")
|
||||
:grid-track-type (unchecked-get module "RawGridTrackType")
|
||||
:shadow-style (unchecked-get module "RawShadowStyle")
|
||||
:stroke-style (unchecked-get module "RawStrokeStyle")
|
||||
:stroke-cap (unchecked-get module "RawStrokeCap")
|
||||
:shape-type (unchecked-get module "RawShapeType")
|
||||
:constraint-h (unchecked-get module "RawConstraintH")
|
||||
:constraint-v (unchecked-get module "RawConstraintV")
|
||||
:sizing (unchecked-get module "RawSizing")
|
||||
:vertical-align (unchecked-get module "RawVerticalAlign")
|
||||
:fill-data (unchecked-get module "RawFillData")
|
||||
:text-align (unchecked-get module "RawTextAlign")
|
||||
:text-direction (unchecked-get module "RawTextDirection")
|
||||
:text-decoration (unchecked-get module "RawTextDecoration")
|
||||
:text-transform (unchecked-get module "RawTextTransform")
|
||||
:segment-data (unchecked-get module "RawSegmentData")
|
||||
:stroke-linecap (unchecked-get module "RawStrokeLineCap")
|
||||
:stroke-linejoin (unchecked-get module "RawStrokeLineJoin")
|
||||
:fill-rule (unchecked-get module "RawFillRule")}]
|
||||
(set! wasm/serializers serializers)
|
||||
(default-fn)))
|
||||
href (cf/resolve-href "js/render-wasm.wasm")]
|
||||
(default-fn #js {:locateFile (constantly href)})))
|
||||
|
||||
(defonce module
|
||||
(delay
|
||||
(if (exists? js/dynamicImport)
|
||||
(let [uri (cf/resolve-static-asset "js/render_wasm.js")]
|
||||
(let [uri (cf/resolve-href "js/render-wasm.js")]
|
||||
(->> (js/dynamicImport (str uri))
|
||||
(p/mcat init-wasm-module)
|
||||
(p/fmap
|
||||
|
||||
242
frontend/src/app/render_wasm/api/shared.js
Normal file
242
frontend/src/app/render_wasm/api/shared.js
Normal file
@@ -0,0 +1,242 @@
|
||||
export const GrowType = {
|
||||
"fixed": 0,
|
||||
"auto-width": 1,
|
||||
"auto-height": 2,
|
||||
};
|
||||
|
||||
export const RawBlendMode = {
|
||||
"normal": 3,
|
||||
"screen": 14,
|
||||
"overlay": 15,
|
||||
"darken": 16,
|
||||
"lighten": 17,
|
||||
"color-dodge": 18,
|
||||
"color-burn": 19,
|
||||
"hard-light": 20,
|
||||
"soft-light": 21,
|
||||
"difference": 22,
|
||||
"exclusion": 23,
|
||||
"multiply": 24,
|
||||
"hue": 25,
|
||||
"saturation": 26,
|
||||
"color": 27,
|
||||
"luminosity": 28,
|
||||
};
|
||||
|
||||
export const RawBlurType = {
|
||||
"layer-blur": 0,
|
||||
};
|
||||
|
||||
export const RawFillData = {
|
||||
"solid": 0,
|
||||
"linear": 1,
|
||||
"radial": 2,
|
||||
"image": 3,
|
||||
};
|
||||
|
||||
export const RawFontStyle = {
|
||||
"normal": 0,
|
||||
"italic": 1,
|
||||
};
|
||||
|
||||
export const RawAlignItems = {
|
||||
"start": 0,
|
||||
"end": 1,
|
||||
"center": 2,
|
||||
"stretch": 3,
|
||||
};
|
||||
|
||||
export const RawAlignContent = {
|
||||
"start": 0,
|
||||
"end": 1,
|
||||
"center": 2,
|
||||
"space-between": 3,
|
||||
"space-around": 4,
|
||||
"space-evenly": 5,
|
||||
"stretch": 6,
|
||||
};
|
||||
|
||||
export const RawJustifyItems = {
|
||||
"start": 0,
|
||||
"end": 1,
|
||||
"center": 2,
|
||||
"stretch": 3,
|
||||
};
|
||||
|
||||
export const RawJustifyContent = {
|
||||
"start": 0,
|
||||
"end": 1,
|
||||
"center": 2,
|
||||
"space-between": 3,
|
||||
"space-around": 4,
|
||||
"space-evenly": 5,
|
||||
"stretch": 6,
|
||||
};
|
||||
|
||||
export const RawJustifySelf = {
|
||||
"none": 0,
|
||||
"auto": 1,
|
||||
"start": 2,
|
||||
"end": 3,
|
||||
"center": 4,
|
||||
"stretch": 5,
|
||||
};
|
||||
|
||||
export const RawAlignSelf = {
|
||||
"none": 0,
|
||||
"auto": 1,
|
||||
"start": 2,
|
||||
"end": 3,
|
||||
"center": 4,
|
||||
"stretch": 5,
|
||||
};
|
||||
|
||||
export const RawVerticalAlign = {
|
||||
"top": 0,
|
||||
"center": 1,
|
||||
"bottom": 2,
|
||||
};
|
||||
|
||||
export const RawConstraintH = {
|
||||
"left": 0,
|
||||
"right": 1,
|
||||
"leftright": 2,
|
||||
"center": 3,
|
||||
"scale": 4,
|
||||
};
|
||||
|
||||
export const RawConstraintV = {
|
||||
"top": 0,
|
||||
"bottom": 1,
|
||||
"topbottom": 2,
|
||||
"center": 3,
|
||||
"scale": 4,
|
||||
};
|
||||
|
||||
export const RawFlexDirection = {
|
||||
"row": 0,
|
||||
"row-reverse": 1,
|
||||
"column": 2,
|
||||
"column-reverse": 3,
|
||||
};
|
||||
|
||||
export const RawWrapType = {
|
||||
"wrap": 0,
|
||||
"nowrap": 1,
|
||||
};
|
||||
|
||||
export const RawGridDirection = {
|
||||
"row": 0,
|
||||
"column": 1,
|
||||
};
|
||||
|
||||
export const RawGridTrackType = {
|
||||
"percent": 0,
|
||||
"flex": 1,
|
||||
"auto": 2,
|
||||
"fixed": 3,
|
||||
};
|
||||
|
||||
export const RawSizing = {
|
||||
"fill": 0,
|
||||
"fix": 1,
|
||||
"auto": 2,
|
||||
};
|
||||
|
||||
export const RawBoolType = {
|
||||
"union": 0,
|
||||
"difference": 1,
|
||||
"intersection": 2,
|
||||
"exclusion": 3,
|
||||
};
|
||||
|
||||
export const RawSegmentData = {
|
||||
"move-to": 1,
|
||||
"line-to": 2,
|
||||
"curve-to": 3,
|
||||
"close": 4,
|
||||
};
|
||||
|
||||
export const RawShadowStyle = {
|
||||
"drop-shadow": 0,
|
||||
"inner-shadow": 1,
|
||||
};
|
||||
|
||||
export const RawShapeType = {
|
||||
"frame": 0,
|
||||
"group": 1,
|
||||
"bool": 2,
|
||||
"rect": 3,
|
||||
"path": 4,
|
||||
"text": 5,
|
||||
"circle": 6,
|
||||
"svg-raw": 7,
|
||||
};
|
||||
|
||||
export const RawStrokeStyle = {
|
||||
"solid": 0,
|
||||
"dotted": 1,
|
||||
"dashed": 2,
|
||||
"mixed": 3,
|
||||
};
|
||||
|
||||
export const RawStrokeCap = {
|
||||
"none": 0,
|
||||
"line-arrow": 1,
|
||||
"triangle-arrow": 2,
|
||||
"square-marker": 3,
|
||||
"circle-marker": 4,
|
||||
"diamond-marker": 5,
|
||||
"round": 6,
|
||||
"square": 7,
|
||||
};
|
||||
|
||||
export const RawFillRule = {
|
||||
"nonzero": 0,
|
||||
"evenodd": 1,
|
||||
};
|
||||
|
||||
export const RawStrokeLineCap = {
|
||||
"butt": 0,
|
||||
"round": 1,
|
||||
"square": 2,
|
||||
};
|
||||
|
||||
export const RawStrokeLineJoin = {
|
||||
"miter": 0,
|
||||
"round": 1,
|
||||
"bevel": 2,
|
||||
};
|
||||
|
||||
export const RawTextAlign = {
|
||||
"left": 0,
|
||||
"center": 1,
|
||||
"right": 2,
|
||||
"justify": 3,
|
||||
};
|
||||
|
||||
export const RawTextDirection = {
|
||||
"ltr": 0,
|
||||
"rtl": 1,
|
||||
};
|
||||
|
||||
export const RawTextDecoration = {
|
||||
"none": 0,
|
||||
"underline": 1,
|
||||
"line-through": 2,
|
||||
"overline": 3,
|
||||
};
|
||||
|
||||
export const RawTextTransform = {
|
||||
"none": 0,
|
||||
"uppercase": 1,
|
||||
"lowercase": 2,
|
||||
"capitalize": 3,
|
||||
};
|
||||
|
||||
export const RawGrowType = {
|
||||
"fixed": 0,
|
||||
"auto-width": 1,
|
||||
"auto-height": 2,
|
||||
};
|
||||
|
||||
@@ -4,9 +4,43 @@
|
||||
;;
|
||||
;; Copyright (c) KALEIDOS INC
|
||||
|
||||
(ns app.render-wasm.wasm)
|
||||
(ns app.render-wasm.wasm
|
||||
(:require ["./api/shared.js" :as shared]))
|
||||
|
||||
(defonce internal-frame-id nil)
|
||||
(defonce internal-module #js {})
|
||||
(defonce serializers #js {})
|
||||
(defonce serializers
|
||||
#js {:blur-type shared/RawBlurType
|
||||
:blend-mode shared/RawBlendMode
|
||||
:bool-type shared/RawBoolType
|
||||
:font-style shared/RawFontStyle
|
||||
:flex-direction shared/RawFlexDirection
|
||||
:grid-direction shared/RawGridDirection
|
||||
:grow-type shared/RawGrowType
|
||||
:align-items shared/RawAlignItems
|
||||
:align-self shared/RawAlignSelf
|
||||
:align-content shared/RawAlignContent
|
||||
:justify-items shared/RawJustifyItems
|
||||
:justify-content shared/RawJustifyContent
|
||||
:justify-self shared/RawJustifySelf
|
||||
:wrap-type shared/RawWrapType
|
||||
:grid-track-type shared/RawGridTrackType
|
||||
:shadow-style shared/RawShadowStyle
|
||||
:stroke-style shared/RawStrokeStyle
|
||||
:stroke-cap shared/RawStrokeCap
|
||||
:shape-type shared/RawShapeType
|
||||
:constraint-h shared/RawConstraintH
|
||||
:constraint-v shared/RawConstraintV
|
||||
:sizing shared/RawSizing
|
||||
:vertical-align shared/RawVerticalAlign
|
||||
:fill-data shared/RawFillData
|
||||
:text-align shared/RawTextAlign
|
||||
:text-direction shared/RawTextDirection
|
||||
:text-decoration shared/RawTextDecoration
|
||||
:text-transform shared/RawTextTransform
|
||||
:segment-data shared/RawSegmentData
|
||||
:stroke-linecap shared/RawStrokeLineCap
|
||||
:stroke-linejoin shared/RawStrokeLineJoin
|
||||
:fill-rule shared/RawFillRule})
|
||||
|
||||
(defonce context-initialized? false)
|
||||
|
||||
@@ -57,10 +57,11 @@
|
||||
(= (dom/get-tag-name target) "INPUT")]
|
||||
|
||||
;; ignore when pasting into an editable control
|
||||
(when-not (or content-editable? is-input?)
|
||||
(if-not (or content-editable? is-input?)
|
||||
(-> event
|
||||
(dom/event->browser-event)
|
||||
(from-clipboard-event options))))))
|
||||
(from-clipboard-event options))
|
||||
(rx/empty)))))
|
||||
|
||||
(defn from-drop-event
|
||||
"Get clipboard stream from drop event"
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
{:label "Føroyskt mál (community)" :value "fo"}
|
||||
{:label "Korean (community)" :value "ko"}
|
||||
{:label "עִבְרִית (community)" :value "he"}
|
||||
{:label "आधुनिक मानक हिन्दी (community)" :value "hi"}
|
||||
{:label "عربي/عربى (community)" :value "ar"}
|
||||
{:label "فارسی (community)" :value "fa"}
|
||||
{:label "日本語 (Community)" :value "ja_jp"}
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
(defn init
|
||||
"Return a initialized webworker instance."
|
||||
[path on-error]
|
||||
(let [instance (js/Worker. path #js {:type "module"})
|
||||
(let [instance (js/Worker. path)
|
||||
bus (rx/subject)
|
||||
worker (Worker. instance (rx/to-observable bus))
|
||||
|
||||
|
||||
@@ -24,11 +24,12 @@
|
||||
[beicon.v2.core :as rx]
|
||||
[okulary.core :as l]
|
||||
[promesa.core :as p]
|
||||
[rumext.v2 :as mf]
|
||||
[shadow.esm :refer (dynamic-import)]))
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(log/set-level! :trace)
|
||||
|
||||
(def ^:private ^:const thumbnail-aspect-ratio (/ 2 3))
|
||||
|
||||
(defn- handle-response
|
||||
[{:keys [body status] :as response}]
|
||||
(cond
|
||||
@@ -64,6 +65,10 @@
|
||||
(rx/map http/conditional-decode-transit)
|
||||
(rx/mapcat handle-response))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; SVG RENDERING (LEGACY RENDER)
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defn- render-thumbnail
|
||||
[{:keys [page file-id revn] :as params}]
|
||||
(try
|
||||
@@ -98,15 +103,13 @@
|
||||
(->> (request-data-for-thumbnail file-id revn true)
|
||||
(rx/map render-thumbnail)))
|
||||
|
||||
(def init-wasm
|
||||
(delay
|
||||
(let [uri (cf/resolve-static-asset "js/render_wasm.js")]
|
||||
(-> (dynamic-import (str uri))
|
||||
(p/then #(wasm.api/init-wasm-module %))
|
||||
(p/then #(set! wasm/internal-module %))))))
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; WASM RENDERING
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(mf/defc svg-wrapper
|
||||
[{:keys [data-uri background width height]}]
|
||||
(mf/defc svg-wrapper*
|
||||
{::mf/private true}
|
||||
[{:keys [uri background width height]}]
|
||||
[:svg {:version "1.1"
|
||||
:xmlns "http://www.w3.org/2000/svg"
|
||||
:xmlnsXlink "http://www.w3.org/1999/xlink"
|
||||
@@ -116,85 +119,97 @@
|
||||
:background background}
|
||||
:fill "none"
|
||||
:viewBox (dm/str "0 0 " width " " height)}
|
||||
[:image {:xlinkHref data-uri
|
||||
[:image {:xlinkHref uri
|
||||
:width width
|
||||
:height height}]])
|
||||
|
||||
(defn blob->uri
|
||||
(defn- blob->uri
|
||||
[blob]
|
||||
(.readAsDataURL (js/FileReaderSync.) blob))
|
||||
|
||||
(def thumbnail-aspect-ratio (/ 2 3))
|
||||
(defn- render-canvas-blob
|
||||
[canvas width height background]
|
||||
(->> (.convertToBlob ^js canvas)
|
||||
(p/fmap (fn [blob]
|
||||
(rds/renderToStaticMarkup
|
||||
(mf/element svg-wrapper*
|
||||
#js {:uri (blob->uri blob)
|
||||
:width width
|
||||
:height height
|
||||
:background background}))))))
|
||||
|
||||
(defn render-canvas-blob
|
||||
[canvas width height background-color]
|
||||
(-> (.convertToBlob canvas)
|
||||
(p/then
|
||||
(fn [blob]
|
||||
(rds/renderToStaticMarkup
|
||||
(mf/element
|
||||
svg-wrapper
|
||||
#js {:data-uri (blob->uri blob)
|
||||
:width width
|
||||
:height height
|
||||
:background background-color}))))))
|
||||
(defonce ^:private wasm-module
|
||||
(delay
|
||||
(let [module (unchecked-get js/globalThis "WasmModule")
|
||||
init-fn (unchecked-get module "default")
|
||||
href (cf/resolve-href "js/render-wasm.wasm")]
|
||||
(->> (init-fn #js {:locateFile (constantly href)})
|
||||
(p/fnly (fn [module cause]
|
||||
(if cause
|
||||
(js/console.error cause)
|
||||
(set! wasm/internal-module module))))))))
|
||||
|
||||
(defn process-wasm-thumbnail
|
||||
(defn- render-thumbnail-with-wasm
|
||||
[{:keys [id file-id revn width] :as message}]
|
||||
(->> (rx/from @init-wasm)
|
||||
(->> (rx/from @wasm-module)
|
||||
(rx/mapcat #(request-data-for-thumbnail file-id revn false))
|
||||
(rx/mapcat
|
||||
(fn [{:keys [page] :as file}]
|
||||
(rx/create
|
||||
(fn [subs]
|
||||
(let [background-color (or (:background page) cc/canvas)
|
||||
height (* width thumbnail-aspect-ratio)
|
||||
canvas (js/OffscreenCanvas. width height)
|
||||
init? (wasm.api/init-canvas-context canvas)]
|
||||
(let [bgcolor (or (:background page) cc/canvas)
|
||||
height (* width thumbnail-aspect-ratio)
|
||||
canvas (js/OffscreenCanvas. width height)
|
||||
init? (wasm.api/init-canvas-context canvas)]
|
||||
(if init?
|
||||
(let [objects (:objects page)
|
||||
frame (some->> page :thumbnail-frame-id (get objects))
|
||||
vbox (if frame
|
||||
(-> (gsb/get-object-bounds objects frame)
|
||||
(grc/fix-aspect-ratio thumbnail-aspect-ratio))
|
||||
(render/calculate-dimensions objects thumbnail-aspect-ratio))
|
||||
zoom (/ width (:width vbox))]
|
||||
frame (some->> page :thumbnail-frame-id (get objects))
|
||||
vbox (if frame
|
||||
(-> (gsb/get-object-bounds objects frame)
|
||||
(grc/fix-aspect-ratio thumbnail-aspect-ratio))
|
||||
(render/calculate-dimensions objects thumbnail-aspect-ratio))
|
||||
zoom (/ width (:width vbox))]
|
||||
|
||||
(wasm.api/initialize-viewport
|
||||
objects zoom vbox background-color
|
||||
objects zoom vbox bgcolor
|
||||
(fn []
|
||||
(if frame
|
||||
(wasm.api/render-sync-shape (:id frame))
|
||||
(wasm.api/render-sync))
|
||||
|
||||
(-> (render-canvas-blob canvas width height background-color)
|
||||
(p/then #(rx/push! subs {:id id :data % :file-id file-id :revn revn}))
|
||||
(p/catch #(rx/error! subs %))
|
||||
(p/finally #(rx/end! subs))))))
|
||||
|
||||
(->> (render-canvas-blob canvas width height bgcolor)
|
||||
(p/fnly (fn [data cause]
|
||||
(if cause
|
||||
(rx/error! subs cause)
|
||||
(rx/push! subs
|
||||
{:id id
|
||||
:data data
|
||||
:file-id file-id
|
||||
:revn revn}))
|
||||
(rx/end! subs)))))))
|
||||
(rx/end! subs))
|
||||
|
||||
nil)))))))
|
||||
|
||||
(defonce thumbs-subject (rx/subject))
|
||||
(defonce ^:private
|
||||
thumbnails-queue
|
||||
(rx/subject))
|
||||
|
||||
(defonce thumbs-stream
|
||||
(->> thumbs-subject
|
||||
(rx/mapcat process-wasm-thumbnail)
|
||||
(defonce ^:private
|
||||
thumbnails-stream
|
||||
(->> thumbnails-queue
|
||||
(rx/mapcat render-thumbnail-with-wasm)
|
||||
(rx/share)))
|
||||
|
||||
(defmethod impl/handler :thumbnails/generate-for-file-wasm
|
||||
[message _]
|
||||
(rx/create
|
||||
(fn [subs]
|
||||
(let [id (uuid/next)
|
||||
sid
|
||||
(->> thumbs-stream
|
||||
(rx/filter #(= id (:id %)))
|
||||
(rx/subs!
|
||||
#(do
|
||||
(rx/push! subs %)
|
||||
(rx/end! subs))))]
|
||||
(rx/push! thumbs-subject (assoc message :id id))
|
||||
|
||||
(let [id (uuid/next)
|
||||
sid (->> thumbnails-stream
|
||||
(rx/filter #(= id (:id %)))
|
||||
(rx/subs!
|
||||
(fn [result]
|
||||
(rx/push! subs result)
|
||||
(rx/end! subs))))]
|
||||
(rx/push! thumbnails-queue (assoc message :id id))
|
||||
#(rx/dispose! sid)))))
|
||||
|
||||
@@ -392,7 +392,7 @@ msgstr ""
|
||||
#: src/app/main/ui/exports/files.cljs:164
|
||||
msgid "dashboard.export.options.all.message"
|
||||
msgstr ""
|
||||
"els fitxers amb biblioteques compartides s’inclouran a l’exportació, "
|
||||
"Els fitxers amb biblioteques compartides s’inclouran a l’exportació, "
|
||||
"mantenint la vinculació."
|
||||
|
||||
#: src/app/main/ui/exports/files.cljs:165
|
||||
|
||||
@@ -542,7 +542,7 @@ msgstr ""
|
||||
#: src/app/main/ui/exports/files.cljs:164
|
||||
msgid "dashboard.export.options.all.message"
|
||||
msgstr ""
|
||||
"soubory se sdílenými knihovnami budou zahrnuty do exportu, čímž se zachová "
|
||||
"Soubory se sdílenými knihovnami budou zahrnuty do exportu, čímž se zachová "
|
||||
"jejich propojení."
|
||||
|
||||
#: src/app/main/ui/exports/files.cljs:165
|
||||
|
||||
@@ -576,7 +576,7 @@ msgstr ""
|
||||
#: src/app/main/ui/exports/files.cljs:164
|
||||
msgid "dashboard.export.options.all.message"
|
||||
msgstr ""
|
||||
"files with shared libraries will be included in the export, maintaining "
|
||||
"Files with shared libraries will be included in the export, maintaining "
|
||||
"their linkage."
|
||||
|
||||
#: src/app/main/ui/exports/files.cljs:165
|
||||
@@ -7745,6 +7745,10 @@ msgstr ""
|
||||
"Invalid token value: only none, Uppercase, Lowercase or Capitalize are "
|
||||
"accepted"
|
||||
|
||||
#: src/app/main/data/workspace/tokens/errors.cljs:93
|
||||
msgid "workspace.tokens.invalid-font-family-token-value"
|
||||
msgstr "Invalid token value: you can only reference a font-family token"
|
||||
|
||||
#: src/app/main/data/workspace/tokens/errors.cljs:85
|
||||
msgid "workspace.tokens.invalid-text-decoration-token-value"
|
||||
msgstr "Invalid token value: only none, underline and strike-through are accepted"
|
||||
|
||||
@@ -585,7 +585,7 @@ msgstr ""
|
||||
#: src/app/main/ui/exports/files.cljs:164
|
||||
msgid "dashboard.export.options.all.message"
|
||||
msgstr ""
|
||||
"ficheros con librerias compartidas se inclurán en el paquete de exportación "
|
||||
"Ficheros con librerias compartidas se inclurán en el paquete de exportación "
|
||||
"y mantendrán los enlaces."
|
||||
|
||||
#: src/app/main/ui/exports/files.cljs:165
|
||||
@@ -7670,6 +7670,14 @@ msgstr ""
|
||||
msgid "workspace.tokens.invalid-shadow-type-token-value"
|
||||
msgstr "Tipo de sombra no válida: solo se aceptan 'innerShadow' o 'dropShadow'"
|
||||
|
||||
#: src/app/main/data/workspace/tokens/errors.cljs:93
|
||||
msgid "workspace.tokens.invalid-font-family-token-value"
|
||||
msgstr "Valor de token no válido: solo puedes referenciar tokens tipo font-family"
|
||||
|
||||
#: src/app/main/data/workspace/tokens/errors.cljs:85
|
||||
msgid "workspace.tokens.invalid-text-decoration-token-value"
|
||||
msgstr "Valor de token no válido: solo none, underline y strike-through son aceptados"
|
||||
|
||||
#: src/app/main/data/workspace/tokens/errors.cljs:93
|
||||
msgid "workspace.tokens.invalid-token-value-typography"
|
||||
msgstr "Valor no válido: debe hacer referencia a un token tipográfico compuesto."
|
||||
|
||||
@@ -370,7 +370,7 @@ msgstr ""
|
||||
#: src/app/main/ui/exports/files.cljs:164
|
||||
msgid "dashboard.export.options.all.message"
|
||||
msgstr ""
|
||||
"partekatutako liburutegiak dituzten fitxategiak esportazio paketean sartuko "
|
||||
"Partekatutako liburutegiak dituzten fitxategiak esportazio paketean sartuko "
|
||||
"dira eta loturak mantenduko dituzte."
|
||||
|
||||
#: src/app/main/ui/exports/files.cljs:165
|
||||
|
||||
@@ -368,7 +368,7 @@ msgstr ""
|
||||
#: src/app/main/ui/exports/files.cljs:164
|
||||
msgid "dashboard.export.options.all.message"
|
||||
msgstr ""
|
||||
"os ficheiros con bibliotecas compartidas incluiranse na exportación "
|
||||
"Os ficheiros con bibliotecas compartidas incluiranse na exportación "
|
||||
"mantendo os vínculos."
|
||||
|
||||
#: src/app/main/ui/exports/files.cljs:165
|
||||
|
||||
@@ -430,7 +430,7 @@ msgstr "za ka iya fitar da kundi daya ko fiye ta hanyar tura taska. \"me \"*?"
|
||||
|
||||
#: src/app/main/ui/exports/files.cljs:164
|
||||
msgid "dashboard.export.options.all.message"
|
||||
msgstr "manhajar tura kundi ta kunshi fitarwa, tattali mahaxarsu."
|
||||
msgstr "Manhajar tura kundi ta kunshi fitarwa, tattali mahaxarsu."
|
||||
|
||||
#: src/app/main/ui/exports/files.cljs:165
|
||||
msgid "dashboard.export.options.all.title"
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2025-10-13 09:26+0000\n"
|
||||
"PO-Revision-Date: 2025-12-22 15:34+0000\n"
|
||||
"Last-Translator: VKing9 <vaibhavrathod2282@gmail.com>\n"
|
||||
"Language-Team: Hindi "
|
||||
"<https://hosted.weblate.org/projects/penpot/frontend/hi/>\n"
|
||||
"Language-Team: Hindi <https://hosted.weblate.org/projects/penpot/frontend/"
|
||||
"hi/>\n"
|
||||
"Language: hi\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n > 1;\n"
|
||||
"X-Generator: Weblate 5.14-dev\n"
|
||||
"X-Generator: Weblate 5.15.1\n"
|
||||
|
||||
#: src/app/main/ui/auth/register.cljs:215, src/app/main/ui/static.cljs:159, src/app/main/ui/viewer/login.cljs:100
|
||||
msgid "auth.already-have-account"
|
||||
@@ -569,10 +569,11 @@ msgstr ""
|
||||
"लाइब्रेरीज़ का उपयोग कर रही हैं। आप उनके एसेट्स के साथ क्या करना चाहते हैं?"
|
||||
|
||||
#: src/app/main/ui/exports/files.cljs:164
|
||||
#, fuzzy
|
||||
msgid "dashboard.export.options.all.message"
|
||||
msgstr ""
|
||||
"साझा की गई लाइब्रेरीज़ वाली फ़ाइलें निर्यात में शामिल की जाएँगी, और उनका "
|
||||
"लिंक बनाए रखा जाएगा।"
|
||||
"साझा की गई लाइब्रेरीज़ वाली फ़ाइलें निर्यात में शामिल की जाएँगी, और उनका लिंक बनाए रखा "
|
||||
"जाएगा।"
|
||||
|
||||
#: src/app/main/ui/exports/files.cljs:165
|
||||
msgid "dashboard.export.options.all.title"
|
||||
@@ -1726,10 +1727,6 @@ msgstr ""
|
||||
"यदि आप डिजाइन निरीक्षण के बारे में अधिक जानना चाहते हैं, तो कृपया पेनपॉट के "
|
||||
"हेल्प सेंटर पर जाएं"
|
||||
|
||||
#: src/app/main/ui/inspect/right_sidebar.cljs:240
|
||||
msgid "inspect.empty.more-info"
|
||||
msgstr "निरीक्षण के बारे में अधिक जानकारी"
|
||||
|
||||
#: src/app/main/ui/inspect/right_sidebar.cljs:232
|
||||
msgid "inspect.empty.select"
|
||||
msgstr "उनके गुणधर्म और कोड का निरीक्षण करने के लिए कोई आकृति, बोर्ड या समूह चुनें"
|
||||
@@ -4321,7 +4318,7 @@ msgstr ""
|
||||
|
||||
#: src/app/main/ui/settings/subscription.cljs:202
|
||||
msgid "subscription.settings.management.dialog.payment-explanation"
|
||||
msgstr "(अभी कोई भुगतान नहीं किया जाएगा)"
|
||||
msgstr "परीक्षण के बाद शुल्क लिया जाएगा। अभी क्रेडिट कार्ड की आवश्यकता नहीं है।"
|
||||
|
||||
#: src/app/main/ui/settings/subscription.cljs:195, src/app/main/ui/settings/subscription.cljs:199
|
||||
#, markdown
|
||||
@@ -4383,9 +4380,8 @@ msgid "subscription.settings.sucess.dialog.title"
|
||||
msgstr "आप %s हैं!"
|
||||
|
||||
#: src/app/main/ui/settings/subscription.cljs:440
|
||||
#, fuzzy
|
||||
msgid "subscription.settings.support-us-since"
|
||||
msgstr "आप इस योजना के साथ %s से हमारा समर्थन कर रहे हैं"
|
||||
msgstr "आप इस योजना में हमारा समर्थन तब से कर रहे हैं: %s"
|
||||
|
||||
#: src/app/main/ui/settings/subscription.cljs:472, src/app/main/ui/settings/subscription.cljs:488
|
||||
msgid "subscription.settings.try-it-free"
|
||||
@@ -7169,7 +7165,6 @@ msgid "workspace.tokens.opacity-range"
|
||||
msgstr "अपारदर्शिता 0 और 100% या 0 और 1 (जैसे 50% या 0.5) के बीच होनी चाहिए।"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/token_pill.cljs:120
|
||||
#, fuzzy
|
||||
msgid "workspace.tokens.original-value"
|
||||
msgstr "मूल मान: %s"
|
||||
|
||||
@@ -7191,9 +7186,8 @@ msgid "workspace.tokens.reference-error"
|
||||
msgstr "संदर्भ त्रुटियाँ: "
|
||||
|
||||
#: src/app/main/data/workspace/tokens/warnings.cljs:15, src/app/main/data/workspace/tokens/warnings.cljs:19, src/app/main/ui/workspace/colorpicker/color_tokens.cljs:56, src/app/main/ui/workspace/colorpicker/color_tokens.cljs:84, src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:102, src/app/main/ui/workspace/tokens/management/create/form_input_token.cljs:109, src/app/main/ui/workspace/tokens/management/create/input_tokens_value.cljs:41, src/app/main/ui/workspace/tokens/management/create/input_tokens_value.cljs:46, src/app/main/ui/workspace/tokens/management/token_pill.cljs:121
|
||||
#, fuzzy
|
||||
msgid "workspace.tokens.resolved-value"
|
||||
msgstr "समाधानित मान: %s"
|
||||
msgstr "हल किया गया मान: %s"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/themes/create_modal.cljs:272
|
||||
msgid "workspace.tokens.save-theme"
|
||||
@@ -7259,7 +7253,6 @@ msgid "workspace.tokens.themes-list"
|
||||
msgstr "थीम्स सूची"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/border_radius.cljs:194, src/app/main/ui/workspace/tokens/management/create/border_radius.cljs:195, src/app/main/ui/workspace/tokens/management/create/form.cljs:629, src/app/main/ui/workspace/tokens/management/create/form.cljs:630
|
||||
#, fuzzy
|
||||
msgid "workspace.tokens.token-description"
|
||||
msgstr "वर्णन"
|
||||
|
||||
@@ -7628,3 +7621,826 @@ msgstr "स्वतः सहेजे गए संस्करण %s दि
|
||||
#, unused
|
||||
msgid "workspace.viewport.click-to-close-path"
|
||||
msgstr "पथ बंद करने के लिए क्लिक करें"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:100, src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:107
|
||||
msgid "color-row.token-color-row.deleted-token"
|
||||
msgstr "यह token मौजूद नहीं है या हटा दिया गया है।"
|
||||
|
||||
#: src/app/main/ui/workspace/colorpicker/color_tokens.cljs:35
|
||||
msgid "color-token.empty-state"
|
||||
msgstr "कोई रंग tokens उपलब्ध नहीं है। सक्रिय सेट/थीम देखें या नए टोकन जोड़ें।"
|
||||
|
||||
#: src/app/main/ui/dashboard/team.cljs:765
|
||||
msgid "dashboard.invitation-modal.delete"
|
||||
msgstr "आप निम्न आमंत्रणों को हटाने जा रहे हैं:"
|
||||
|
||||
#: src/app/main/ui/dashboard/team.cljs:766
|
||||
msgid "dashboard.invitation-modal.resend"
|
||||
msgstr "आप निम्नलिखित को पुनः निमंत्रण भेजने जा रहे हैं:"
|
||||
|
||||
#: src/app/main/ui/dashboard/team.cljs:756
|
||||
msgid "dashboard.invitation-modal.title.delete-invitations"
|
||||
msgstr "निमंत्रण हटाएँ"
|
||||
|
||||
#: src/app/main/ui/dashboard/team.cljs:757
|
||||
msgid "dashboard.invitation-modal.title.resend-invitations"
|
||||
msgstr "निमंत्रण पुनः भेजें"
|
||||
|
||||
#: src/app/main/ui/dashboard/team.cljs:949
|
||||
msgid "dashboard.order-invitations-by-role"
|
||||
msgstr "भूमिका के अनुसार क्रमबद्ध करें"
|
||||
|
||||
#: src/app/main/ui/dashboard/team.cljs:958
|
||||
msgid "dashboard.order-invitations-by-status"
|
||||
msgstr "स्थिति के अनुसार क्रमबद्ध करें"
|
||||
|
||||
#: src/app/main/ui/ds/controls/numeric_input.cljs:99
|
||||
msgid "ds.inputs.numeric-input.no-applicable-tokens"
|
||||
msgstr "सक्रिय सेट या थीम में कोई लागू tokens नहीं।"
|
||||
|
||||
#: src/app/main/ui/ds/controls/numeric_input.cljs:100
|
||||
msgid "ds.inputs.numeric-input.no-matches"
|
||||
msgstr "कोई मेल नहीं मिले।"
|
||||
|
||||
#: src/app/main/ui/ds/controls/numeric_input.cljs:650, src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:140
|
||||
msgid "ds.inputs.numeric-input.open-token-list-dropdown"
|
||||
msgstr "token सूची खोलें"
|
||||
|
||||
#: src/app/main/ui/ds/controls/utilities/token_field.cljs:87, src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:135
|
||||
msgid "ds.inputs.token-field.detach-token"
|
||||
msgstr "token अलग करें"
|
||||
|
||||
#: src/app/main/ui/ds/controls/utilities/token_field.cljs:41, src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:98, src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:105
|
||||
msgid "ds.inputs.token-field.no-active-token-option"
|
||||
msgstr "यह token किसी भी सक्रिय सेट में नहीं है या इसका मान अमान्य है।"
|
||||
|
||||
#: src/app/main/ui/auth/register.cljs:89
|
||||
msgid "errors.email-does-not-match-invitation"
|
||||
msgstr "ईमेल आमंत्रण से मेल नहीं खाता।"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/border_radius.cljs:52, src/app/main/ui/workspace/tokens/management/create/form.cljs:80
|
||||
msgid "errors.field-max-length"
|
||||
msgstr "इसमें अधिकतम %s वर्ण होने चाहिए।"
|
||||
|
||||
#: src/app/main/ui/dashboard/team.cljs:853
|
||||
msgid "errors.max-quote-reached"
|
||||
msgstr "|"
|
||||
|
||||
#: src/app/main/errors.cljs:167
|
||||
msgid "errors.only-creator-can-lock"
|
||||
msgstr "केवल संस्करण निर्माता ही इसे लॉक कर सकता है"
|
||||
|
||||
#: src/app/main/errors.cljs:175
|
||||
msgid "errors.only-creator-can-unlock"
|
||||
msgstr "केवल संस्करण निर्माता ही इसे अनलॉक कर सकता है"
|
||||
|
||||
#: src/app/main/errors.cljs:183
|
||||
msgid "errors.version-already-locked"
|
||||
msgstr "यह संस्करण पहले से ही लॉक है"
|
||||
|
||||
#: src/app/main/errors.cljs:159
|
||||
msgid "errors.version-locked"
|
||||
msgstr "यह संस्करण लॉक है और इसे अन्य लोग हटा नहीं सकते"
|
||||
|
||||
#: src/app/main/ui/settings/feedback.cljs:122
|
||||
msgid "feedback.description-placeholder"
|
||||
msgstr "कृपया अपनी प्रतिक्रिया का कारण बताएँ"
|
||||
|
||||
#: src/app/main/ui/settings/feedback.cljs:143
|
||||
msgid "feedback.other-ways-contact"
|
||||
msgstr "हमसे संपर्क करने के अन्य तरीके"
|
||||
|
||||
#: src/app/main/ui/settings/feedback.cljs:126
|
||||
msgid "feedback.penpot.link"
|
||||
msgstr ""
|
||||
"यदि फीडबैक किसी फ़ाइल या प्रोजेक्ट से संबंधित है, तो यहां पेनपॉट लिंक जोड़ें:"
|
||||
|
||||
#: src/app/main/ui/settings/feedback.cljs:101
|
||||
msgid "feedback.title-contact-us"
|
||||
msgstr "हमसे संपर्क करें"
|
||||
|
||||
#: src/app/main/ui/settings/feedback.cljs:110, src/app/main/ui/settings/feedback.cljs:111
|
||||
msgid "feedback.type"
|
||||
msgstr "प्रकार"
|
||||
|
||||
#: src/app/main/ui/settings/feedback.cljs:115
|
||||
msgid "feedback.type.doubt"
|
||||
msgstr "संदेह"
|
||||
|
||||
#: src/app/main/ui/settings/feedback.cljs:113
|
||||
msgid "feedback.type.idea"
|
||||
msgstr "विचार"
|
||||
|
||||
#: src/app/main/ui/settings/feedback.cljs:114
|
||||
msgid "feedback.type.issue"
|
||||
msgstr "मुद्दा"
|
||||
|
||||
#: src/app/main/ui/inspect/styles/rows/color_properties_row.cljs:120
|
||||
msgid "inspect.attributes.image.preview"
|
||||
msgstr "आकृति की भरण छवि का पूर्वावलोकन"
|
||||
|
||||
#, unused
|
||||
msgid "inspect.attributes.typography.text-decoration.line-through"
|
||||
msgstr "स्ट्राइकथ्रू"
|
||||
|
||||
#: src/app/main/ui/inspect/attributes/text.cljs:125, src/app/main/ui/workspace/sidebar/options/menus/typography.cljs:429
|
||||
msgid "inspect.attributes.typography.text-transform.capitalize"
|
||||
msgstr "प्रमुख अक्षर करना"
|
||||
|
||||
#: src/app/main/ui/inspect/right_sidebar.cljs:170
|
||||
msgid "inspect.color-space-label"
|
||||
msgstr "रंग स्थान चुनें"
|
||||
|
||||
#: src/app/main/ui/inspect/right_sidebar.cljs:166
|
||||
#, fuzzy
|
||||
msgid "inspect.layer-info"
|
||||
msgstr "निरीक्षण टैब चुनें"
|
||||
|
||||
#: src/app/main/ui/inspect/styles/panels/tokens_panel.cljs:26
|
||||
msgid "inspect.tabs.styles.active-sets"
|
||||
msgstr "सक्रिय सेट"
|
||||
|
||||
#: src/app/main/ui/inspect/styles/panels/tokens_panel.cljs:21
|
||||
msgid "inspect.tabs.styles.active-themes"
|
||||
msgstr "सक्रिय थीम"
|
||||
|
||||
#: src/app/main/ui/inspect/styles/style_box.cljs:68
|
||||
msgid "inspect.tabs.styles.copy-shorthand"
|
||||
msgstr "CSS शॉर्टहैंड को क्लिपबोर्ड पर कॉपी करें"
|
||||
|
||||
#: src/app/main/ui/inspect/styles/property_detail_copiable.cljs:51
|
||||
msgid "inspect.tabs.styles.copy-to-clipboard"
|
||||
msgstr "क्लिपबोर्ड पर कॉपी करें"
|
||||
|
||||
#: src/app/main/ui/inspect/styles/style_box.cljs:22
|
||||
msgid "inspect.tabs.styles.geometry-panel"
|
||||
msgstr "आकार & स्थिति"
|
||||
|
||||
#: src/app/main/ui/inspect/styles/style_box.cljs:60, src/app/main/ui/workspace/colorpicker/color_tokens.cljs:179
|
||||
msgid "inspect.tabs.styles.toggle-style"
|
||||
msgstr "टॉगल पैनल %s"
|
||||
|
||||
#: src/app/main/ui/inspect/styles/style_box.cljs:21
|
||||
msgid "inspect.tabs.styles.token-panel"
|
||||
msgstr "Token सेट और थीम"
|
||||
|
||||
#: src/app/main/ui/inspect/styles/rows/color_properties_row.cljs:102, src/app/main/ui/inspect/styles/rows/properties_row.cljs:60
|
||||
msgid "inspect.tabs.styles.token-resolved-value"
|
||||
msgstr "हल किया गया मान:"
|
||||
|
||||
#: src/app/main/ui/inspect/styles/style_box.cljs:20
|
||||
msgid "inspect.tabs.styles.variants-panel"
|
||||
msgstr "भिन्न गुण"
|
||||
|
||||
#: src/app/main/ui/dashboard/sidebar.cljs:1044
|
||||
msgid "labels.about-penpot"
|
||||
msgstr "पेनपोट के बारे में"
|
||||
|
||||
#: src/app/main/ui/inspect/styles/style_box.cljs:26
|
||||
msgid "labels.blur"
|
||||
msgstr "धुंधला"
|
||||
|
||||
#: src/app/main/ui/workspace/colorpicker.cljs:423
|
||||
msgid "labels.color"
|
||||
msgstr "रंग"
|
||||
|
||||
#: src/app/main/ui/dashboard/sidebar.cljs:1031
|
||||
msgid "labels.community-contributions"
|
||||
msgstr "समुदाय & योगदान"
|
||||
|
||||
#: src/app/main/ui/inspect/right_sidebar.cljs:109
|
||||
msgid "labels.computed"
|
||||
msgstr "परिकलित"
|
||||
|
||||
#: src/app/main/ui/static.cljs:406
|
||||
msgid "labels.contact-support"
|
||||
msgstr "समर्थन से संपर्क करें"
|
||||
|
||||
#: src/app/main/ui/settings/sidebar.cljs:136
|
||||
msgid "labels.contact-us"
|
||||
msgstr "हमसे संपर्क करें"
|
||||
|
||||
#: src/app/main/ui/static.cljs:68
|
||||
msgid "labels.copyright-period"
|
||||
msgstr "कैलिडोस © 2019-वर्तमान"
|
||||
|
||||
#: src/app/main/ui/settings/feedback.cljs:134, src/app/main/ui/static.cljs:400
|
||||
msgid "labels.download"
|
||||
msgstr "%s डाउनलोड करें"
|
||||
|
||||
#: src/app/main/ui/inspect/styles/style_box.cljs:23
|
||||
msgid "labels.fill"
|
||||
msgstr "भरना"
|
||||
|
||||
#: src/app/main/ui/dashboard/sidebar.cljs:1020
|
||||
msgid "labels.help-learning"
|
||||
msgstr "मदद & सीखना"
|
||||
|
||||
#: src/app/main/ui/static.cljs:396
|
||||
msgid "labels.internal-error.desc-message-first"
|
||||
msgstr "कुछ बुरा हुआ।"
|
||||
|
||||
#: src/app/main/ui/static.cljs:397
|
||||
msgid "labels.internal-error.desc-message-second"
|
||||
msgstr ""
|
||||
"आप ऑपरेशन पुनः प्रयास कर सकते हैं या त्रुटि की रिपोर्ट करने के लिए समर्थन से संपर्क कर सकते हैं"
|
||||
"।"
|
||||
|
||||
#: src/app/main/ui/inspect/styles/style_box.cljs:28
|
||||
msgid "labels.layout"
|
||||
msgstr "लेआउट"
|
||||
|
||||
#: src/app/main/ui/dashboard/sidebar.cljs:799
|
||||
msgid "labels.learning-center"
|
||||
msgstr "अध्ययन केन्द्र"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/versions.cljs:209
|
||||
msgid "labels.lock"
|
||||
msgstr "ताला"
|
||||
|
||||
#: src/app/main/ui/ds/controls/numeric_input.cljs:628
|
||||
msgid "labels.mixed-values"
|
||||
msgstr "मिश्रित"
|
||||
|
||||
#: src/app/main/ui/dashboard/sidebar.cljs:879
|
||||
msgid "labels.penpot-changelog"
|
||||
msgstr "पेनपॉट चेंजलॉग"
|
||||
|
||||
#: src/app/main/ui/dashboard/sidebar.cljs:805
|
||||
msgid "labels.penpot-hub"
|
||||
msgstr "पेनपॉट हब"
|
||||
|
||||
#: src/app/main/ui/dashboard/sidebar.cljs:752
|
||||
msgid "labels.pinned-projects"
|
||||
msgstr "पिन किए गए प्रोजेक्ट"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs:667
|
||||
msgid "labels.reference"
|
||||
msgstr "संदर्भ"
|
||||
|
||||
#: src/app/main/ui/dashboard/team.cljs:788
|
||||
msgid "labels.resend"
|
||||
msgstr "पुन: भेजें"
|
||||
|
||||
#: src/app/main/ui/inspect/styles/style_box.cljs:27
|
||||
msgid "labels.shadow"
|
||||
msgstr "छाया"
|
||||
|
||||
#: src/app/main/ui/dashboard/sidebar.cljs:731
|
||||
msgid "labels.sources"
|
||||
msgstr "स्त्रोत"
|
||||
|
||||
#: src/app/main/ui/inspect/styles/style_box.cljs:24, src/app/main/ui/workspace/sidebar/options/menus/stroke.cljs:46
|
||||
msgid "labels.stroke"
|
||||
msgstr "स्ट्रोक"
|
||||
|
||||
#: src/app/main/ui/inspect/right_sidebar.cljs:107, src/app/main/ui/inspect/styles.cljs:134
|
||||
msgid "labels.styles"
|
||||
msgstr "शैलियों"
|
||||
|
||||
#: src/app/main/ui/inspect/styles/style_box.cljs:33
|
||||
msgid "labels.svg"
|
||||
msgstr "SVG"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/rows/stroke_row.cljs:229
|
||||
msgid "labels.switch"
|
||||
msgstr "बदलना"
|
||||
|
||||
#: src/app/main/ui/inspect/styles/style_box.cljs:25
|
||||
msgid "labels.text"
|
||||
msgstr "मूलपाठ"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs:1452
|
||||
msgid "labels.typography"
|
||||
msgstr "अक्षर विन्यास"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/versions.cljs:203
|
||||
msgid "labels.unlock"
|
||||
msgstr "अनलॉक"
|
||||
|
||||
#: src/app/main/ui/inspect/right_sidebar.cljs:65, src/app/main/ui/workspace/sidebar/options/menus/component.cljs:1028
|
||||
msgid "labels.variant"
|
||||
msgstr "रूपांतर"
|
||||
|
||||
#: src/app/main/ui/dashboard/sidebar.cljs:873
|
||||
msgid "labels.version-notes"
|
||||
msgstr "संस्करण %s नोट्स"
|
||||
|
||||
#: src/app/main/ui/inspect/styles/style_box.cljs:32
|
||||
msgid "labels.visibility"
|
||||
msgstr "दृश्यता"
|
||||
|
||||
#: src/app/main/ui/dashboard/team.cljs:825
|
||||
msgid "notifications.invitation-deleted"
|
||||
msgstr "आमंत्रण सफलतापूर्वक हटा दिया गया"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/shortcuts.cljs:97
|
||||
msgid "shortcuts.create-component-variant"
|
||||
msgstr "घटक/संस्करण बनाएं"
|
||||
|
||||
#: src/app/main/ui/dashboard/subscription.cljs:109
|
||||
msgid "subscription.dashboard.power-up.enterprise-trial.top-title"
|
||||
msgstr "एंटरप्राइज़ योजना (परीक्षण)"
|
||||
|
||||
#: src/app/main/ui/dashboard/subscription.cljs:84
|
||||
msgid "subscription.dashboard.power-up.professional.bottom-button"
|
||||
msgstr "शक्तिप्रापक!"
|
||||
|
||||
#: src/app/main/ui/dashboard/subscription.cljs:83
|
||||
msgid "subscription.dashboard.power-up.professional.bottom-description"
|
||||
msgstr ""
|
||||
"अपनी टीमों के लिए अतिरिक्त संग्रहण, फ़ाइल पुनर्प्राप्ति और बहुत कुछ प्राप्त करें।"
|
||||
|
||||
#: src/app/main/ui/dashboard/subscription.cljs:101
|
||||
#, markdown
|
||||
msgid "subscription.dashboard.power-up.unlimited.bottom-text"
|
||||
msgstr ""
|
||||
"अपनी सभी टीमों के लिए एक निश्चित कीमत पर असीमित स्टोरेज, विस्तारित फ़ाइल रिकवरी और "
|
||||
"असीमित एडिटर प्राप्त करें। [एंटरप्राइज़ प्लान देखें।|target:self](%s)"
|
||||
|
||||
#: src/app/main/ui/dashboard/subscription.cljs:194
|
||||
msgid "subscription.dashboard.professional-dashboard-cta-title"
|
||||
msgstr ""
|
||||
"आपकी स्वामित्व वाली टीमों में %s संपादक हैं, जबकि आपकी व्यावसायिक योजना 8 तक को कवर "
|
||||
"करती है।"
|
||||
|
||||
#: src/app/main/ui/dashboard/subscription.cljs:202
|
||||
#, markdown
|
||||
msgid "subscription.dashboard.professional-dashboard-cta-upgrade-owner"
|
||||
msgstr ""
|
||||
"कृपया ज़्यादा एडिटर, स्टोरेज और फ़ाइल रिकवरी के लिए अभी अनलिमिटेड या एंटरप्राइज़ में "
|
||||
"अपग्रेड करें। [अभी सब्सक्राइब करें।|target:self](%s)"
|
||||
|
||||
#: src/app/main/ui/dashboard/subscription.cljs:197
|
||||
msgid "subscription.dashboard.unlimited-dashboard-cta-title"
|
||||
msgstr ""
|
||||
"आपकी टीम बढ़ती जा रही है! आपकी अनलिमिटेड योजना में %s संपादकों तक की सेवाएँ शामिल हैं, "
|
||||
"लेकिन अब आपके पास %s हैं।"
|
||||
|
||||
#: src/app/main/ui/dashboard/subscription.cljs:205
|
||||
#, markdown
|
||||
msgid "subscription.dashboard.unlimited-dashboard-cta-upgrade-owner"
|
||||
msgstr ""
|
||||
"कृपया अपनी वर्तमान संपादक संख्या से मेल खाने के लिए अभी अपग्रेड करें। [अभी सदस्यता लें"
|
||||
"।|target:self](%s)"
|
||||
|
||||
#: src/app/main/ui/dashboard/subscription.cljs:182
|
||||
msgid "subscription.dashboard.unlimited-members-extra-editors-cta-text"
|
||||
msgstr ""
|
||||
"आपकी स्वामित्व वाली टीमों के केवल नए संपादक ही भविष्य के बिलिंग में शामिल होंगे। 25+ "
|
||||
"संपादकों के लिए अभी भी $175/माह का एक समान शुल्क लागू है।"
|
||||
|
||||
#: src/app/main/ui/dashboard/subscription.cljs:178
|
||||
msgid "subscription.dashboard.unlimited-members-extra-editors-cta-title"
|
||||
msgstr "असीमित योजना के दौरान लोगों को आमंत्रित करना"
|
||||
|
||||
#: src/app/main/ui/settings/subscription.cljs:53
|
||||
msgid "subscription.settings.editors"
|
||||
msgstr "(x %s संपादक)"
|
||||
|
||||
#: src/app/main/ui/settings/subscription.cljs:418, src/app/main/ui/settings/subscription.cljs:428, src/app/main/ui/settings/subscription.cljs:486
|
||||
msgid "subscription.settings.enterprise.autosave"
|
||||
msgstr "90-दिन के ऑटोसेव संस्करण और फ़ाइल पुनर्प्राप्ति"
|
||||
|
||||
#: src/app/main/ui/settings/subscription.cljs:419, src/app/main/ui/settings/subscription.cljs:429, src/app/main/ui/settings/subscription.cljs:487
|
||||
msgid "subscription.settings.enterprise.capped-bill"
|
||||
msgstr "फ्लैट मासिक बिल"
|
||||
|
||||
#: src/app/main/ui/settings/subscription.cljs:417, src/app/main/ui/settings/subscription.cljs:427, src/app/main/ui/settings/subscription.cljs:485
|
||||
msgid "subscription.settings.enterprise.unlimited-storage-benefit"
|
||||
msgstr "असीमित भंडारण"
|
||||
|
||||
#: src/app/main/ui/settings/subscription.cljs:154
|
||||
msgid "subscription.settings.management.dialog.currently-editors-title"
|
||||
msgid_plural "subscription.settings.management.dialog.currently-editors-title"
|
||||
msgstr[0] "वर्तमान में, आपकी टीम में %s व्यक्ति हैं जो संपादन कर सकते हैं।"
|
||||
msgstr[1] "वर्तमान में, आपकी टीम में %s लोग हैं जो संपादन कर सकते हैं।"
|
||||
|
||||
#: src/app/main/ui/inspect/attributes/text.cljs:112
|
||||
msgid "inspect.attributes.typography.text-decoration.strikethrough"
|
||||
msgstr " "
|
||||
|
||||
#: src/app/main/ui/inspect/right_sidebar.cljs:177
|
||||
msgid "inspect.tabs-switcher-label"
|
||||
msgstr " "
|
||||
|
||||
#: src/app/main/ui/settings/subscription.cljs:156
|
||||
msgid "subscription.settings.management.dialog.editors"
|
||||
msgstr "संपादनकर्ता"
|
||||
|
||||
#: src/app/main/ui/settings/subscription.cljs:163
|
||||
msgid "subscription.settings.management.dialog.editors-explanation"
|
||||
msgstr "(स्वामी, व्यवस्थापक और संपादक। दर्शकों को संपादक नहीं माना जाएगा)"
|
||||
|
||||
#: src/app/main/ui/settings/subscription.cljs:206
|
||||
msgid "subscription.settings.management.dialog.input-error"
|
||||
msgstr ""
|
||||
"आप मौजूदा संपादकों की संख्या से कम संपादक नहीं सेट कर सकते। टीम सेटिंग में उन लोगों की "
|
||||
"भूमिका (संपादक/व्यवस्थापक से दर्शक) बदलें जो वास्तव में फ़ाइलें संपादित नहीं करते हैं।"
|
||||
|
||||
msgid "subscription.settings.management-dialog.step-2-title"
|
||||
msgstr "हमें आगे बढ़ने में मदद करें और अपने परीक्षण को आसान बनाएं"
|
||||
|
||||
msgid "subscription.settings.management-dialog.step-2-description"
|
||||
msgstr ""
|
||||
"परीक्षण अवधि के बाद अपनी सदस्यता को सुचारू रूप से जारी रखने और हमारे ओपन-सोर्स प्रोजेक्ट "
|
||||
"का समर्थन जारी रखने के लिए अभी अपनी भुगतान जानकारी जोड़ें। आपसे अभी कोई शुल्क नहीं लिया "
|
||||
"जाएगा।"
|
||||
|
||||
msgid "subscription.settings.management-dialog.step-2-skip-button"
|
||||
msgstr "अभी छोड़ें और परीक्षण शुरू करें"
|
||||
|
||||
msgid "subscription.settings.management-dialog.step-2-add-payment-button"
|
||||
msgstr "भुगतान विवरण जोड़ें"
|
||||
|
||||
#: src/app/main/ui/settings/subscription.cljs:209
|
||||
msgid "subscription.settings.management.dialog.unlimited-capped-warning"
|
||||
msgstr ""
|
||||
"सुझाव: आमंत्रणों से आगे रहने के लिए आप अभी अपनी सीटों की संख्या बढ़ा सकते हैं। 25+ संपादकों "
|
||||
"वाली टीमों में, आपको प्रति माह ₹175 का एकमुश्त शुल्क मिलेगा।"
|
||||
|
||||
#: src/app/main/ui/settings/subscription.cljs:385, src/app/main/ui/settings/subscription.cljs:456
|
||||
msgid "subscription.settings.professional.autosave-benefit"
|
||||
msgstr "7-दिन का स्वतः सहेजा गया संस्करण और फ़ाइल पुनर्प्राप्ति"
|
||||
|
||||
#: src/app/main/ui/settings/subscription.cljs:384, src/app/main/ui/settings/subscription.cljs:455
|
||||
msgid "subscription.settings.professional.storage-benefit"
|
||||
msgstr "10GB स्टोरेज"
|
||||
|
||||
#: src/app/main/ui/settings/subscription.cljs:386, src/app/main/ui/settings/subscription.cljs:457
|
||||
msgid "subscription.settings.professional.teams-editors-benefit"
|
||||
msgstr "असीमित टीमें। आपकी स्वामित्व वाली टीमों में अधिकतम 8 संपादक।"
|
||||
|
||||
#: src/app/main/ui/settings/subscription.cljs:50
|
||||
msgid "subscription.settings.recommended"
|
||||
msgstr "अनुशंसित"
|
||||
|
||||
#: src/app/main/ui/settings/subscription.cljs:263
|
||||
msgid "subscription.settings.success.dialog.thanks"
|
||||
msgstr "पेनपोट %s योजना चुनने के लिए धन्यवाद!"
|
||||
|
||||
#: src/app/main/ui/settings/subscription.cljs:394, src/app/main/ui/settings/subscription.cljs:406, src/app/main/ui/settings/subscription.cljs:470
|
||||
msgid "subscription.settings.unlimited.autosave-benefit"
|
||||
msgstr "30-दिन का स्वतः सहेजा गया संस्करण और फ़ाइल पुनर्प्राप्ति"
|
||||
|
||||
#: src/app/main/ui/settings/subscription.cljs:393, src/app/main/ui/settings/subscription.cljs:405, src/app/main/ui/settings/subscription.cljs:469
|
||||
msgid "subscription.settings.unlimited.storage-benefit"
|
||||
msgstr "25GB स्टोरेज"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/versions.cljs:56
|
||||
#, markdown
|
||||
msgid "subscription.workspace.versions.warning.enterprise.subtext-owner"
|
||||
msgstr "यदि आप इस सीमा को बढ़ाना चाहते हैं, तो हमें [%s](mailto) पर लिखें"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/versions.cljs:58
|
||||
#, markdown
|
||||
msgid "subscription.workspace.versions.warning.subtext-member"
|
||||
msgstr ""
|
||||
"यदि आप इस सीमा को बढ़ाना चाहते हैं, तो टीम के मालिक से संपर्क करें: [%s](mailto)"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/versions.cljs:57
|
||||
#, markdown
|
||||
msgid "subscription.workspace.versions.warning.subtext-owner"
|
||||
msgstr ""
|
||||
"यदि आप इस सीमा को बढ़ाना चाहते हैं, तो [अपना प्लान अपग्रेड करें|target:self](%s)"
|
||||
|
||||
#: src/app/main/ui/dashboard/team.cljs:933
|
||||
msgid "team.invitations-selected"
|
||||
msgid_plural "team.invitations-selected"
|
||||
msgstr[0] "1 आमंत्रण चयनित"
|
||||
msgstr[1] "%s आमंत्रण चयनित"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/assets/groups.cljs:81
|
||||
msgid "workspace.assets.component-group-options"
|
||||
msgstr "घटक समूह विकल्प"
|
||||
|
||||
#: src/app/main/ui/workspace/colorpicker.cljs:427, src/app/main/ui/workspace/colorpicker.cljs:439
|
||||
msgid "workspace.colorpicker.color-tokens"
|
||||
msgstr "रंग टोकन"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/component.cljs:499
|
||||
msgid "workspace.component.swap.loop-error"
|
||||
msgstr "घटकों को अपने अंदर नहीं रखा जा सकता।"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/component.cljs:498
|
||||
msgid "workspace.component.switch.loop-error-multi"
|
||||
msgstr ""
|
||||
"कुछ प्रतियों को स्विच नहीं किया जा सका। घटकों को आपस में नेस्ट नहीं किया जा सकता।"
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:107, src/app/main/ui/workspace/libraries.cljs:133
|
||||
msgid "workspace.libraries.colors"
|
||||
msgid_plural "workspace.libraries.colors"
|
||||
msgstr[0] "1 रंग"
|
||||
msgstr[1] "%s रंग"
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:101, src/app/main/ui/workspace/libraries.cljs:125
|
||||
msgid "workspace.libraries.components"
|
||||
msgid_plural "workspace.libraries.components"
|
||||
msgstr[0] "1 घटक"
|
||||
msgstr[1] "%s घटक"
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:349
|
||||
msgid "workspace.libraries.connected-to"
|
||||
msgstr "से जुड़ा"
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:104, src/app/main/ui/workspace/libraries.cljs:129
|
||||
msgid "workspace.libraries.graphics"
|
||||
msgid_plural "workspace.libraries.graphics"
|
||||
msgstr[0] "1 ग्राफ़िक"
|
||||
msgstr[1] "%s ग्राफ़िक्स"
|
||||
|
||||
#: src/app/main/ui/workspace/libraries.cljs:110, src/app/main/ui/workspace/libraries.cljs:137
|
||||
msgid "workspace.libraries.typography"
|
||||
msgid_plural "workspace.libraries.typography"
|
||||
msgstr[0] "1 अक्षर विन्यास"
|
||||
msgstr[1] "%s अक्षर विन्यास"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/component.cljs:563
|
||||
msgid "workspace.options.component.variant.duplicated.copy.locate"
|
||||
msgstr "परस्पर विरोधी वेरिएंट का पता लगाएं"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/component.cljs:560
|
||||
msgid "workspace.options.component.variant.duplicated.copy.title"
|
||||
msgstr ""
|
||||
"इस घटक में परस्पर विरोधी वैरिएंट हैं। सुनिश्चित करें कि प्रत्येक वैरिएंट में गुण मानों का एक "
|
||||
"विशिष्ट सेट हो।"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/component.cljs:1330
|
||||
msgid "workspace.options.component.variant.duplicated.group.locate"
|
||||
msgstr "डुप्लिकेट वेरिएंट का पता लगाएँ"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/component.cljs:1327
|
||||
msgid "workspace.options.component.variant.duplicated.group.title"
|
||||
msgstr "कुछ वेरिएंट में समान गुण और मूल्य होते हैं"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/component.cljs:268
|
||||
msgid "workspace.options.component.variant.duplicated.single.all"
|
||||
msgstr ""
|
||||
"इन वेरिएंट के गुण और मान समान हैं। मानों को समायोजित करें ताकि उन्हें पुनर्प्राप्त किया जा सके"
|
||||
"।"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/component.cljs:265
|
||||
msgid "workspace.options.component.variant.duplicated.single.one"
|
||||
msgstr ""
|
||||
"इस संस्करण के गुण और मान दूसरे संस्करण के समान हैं। मानों को समायोजित करें ताकि उन्हें "
|
||||
"पुनर्प्राप्त किया जा सके।"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/component.cljs:271
|
||||
msgid "workspace.options.component.variant.duplicated.single.some"
|
||||
msgstr ""
|
||||
"इनमें से कुछ वेरिएंट के गुण और मान समान हैं। मानों को समायोजित करें ताकि उन्हें पुनर्प्राप्त "
|
||||
"किया जा सके।"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/component.cljs:550
|
||||
msgid "workspace.options.component.variant.malformed.copy"
|
||||
msgstr ""
|
||||
"इस घटक के कुछ वेरिएंट अमान्य नामों वाले हैं। सुनिश्चित करें कि प्रत्येक वेरिएंट सही संरचना का "
|
||||
"पालन कर रहा है।"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/component.cljs:553
|
||||
msgid "workspace.options.component.variant.malformed.locate"
|
||||
msgstr "अमान्य वेरिएंट का पता लगाएं"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/variants_help_modal.cljs:54
|
||||
msgid "workspace.options.component.variants-help-modal.intro"
|
||||
msgstr ""
|
||||
"वेरिएंट के बीच स्विच करते समय परिवर्तनों को बनाए रखने के लिए, पेनपॉट उन परतों को जोड़ता "
|
||||
"है जो:"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/variants_help_modal.cljs:91
|
||||
msgid "workspace.options.component.variants-help-modal.outro"
|
||||
msgstr ""
|
||||
"इनमें से किसी भी परिवर्तन (जैसे, परत का नाम बदलना या समूह बनाना) से कनेक्शन टूट जाता है, "
|
||||
"लेकिन परिवर्तन को पूर्ववत करने से यह पुनः स्थापित हो जाएगा।"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/variants_help_modal.cljs:67
|
||||
msgid "workspace.options.component.variants-help-modal.rule1"
|
||||
msgstr "एक ही नाम साझा करें।"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/variants_help_modal.cljs:76
|
||||
msgid "workspace.options.component.variants-help-modal.rule2"
|
||||
msgstr "एक ही प्रकार के हैं।"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/variants_help_modal.cljs:77
|
||||
msgid "workspace.options.component.variants-help-modal.rule2.detail"
|
||||
msgstr "आयत, दीर्घवृत्त, पथ और बूलियन ऑपरेशन एक ही प्रकार के माने जाते हैं।"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/variants_help_modal.cljs:87
|
||||
msgid "workspace.options.component.variants-help-modal.rule3"
|
||||
msgstr "समान पदानुक्रम स्तर रखें।"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/variants_help_modal.cljs:88
|
||||
msgid "workspace.options.component.variants-help-modal.rule3.detail"
|
||||
msgstr "समूह, बोर्ड और लेआउट को समतुल्य माना जाता है।"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/component.cljs:1034, src/app/main/ui/workspace/sidebar/options/menus/component.cljs:1278, src/app/main/ui/workspace/sidebar/options/menus/variants_help_modal.cljs:47
|
||||
msgid "workspace.options.component.variants-help-modal.title"
|
||||
msgstr "वेरिएंट कैसे जुड़े रहते हैं"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/color_selection.cljs:264
|
||||
msgid "workspace.options.more-token-colors"
|
||||
msgstr "अधिक रंग के टोकन"
|
||||
|
||||
#: src/app/main/ui/workspace/plugins.cljs:287
|
||||
msgid "workspace.plugins.permissions.allow-localstorage"
|
||||
msgstr "ब्राउज़र में डेटा संग्रहीत करें।"
|
||||
|
||||
#: src/app/main/ui/workspace/context_menu.cljs:617, src/app/main/ui/workspace/sidebar/assets/components.cljs:634, src/app/main/ui/workspace/sidebar/assets/groups.cljs:75, src/app/main/ui/workspace/sidebar/options/menus/component.cljs:1095
|
||||
msgid "workspace.shape.menu.combine-as-variants"
|
||||
msgstr "वैरिएंट के रूप में संयोजित करें"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/assets/components.cljs:636
|
||||
msgid "workspace.shape.menu.combine-as-variants-error"
|
||||
msgstr "घटकों को एक ही पृष्ठ पर होना आवश्यक है"
|
||||
|
||||
#: src/app/main/ui/workspace/sidebar/options/menus/component.cljs:1145
|
||||
msgid "workspace.shape.menu.remove-variant-property.last-property"
|
||||
msgstr "वैरिएंट में कम से कम एक प्रॉपर्टी होनी चाहिए"
|
||||
|
||||
#: src/app/main/data/workspace/tokens/errors.cljs:97
|
||||
msgid "workspace.tokens.composite-line-height-needs-font-size"
|
||||
msgstr ""
|
||||
"पंक्ति की ऊँचाई फ़ॉन्ट आकार पर निर्भर करती है। हल किया गया मान प्राप्त करने के लिए फ़ॉन्ट "
|
||||
"आकार जोड़ें।"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs:581
|
||||
msgid "workspace.tokens.edit-token"
|
||||
msgstr "%s token संपादित करें"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs:1339
|
||||
msgid "workspace.tokens.font-size-value-enter"
|
||||
msgstr "फ़ॉन्ट आकार या {उपनाम}"
|
||||
|
||||
#: src/app/main/data/workspace/tokens/application.cljs:323
|
||||
msgid "workspace.tokens.font-variant-not-found"
|
||||
msgstr ""
|
||||
"फ़ॉन्ट वज़न/शैली सेट करते समय त्रुटि हुई। यह फ़ॉन्ट शैली वर्तमान फ़ॉन्ट में मौजूद नहीं है"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs:1328, src/app/main/ui/workspace/tokens/management/create/form.cljs:1343
|
||||
msgid "workspace.tokens.font-weight-value-enter"
|
||||
msgstr "फ़ॉन्ट वज़न (300, बोल्ड इटैलिक...) या {उपनाम}"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/import/modal.cljs:233
|
||||
msgid "workspace.tokens.import-button-prefix"
|
||||
msgstr "%s आयात करें"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/import/modal.cljs:273
|
||||
msgid "workspace.tokens.import-menu-folder-option"
|
||||
msgstr "फ़ोल्डर"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/import/modal.cljs:272
|
||||
msgid "workspace.tokens.import-menu-json-option"
|
||||
msgstr "एकल JSON फ़ाइल"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/import/modal.cljs:271
|
||||
msgid "workspace.tokens.import-menu-zip-option"
|
||||
msgstr "ज़िप फ़ाइल"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs:741
|
||||
msgid "workspace.tokens.individual-tokens"
|
||||
msgstr "व्यक्तिगत टोकन का प्रयोग करें"
|
||||
|
||||
#: src/app/main/data/workspace/tokens/errors.cljs:89
|
||||
msgid "workspace.tokens.invalid-font-weight-token-value"
|
||||
msgstr ""
|
||||
"अमान्य फ़ॉन्ट भार मान: संख्यात्मक मान (100-950) या मानक नाम (पतला, हल्का, नियमित, "
|
||||
"बोल्ड, आदि) का उपयोग करें, वैकल्पिक रूप से उसके बाद 'इटैलिक' लिखें"
|
||||
|
||||
#: src/app/main/data/workspace/tokens/errors.cljs:101
|
||||
msgid "workspace.tokens.invalid-shadow-type-token-value"
|
||||
msgstr ""
|
||||
"अमान्य छाया प्रकार: केवल 'innerShadow' या 'dropShadow' स्वीकार किए जाते हैं"
|
||||
|
||||
#: src/app/main/data/workspace/tokens/errors.cljs:81
|
||||
msgid "workspace.tokens.invalid-text-case-token-value"
|
||||
msgstr ""
|
||||
"अमान्य token मान: केवल कोई नहीं, अपरकेस, लोअरकेस या कैपिटलाइज़ स्वीकार किए जाते हैं"
|
||||
|
||||
#: src/app/main/data/workspace/tokens/errors.cljs:85
|
||||
msgid "workspace.tokens.invalid-text-decoration-token-value"
|
||||
msgstr ""
|
||||
"अमान्य token मान: केवल कोई नहीं, रेखांकित और स्ट्राइक-थ्रू स्वीकार किए जाते हैं"
|
||||
|
||||
#: src/app/main/data/workspace/tokens/errors.cljs:93
|
||||
msgid "workspace.tokens.invalid-token-value-typography"
|
||||
msgstr "अमान्य मान: एक संयुक्त टाइपोग्राफी token का संदर्भ होना चाहिए।"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs:1351
|
||||
msgid "workspace.tokens.letter-spacing-value-enter-composite"
|
||||
msgstr "अक्षर रिक्ति या {उपनाम}"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs:1347
|
||||
msgid "workspace.tokens.line-height-value-enter"
|
||||
msgstr "पंक्ति ऊँचाई (गुणक, पिक्सेल, %) या {उपनाम}"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/token_pill.cljs:123
|
||||
msgid "workspace.tokens.more-options"
|
||||
msgstr "विकल्प देखने के लिए राइट क्लिक करें"
|
||||
|
||||
#: src/app/main/data/workspace/tokens/errors.cljs:19
|
||||
msgid "workspace.tokens.no-token-files-found"
|
||||
msgstr "इस फ़ाइल में कोई टोकन, सेट या थीम नहीं मिला।"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs:775
|
||||
msgid "workspace.tokens.reference-composite"
|
||||
msgstr "token टाइपोग्राफी उपनाम दर्ज करें"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs:1084
|
||||
msgid "workspace.tokens.shadow-add-shadow"
|
||||
msgstr "छाया जोड़ें"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs:981, src/app/main/ui/workspace/tokens/management/create/form.cljs:982
|
||||
msgid "workspace.tokens.shadow-blur"
|
||||
msgstr "धुंधला"
|
||||
|
||||
#: src/app/main/data/workspace/tokens/errors.cljs:105
|
||||
msgid "workspace.tokens.shadow-blur-range"
|
||||
msgstr "छाया धुंधलापन 0 से अधिक या उसके बराबर होना चाहिए।"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs:987, src/app/main/ui/workspace/tokens/management/create/form.cljs:988
|
||||
msgid "workspace.tokens.shadow-color"
|
||||
msgstr "रंग"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs:990, src/app/main/ui/workspace/tokens/management/create/form.cljs:991
|
||||
msgid "workspace.tokens.shadow-inset"
|
||||
msgstr "अंतर्भूत"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs:1091
|
||||
msgid "workspace.tokens.shadow-remove-shadow"
|
||||
msgstr "छाया हटाएँ"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs:984, src/app/main/ui/workspace/tokens/management/create/form.cljs:985
|
||||
msgid "workspace.tokens.shadow-spread"
|
||||
msgstr "फैलाना"
|
||||
|
||||
#: src/app/main/data/workspace/tokens/errors.cljs:109
|
||||
msgid "workspace.tokens.shadow-spread-range"
|
||||
msgstr "छाया प्रसार 0 से अधिक या उसके बराबर होना चाहिए।"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs:1215
|
||||
msgid "workspace.tokens.shadow-title"
|
||||
msgstr "छायाएँ"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs:975, src/app/main/ui/workspace/tokens/management/create/form.cljs:976
|
||||
msgid "workspace.tokens.shadow-x"
|
||||
msgstr "X"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs:978, src/app/main/ui/workspace/tokens/management/create/form.cljs:979
|
||||
msgid "workspace.tokens.shadow-y"
|
||||
msgstr "Y"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs:1316, src/app/main/ui/workspace/tokens/management/create/form.cljs:1355
|
||||
msgid "workspace.tokens.text-case-value-enter"
|
||||
msgstr "कोई नहीं | अपरकेस | लोअरकेस | कैपिटलाइज़ या {उपनाम}"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs:1322, src/app/main/ui/workspace/tokens/management/create/form.cljs:1359
|
||||
msgid "workspace.tokens.text-decoration-value-enter"
|
||||
msgstr "कोई नहीं | रेखांकित | स्ट्राइक-थ्रू या {उपनाम}"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/themes/create_modal.cljs:52
|
||||
msgid "workspace.tokens.theme-name-already-exists"
|
||||
msgstr "इस नाम वाली थीम पहले से मौजूद है"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs:1277
|
||||
msgid "workspace.tokens.token-font-family-select"
|
||||
msgstr "फ़ॉन्ट परिवार चुनें"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs:1333
|
||||
msgid "workspace.tokens.token-font-family-value"
|
||||
msgstr "फॉन्ट परिवार"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs:1283, src/app/main/ui/workspace/tokens/management/create/form.cljs:1335
|
||||
msgid "workspace.tokens.token-font-family-value-enter"
|
||||
msgstr "फ़ॉन्ट परिवार या अल्पविराम (,) द्वारा अलग किए गए फ़ॉन्ट की सूची"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/border_radius.cljs:44, src/app/main/ui/workspace/tokens/management/create/form.cljs:70
|
||||
msgid "workspace.tokens.token-name-duplication-validation-error"
|
||||
msgstr "पथ पर एक token पहले से मौजूद है: %s"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/border_radius.cljs:42, src/app/main/ui/workspace/tokens/management/create/form.cljs:68
|
||||
msgid "workspace.tokens.token-name-length-validation-error"
|
||||
msgstr "नाम कम से कम 1 अक्षर का होना चाहिए"
|
||||
|
||||
#: src/app/main/data/workspace/tokens/import_export.cljs:47
|
||||
msgid "workspace.tokens.unknown-token-type-message"
|
||||
msgstr "आयात सफल रहा। कुछ टोकन शामिल नहीं किए गए।"
|
||||
|
||||
#: src/app/main/ui/workspace/tokens/management/create/form.cljs:745
|
||||
msgid "workspace.tokens.use-reference"
|
||||
msgstr "एक संदर्भ का प्रयोग करें"
|
||||
|
||||
#: src/app/main/data/workspace/tokens/errors.cljs:69
|
||||
msgid "workspace.tokens.value-with-percent"
|
||||
msgstr "अमान्य मान: % की अनुमति नहीं है।"
|
||||
|
||||
#, unused
|
||||
msgid "workspace.versions.locked-by-other"
|
||||
msgstr "यह संस्करण %s द्वारा लॉक किया गया है और इसे संशोधित नहीं किया जा सकता"
|
||||
|
||||
#, unused
|
||||
msgid "workspace.versions.locked-by-you"
|
||||
msgstr "यह संस्करण आपके द्वारा लॉक किया गया है"
|
||||
|
||||
#, unused
|
||||
msgid "workspace.versions.tooltip.locked-version"
|
||||
msgstr "लॉक किया गया संस्करण - केवल निर्माता ही इसे संशोधित कर सकता है"
|
||||
|
||||
@@ -541,7 +541,7 @@ msgstr ""
|
||||
#: src/app/main/ui/exports/files.cljs:164
|
||||
msgid "dashboard.export.options.all.message"
|
||||
msgstr ""
|
||||
"datoteke sa zajedničkim bibliotekama bit će uključene u izvoz, održavajući "
|
||||
"Datoteke sa zajedničkim bibliotekama bit će uključene u izvoz, održavajući "
|
||||
"njihovu poveznicu."
|
||||
|
||||
#: src/app/main/ui/exports/files.cljs:165
|
||||
|
||||
@@ -573,7 +573,7 @@ msgstr ""
|
||||
|
||||
#: src/app/main/ui/exports/files.cljs:164
|
||||
msgid "dashboard.export.options.all.message"
|
||||
msgstr "berkas dengan pustaka bersama akan dimasukkan dalam hasil ekspor."
|
||||
msgstr "Berkas dengan pustaka bersama akan dimasukkan dalam hasil ekspor."
|
||||
|
||||
#: src/app/main/ui/exports/files.cljs:165
|
||||
msgid "dashboard.export.options.all.title"
|
||||
|
||||
@@ -346,7 +346,7 @@ msgstr ""
|
||||
#: src/app/main/ui/exports/files.cljs:164
|
||||
msgid "dashboard.export.options.all.message"
|
||||
msgstr ""
|
||||
"failai su bendromis bibliotekomis bus įtraukti į eksportą, išlaikant jų "
|
||||
"Failai su bendromis bibliotekomis bus įtraukti į eksportą, išlaikant jų "
|
||||
"susiejimą."
|
||||
|
||||
#: src/app/main/ui/exports/files.cljs:165
|
||||
|
||||
@@ -584,7 +584,7 @@ msgstr ""
|
||||
#: src/app/main/ui/exports/files.cljs:164
|
||||
msgid "dashboard.export.options.all.message"
|
||||
msgstr ""
|
||||
"izguvē tiks iekļautas datnes ar koplietojamām bibliotēkām, saglabājot to "
|
||||
"Izguvē tiks iekļautas datnes ar koplietojamām bibliotēkām, saglabājot to "
|
||||
"sasaisti."
|
||||
|
||||
#: src/app/main/ui/exports/files.cljs:165
|
||||
|
||||
@@ -438,7 +438,7 @@ msgstr ""
|
||||
#: src/app/main/ui/exports/files.cljs:164
|
||||
msgid "dashboard.export.options.all.message"
|
||||
msgstr ""
|
||||
"fail dengan perpustakaan kongsi akan disertakan dalam eksport, mengekalkan "
|
||||
"Fail dengan perpustakaan kongsi akan disertakan dalam eksport, mengekalkan "
|
||||
"hubungannya."
|
||||
|
||||
#: src/app/main/ui/exports/files.cljs:165
|
||||
|
||||
@@ -372,7 +372,7 @@ msgstr ""
|
||||
#: src/app/main/ui/exports/files.cljs:164
|
||||
msgid "dashboard.export.options.all.message"
|
||||
msgstr ""
|
||||
"pliki z bibliotekami współdzielonymi zostaną uwzględnione w eksporcie, z "
|
||||
"Pliki z bibliotekami współdzielonymi zostaną uwzględnione w eksporcie, z "
|
||||
"zachowaniem ich powiązania."
|
||||
|
||||
#: src/app/main/ui/exports/files.cljs:165
|
||||
|
||||
@@ -581,7 +581,7 @@ msgstr ""
|
||||
#: src/app/main/ui/exports/files.cljs:164
|
||||
msgid "dashboard.export.options.all.message"
|
||||
msgstr ""
|
||||
"arquivos com bibliotecas compartilhadas serão incluídos na exportação, "
|
||||
"Arquivos com bibliotecas compartilhadas serão incluídos na exportação, "
|
||||
"mantendo seu vínculo."
|
||||
|
||||
#: src/app/main/ui/exports/files.cljs:165
|
||||
|
||||
@@ -555,7 +555,7 @@ msgstr ""
|
||||
#: src/app/main/ui/exports/files.cljs:164
|
||||
msgid "dashboard.export.options.all.message"
|
||||
msgstr ""
|
||||
"ficheiros com bibliotecas partilhadas serão incluídos na exportação, "
|
||||
"Ficheiros com bibliotecas partilhadas serão incluídos na exportação, "
|
||||
"mantendo as ligações."
|
||||
|
||||
#: src/app/main/ui/exports/files.cljs:165
|
||||
|
||||
@@ -590,7 +590,7 @@ msgstr ""
|
||||
#: src/app/main/ui/exports/files.cljs:164
|
||||
msgid "dashboard.export.options.all.message"
|
||||
msgstr ""
|
||||
"fișierele cu biblioteci partajate vor fi incluse în export, menținându-le "
|
||||
"Fișierele cu biblioteci partajate vor fi incluse în export, menținându-le "
|
||||
"legătura."
|
||||
|
||||
#: src/app/main/ui/exports/files.cljs:165
|
||||
|
||||
@@ -491,7 +491,7 @@ msgstr ""
|
||||
#: src/app/main/ui/exports/files.cljs:164
|
||||
msgid "dashboard.export.options.all.message"
|
||||
msgstr ""
|
||||
"датотеке са дељеним библиотекама ће бити укључене у извоз, одржавајући "
|
||||
"Датотеке са дељеним библиотекама ће бити укључене у извоз, одржавајући "
|
||||
"њихову повезаност."
|
||||
|
||||
#: src/app/main/ui/exports/files.cljs:165
|
||||
|
||||
@@ -582,7 +582,7 @@ msgstr ""
|
||||
#: src/app/main/ui/exports/files.cljs:164
|
||||
msgid "dashboard.export.options.all.message"
|
||||
msgstr ""
|
||||
"filer med delade bibliotek kommer att ingå i exporten, bibehåller deras "
|
||||
"Filer med delade bibliotek kommer att ingå i exporten, bibehåller deras "
|
||||
"koppling."
|
||||
|
||||
#: src/app/main/ui/exports/files.cljs:165
|
||||
|
||||
@@ -583,7 +583,7 @@ msgstr ""
|
||||
#: src/app/main/ui/exports/files.cljs:164
|
||||
msgid "dashboard.export.options.all.message"
|
||||
msgstr ""
|
||||
"paylaşılan kütüphanelere sahip dosyalar, bağlantılarını koruyarak dışarı "
|
||||
"Paylaşılan kütüphanelere sahip dosyalar, bağlantılarını koruyarak dışarı "
|
||||
"aktarmaya dahil edilecek."
|
||||
|
||||
#: src/app/main/ui/exports/files.cljs:165
|
||||
|
||||
@@ -577,7 +577,7 @@ msgstr ""
|
||||
#: src/app/main/ui/exports/files.cljs:164
|
||||
msgid "dashboard.export.options.all.message"
|
||||
msgstr ""
|
||||
"файли з спільними бібліотеками буде додано до експорту зі збереженням "
|
||||
"Файли з спільними бібліотеками буде додано до експорту зі збереженням "
|
||||
"зв'язків між ними."
|
||||
|
||||
#: src/app/main/ui/exports/files.cljs:165
|
||||
|
||||
@@ -1226,16 +1226,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@penpot/svgo@penpot/svgo#v3.1":
|
||||
"@penpot/svgo@penpot/svgo#v3.2":
|
||||
version: 4.0.0
|
||||
resolution: "@penpot/svgo@https://github.com/penpot/svgo.git#commit=a46262c12c0d967708395972c374eb2adead4180"
|
||||
resolution: "@penpot/svgo@https://github.com/penpot/svgo.git#commit=8c9b0e32e9cb5f106085260bd9375f3c91a5010b"
|
||||
dependencies:
|
||||
"@trysound/sax": "npm:0.2.0"
|
||||
css-select: "npm:^5.1.0"
|
||||
css-tree: "npm:^3.1.0"
|
||||
csso: "npm:^5.0.5"
|
||||
lodash: "npm:^4.17.21"
|
||||
checksum: 10c0/db5f81c99dec2765721d73b69bb30594869ebf657380dfb46709c79775b6c0dc1af678fe9fe51bbe2272a2c78d19c2694a12ec6578bcc41235fa4aff475c9416
|
||||
checksum: 10c0/d7af2801451b97f8ffb17664147c609456f5bcc786c6d03b222546125260c0f268e750748311d61598e31f66610b00038d2b969635b1a15e5694647e19c6b63a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -4311,7 +4311,7 @@ __metadata:
|
||||
"@penpot/hljs": "portal:./vendor/hljs"
|
||||
"@penpot/mousetrap": "portal:./vendor/mousetrap"
|
||||
"@penpot/plugins-runtime": "npm:1.3.2"
|
||||
"@penpot/svgo": "penpot/svgo#v3.1"
|
||||
"@penpot/svgo": "penpot/svgo#v3.2"
|
||||
"@penpot/text-editor": "portal:./text-editor"
|
||||
"@playwright/test": "npm:1.52.0"
|
||||
"@storybook/addon-docs": "npm:10.0.4"
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# CHANGELOG
|
||||
|
||||
|
||||
## 1.2.0-RC1
|
||||
|
||||
- Add the ability to add relations (with `addRelation` method)
|
||||
|
||||
|
||||
## 1.1.0
|
||||
|
||||
- Same as 1.1.0-RC2
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"name": "@penpot/library",
|
||||
"version": "1.1.0",
|
||||
"version": "1.2.0-RC1",
|
||||
"license": "MPL-2.0",
|
||||
"author": "Kaleidos INC",
|
||||
"packageManager": "yarn@4.11.0+sha512.4e54aeace9141df2f0177c266b05ec50dc044638157dae128c471ba65994ac802122d7ab35bcd9e81641228b7dcf24867d28e750e0bcae8a05277d600008ad54",
|
||||
"packageManager": "yarn@4.12.0+sha512.f45ab632439a67f8bc759bf32ead036a1f413287b9042726b7cc4818b7b49e14e9423ba49b18f9e06ea4941c1ad062385b1d8760a8d5091a1a31e5f6219afca8",
|
||||
"type": "module",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
30
library/playground/sample-relations.js
Normal file
30
library/playground/sample-relations.js
Normal file
@@ -0,0 +1,30 @@
|
||||
import * as penpot from "#self";
|
||||
import { writeFile, readFile } from "fs/promises";
|
||||
|
||||
(async function () {
|
||||
const context = penpot.createBuildContext();
|
||||
|
||||
{
|
||||
const file1 = context.addFile({ name: "Test File 1" });
|
||||
const file2 = context.addFile({ name: "Test File 1" });
|
||||
|
||||
context.addRelation(file1, file2);
|
||||
}
|
||||
|
||||
{
|
||||
let result = await penpot.exportAsBytes(context);
|
||||
await writeFile("sample-relations.zip", result);
|
||||
}
|
||||
})()
|
||||
.catch((cause) => {
|
||||
console.error(cause);
|
||||
|
||||
const innerCause = cause.cause;
|
||||
if (innerCause) {
|
||||
console.error("Inner cause:", innerCause);
|
||||
}
|
||||
process.exit(-1);
|
||||
})
|
||||
.finally(() => {
|
||||
process.exit(0);
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user