mirror of
https://github.com/penpot/penpot.git
synced 2025-07-04 07:37:15 +02:00
Merge remote-tracking branch 'origin/staging' into develop
This commit is contained in:
commit
8a81bc11e0
19 changed files with 201 additions and 118 deletions
|
@ -14,6 +14,7 @@
|
|||
[app.config :as cf]
|
||||
[app.db :as db]
|
||||
[app.db.sql :as sql]
|
||||
[app.features.components-v2 :as feat.compv2]
|
||||
[app.features.fdata :as fdata]
|
||||
[app.rpc :as-alias rpc]
|
||||
[app.rpc.commands.files :as files]
|
||||
|
@ -46,22 +47,26 @@
|
|||
[cfg {:keys [::rpc/profile-id project-id] :as params}]
|
||||
(db/tx-run! cfg (fn [{:keys [::db/conn] :as cfg}]
|
||||
(projects/check-edition-permissions! conn profile-id project-id)
|
||||
(let [team (teams/get-team conn
|
||||
:profile-id profile-id
|
||||
:project-id project-id)
|
||||
(let [team (teams/get-team conn :profile-id profile-id :project-id project-id)
|
||||
|
||||
;; When we create files, we only need to respect the team
|
||||
;; features, because some features can be enabled
|
||||
;; globally, but the team is still not migrated properly.
|
||||
features (-> (cfeat/get-team-enabled-features cf/flags team)
|
||||
(cfeat/check-client-features! (:features params)))
|
||||
input-features (:features params #{})
|
||||
|
||||
;; If the imported project doesn't contain v2 we need to remove it
|
||||
team-features
|
||||
(cond-> (cfeat/get-team-enabled-features cf/flags team)
|
||||
(not (contains? input-features "components/v2"))
|
||||
(disj "components/v2"))
|
||||
|
||||
|
||||
;; We also include all no migration features declared by
|
||||
;; client; that enables the ability to enable a runtime
|
||||
;; feature on frontend and make it permanent on file
|
||||
features (-> (:features params #{})
|
||||
features (-> input-features
|
||||
(set/intersection cfeat/no-migration-features)
|
||||
(set/union features))
|
||||
(set/union team-features))
|
||||
|
||||
params (-> params
|
||||
(assoc :profile-id profile-id)
|
||||
|
@ -100,7 +105,7 @@
|
|||
;; --- MUTATION COMMAND: persist-temp-file
|
||||
|
||||
(defn persist-temp-file
|
||||
[{:keys [::db/conn] :as cfg} {:keys [id] :as params}]
|
||||
[{:keys [::db/conn] :as cfg} {:keys [id ::rpc/profile-id] :as params}]
|
||||
(let [file (files/get-file cfg id
|
||||
:migrate? false
|
||||
:lock-for-update? true)]
|
||||
|
@ -109,6 +114,7 @@
|
|||
(ex/raise :type :validation
|
||||
:code :cant-persist-already-persisted-file))
|
||||
|
||||
|
||||
(let [changes (->> (db/cursor conn
|
||||
(sql/select :file-change {:file-id id}
|
||||
{:order-by [[:revn :asc]]})
|
||||
|
@ -133,6 +139,19 @@
|
|||
:revn 1
|
||||
:data (blob/encode (:data file))}
|
||||
{:id id})
|
||||
|
||||
(let [team (teams/get-team conn :profile-id profile-id :project-id (:project-id file))
|
||||
file-features (:features file)
|
||||
team-features (cfeat/get-team-enabled-features cf/flags team)]
|
||||
(when (and (contains? team-features "components/v2")
|
||||
(not (contains? file-features "components/v2")))
|
||||
;; Migrate components v2
|
||||
(feat.compv2/migrate-file! cfg
|
||||
(:id file)
|
||||
:max-procs 2
|
||||
:validate? true
|
||||
:throw-on-validate? true)))
|
||||
|
||||
nil)))
|
||||
|
||||
(def ^:private schema:persist-temp-file
|
||||
|
|
|
@ -524,7 +524,10 @@
|
|||
(dissoc :main-instance-y))
|
||||
|
||||
obj (-> (cts/setup-shape attrs)
|
||||
(check-name file root-type))]
|
||||
(check-name file root-type)
|
||||
;; Components need to have nil values for frame and parent
|
||||
(assoc :frame-id nil)
|
||||
(assoc :parent-id nil))]
|
||||
|
||||
(-> file
|
||||
(commit-change
|
||||
|
@ -537,19 +540,24 @@
|
|||
:shapes [obj]})
|
||||
|
||||
(assoc :last-id (:id obj))
|
||||
(update :parent-stack conjv (:id obj))
|
||||
(assoc :parent-stack [(:id obj)])
|
||||
(assoc :current-component-id (:id obj))
|
||||
(assoc :current-frame-id (when (= (:type obj) :frame)
|
||||
(:id obj)))))))
|
||||
(assoc :current-frame-id (if (= (:type obj) :frame) (:id obj) uuid/zero))))))
|
||||
|
||||
(defn finish-component
|
||||
[file]
|
||||
(let [component-id (:current-component-id file)
|
||||
component-data (ctkl/get-component (:data file) component-id)
|
||||
|
||||
component (lookup-shape file component-id)
|
||||
children (->> component :shapes (mapv #(lookup-shape file %)))
|
||||
|
||||
file
|
||||
(cond
|
||||
;; Components-v2 component we skip this step
|
||||
(and component-data (:main-instance-id component-data))
|
||||
file
|
||||
|
||||
(empty? children)
|
||||
(commit-change
|
||||
file
|
||||
|
|
|
@ -406,10 +406,9 @@
|
|||
height: $s-16;
|
||||
min-width: $s-16;
|
||||
min-height: $s-16;
|
||||
border-radius: $br-6;
|
||||
background-color: var(--input-checkbox-inactive-background-color);
|
||||
background-color: var(--input-checkbox-background-color-rest);
|
||||
border: $s-1 solid var(--input-checkbox-border-color-rest);
|
||||
border-radius: $br-4;
|
||||
box-shadow: inset 0 0 0px 2px rgb(255 255 255 / 20%);
|
||||
svg {
|
||||
width: $s-16;
|
||||
height: $s-16;
|
||||
|
@ -422,22 +421,25 @@
|
|||
&:focus {
|
||||
border-color: var(--input-checkbox-border-color-focus);
|
||||
}
|
||||
|
||||
&:global(.checked) {
|
||||
border-color: var(--input-checkbox-border-color-active);
|
||||
background-color: var(--input-checkbox-active-background-color);
|
||||
background-color: var(--input-checkbox-background-color-active);
|
||||
svg {
|
||||
@extend .button-icon-small;
|
||||
stroke: var(--input-checkbox-active-foreground-color);
|
||||
stroke: var(--input-checkbox-foreground-color-active);
|
||||
}
|
||||
}
|
||||
|
||||
&:global(.intermediate) {
|
||||
background-color: var(--input-checkbox-background-color-intermediate);
|
||||
border-color: var(--input-checkbox-border-color-active);
|
||||
border-color: var(--input-checkbox-border-color-intermediate);
|
||||
svg {
|
||||
@extend .button-icon-small;
|
||||
stroke: var(--input-details-color);
|
||||
stroke: var(--input-checkbox-foreground-color-intermediate);
|
||||
}
|
||||
}
|
||||
|
||||
&:global(.unchecked) {
|
||||
background-color: var(--input-checkbox-background-color-rest);
|
||||
border: $s-1 solid var(--input-checkbox-background-color-rest);
|
||||
|
@ -468,6 +470,13 @@
|
|||
border-color: var(--input-checkbox-border-color-hover);
|
||||
}
|
||||
}
|
||||
|
||||
&:focus,
|
||||
&:focus-within {
|
||||
span {
|
||||
border-color: var(--input-checkbox-border-color-focus);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -159,18 +159,22 @@
|
|||
--input-border-color-error: var(--error-color);
|
||||
--input-border-color-success: var(--color-accent-primary);
|
||||
--input-details-color: var(--color-background-primary);
|
||||
|
||||
--input-checkbox-background-color-rest: var(--color-background-quaternary);
|
||||
--input-checkbox-border-color-rest: var(--color-foreground-secondary);
|
||||
--input-checkbox-border-color-active: var(--color-background-quaternary);
|
||||
--input-checkbox-border-color-focus: var(--color-accent-primary);
|
||||
--input-checkbox-border-color: var(--color-background-secondary);
|
||||
--input-checkbox-border-color-hover: var(--color-accent-primary-muted);
|
||||
--input-checkbox-background-color-intermediate: var(--color-foreground-secondary);
|
||||
--input-checkbox-border-color-intermediate: var(--color-foreground-secondary);
|
||||
--input-checkbox-foreground-color-intermediate: var(--color-background-secondary);
|
||||
|
||||
// Checkbox color
|
||||
--input-checkbox-inactive-background-color: var(--color-foreground-secondary);
|
||||
--input-checkbox-inactive-foreground-color: var(--color-background-primary);
|
||||
--input-checkbox-active-background-color: var(--color-accent-primary);
|
||||
--input-checkbox-active-foreground-color: var(--color-background-primary);
|
||||
--input-checkbox-background-color-active: var(--color-accent-primary);
|
||||
--input-checkbox-foreground-color-active: var(--color-background-primary);
|
||||
--input-checkbox-text-foreground-color: var(--color-foreground-secondary);
|
||||
|
||||
--menu-background-color: var(--color-background-tertiary);
|
||||
|
|
|
@ -336,7 +336,7 @@
|
|||
;; used to render thumbnails on assets panel.
|
||||
(mf/defc component-svg
|
||||
{::mf/wrap [mf/memo #(mf/deferred % ts/idle-then-raf)]}
|
||||
[{:keys [objects root-shape show-grids? zoom] :or {zoom 1} :as props}]
|
||||
[{:keys [objects root-shape show-grids? zoom class] :or {zoom 1} :as props}]
|
||||
(when root-shape
|
||||
(let [root-shape-id (:id root-shape)
|
||||
include-metadata (mf/use-ctx export/include-metadata-ctx)
|
||||
|
@ -373,6 +373,7 @@
|
|||
:width (ust/format-precision width viewbox-decimal-precision)
|
||||
:height (ust/format-precision height viewbox-decimal-precision)
|
||||
:version "1.1"
|
||||
:class class
|
||||
:xmlns "http://www.w3.org/2000/svg"
|
||||
:xmlnsXlink "http://www.w3.org/1999/xlink"
|
||||
:xmlns:penpot (when include-metadata "https://penpot.app/xmlns")
|
||||
|
@ -388,7 +389,7 @@
|
|||
|
||||
(mf/defc component-svg-thumbnail
|
||||
{::mf/wrap [mf/memo #(mf/deferred % ts/idle-then-raf)]}
|
||||
[{:keys [thumbnail-uri on-error show-grids?
|
||||
[{:keys [thumbnail-uri on-error show-grids? class
|
||||
objects root-shape zoom] :or {zoom 1} :as props}]
|
||||
|
||||
(when root-shape
|
||||
|
@ -421,6 +422,7 @@
|
|||
:width (ust/format-precision width-zoom viewbox-decimal-precision)
|
||||
:height (ust/format-precision height-zoom viewbox-decimal-precision)
|
||||
:version "1.1"
|
||||
:class class
|
||||
:xmlns "http://www.w3.org/2000/svg"
|
||||
:xmlnsXlink "http://www.w3.org/1999/xlink"
|
||||
:fill "none"}
|
||||
|
@ -506,7 +508,7 @@
|
|||
(mf/deps objects)
|
||||
(fn [] (frame-wrapper-factory objects)))]
|
||||
|
||||
[:> "symbol" #js {:id (str root-id)
|
||||
[:> "symbol" #js {:id (str (:id component))
|
||||
:viewBox vbox
|
||||
"penpot:path" path
|
||||
"penpot:main-instance-id" main-instance-id
|
||||
|
|
|
@ -80,12 +80,13 @@
|
|||
(assoc :deleted? true))))))
|
||||
|
||||
(defn set-analyze-error
|
||||
[files uri]
|
||||
[files uri error]
|
||||
(->> files
|
||||
(mapv (fn [file]
|
||||
(cond-> file
|
||||
(= uri (:uri file))
|
||||
(assoc :status :analyze-error))))))
|
||||
(-> (assoc :status :analyze-error)
|
||||
(assoc :error error)))))))
|
||||
|
||||
(defn set-analyze-result [files uri type data]
|
||||
(let [existing-files? (into #{} (->> files (map :file-id) (filter some?)))
|
||||
|
@ -150,7 +151,6 @@
|
|||
|
||||
(mf/defc import-entry
|
||||
[{:keys [state file editing? can-be-deleted?]}]
|
||||
|
||||
(let [loading? (or (= :analyzing (:status file))
|
||||
(= :importing (:status file)))
|
||||
analyze-error? (= :analyze-error (:status file))
|
||||
|
@ -226,7 +226,9 @@
|
|||
(cond
|
||||
analyze-error?
|
||||
[:div {:class (stl/css :error-message)}
|
||||
(tr "dashboard.import.analyze-error")]
|
||||
(if (some? (:error file))
|
||||
(tr (:error file))
|
||||
(tr "dashboard.import.analyze-error"))]
|
||||
|
||||
import-error?
|
||||
[:div {:class (stl/css :error-message)}
|
||||
|
@ -260,13 +262,14 @@
|
|||
(fn [files]
|
||||
(->> (uw/ask-many!
|
||||
{:cmd :analyze-import
|
||||
:files files})
|
||||
:files files
|
||||
:features @features/features-ref})
|
||||
(rx/mapcat #(rx/delay emit-delay (rx/of %)))
|
||||
(rx/filter some?)
|
||||
(rx/subs!
|
||||
(fn [{:keys [uri data error type] :as msg}]
|
||||
(if (some? error)
|
||||
(swap! state update :files set-analyze-error uri)
|
||||
(swap! state update :files set-analyze-error uri error)
|
||||
(swap! state update :files set-analyze-result uri type data)))))))
|
||||
|
||||
import-files
|
||||
|
|
|
@ -240,17 +240,21 @@
|
|||
(tr "common.share-link.permissions-pages")]
|
||||
[:div {:class (stl/css :items)}
|
||||
(if (= 1 (count pages))
|
||||
|
||||
[:div {:class (stl/css :checkbox-wrapper)}
|
||||
|
||||
[:label {:for (str "page-" current-page-id)
|
||||
:class (stl/css-case :global/checked true)}
|
||||
|
||||
[:span {:class (stl/css :checked)}
|
||||
i/status-tick-refactor]
|
||||
|
||||
(:name current-page)]
|
||||
|
||||
[:input {:type "checkbox"
|
||||
:id (dm/str "page-" current-page-id)
|
||||
:data-page-id (dm/str current-page-id)
|
||||
:on-change on-mark-checked-page
|
||||
:checked true}]
|
||||
[:label {:for (str "page-" current-page-id)} (:name current-page)]
|
||||
[:span {:class (stl/css-case :checkobox-tick true
|
||||
:global/checked true)}
|
||||
i/status-tick-refactor]
|
||||
[:span (str " " (tr "common.share-link.current-tag"))]]
|
||||
|
||||
[:*
|
||||
|
|
|
@ -187,4 +187,12 @@
|
|||
@extend .input-checkbox;
|
||||
height: $s-32;
|
||||
padding: 0;
|
||||
span.checked {
|
||||
background-color: var(--input-checkbox-background-color-active);
|
||||
border: $s-1 solid var(--input-checkbox-background-color-active);
|
||||
svg {
|
||||
@extend .button-icon-small;
|
||||
stroke: var(--input-checkbox-foreground-color-active);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -281,7 +281,7 @@
|
|||
(mf/defc component-item-thumbnail
|
||||
"Component that renders the thumbnail image or the original SVG."
|
||||
{::mf/wrap-props false}
|
||||
[{:keys [file-id root-shape component container]}]
|
||||
[{:keys [file-id root-shape component container class]}]
|
||||
(let [retry (mf/use-state 0)
|
||||
thumbnail-uri (get-component-thumbnail-uri file-id component)
|
||||
handle-error
|
||||
|
@ -294,6 +294,7 @@
|
|||
(if (some? thumbnail-uri)
|
||||
[:& component-svg-thumbnail
|
||||
{:thumbnail-uri thumbnail-uri
|
||||
:class class
|
||||
:on-error handle-error
|
||||
:root-shape root-shape
|
||||
:objects (:objects container)
|
||||
|
@ -301,6 +302,7 @@
|
|||
|
||||
[:& component-svg
|
||||
{:root-shape root-shape
|
||||
:class class
|
||||
:objects (:objects container)
|
||||
:show-grids? true}])))
|
||||
|
||||
|
|
|
@ -179,7 +179,8 @@
|
|||
|
||||
(when visible?
|
||||
[:& cmm/component-item-thumbnail {:file-id file-id
|
||||
:class (stl/css :thumbnail)
|
||||
:class (stl/css-case :thumbnail true
|
||||
:asset-list-thumbnail (not listing-thumbs?))
|
||||
:root-shape root-shape
|
||||
:component component
|
||||
:container container}])])]))
|
||||
|
|
|
@ -26,14 +26,6 @@
|
|||
background-color: var(--assets-component-background-color);
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
img {
|
||||
height: auto;
|
||||
width: auto;
|
||||
max-height: 100%;
|
||||
max-width: 100%;
|
||||
pointer-events: none;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.cell-name {
|
||||
@include titleTipography;
|
||||
|
@ -84,6 +76,8 @@
|
|||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
pointer-events: none;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.grid-placeholder {
|
||||
|
@ -96,10 +90,13 @@
|
|||
.asset-enum {
|
||||
margin: 0 $s-12;
|
||||
}
|
||||
|
||||
.enum-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
align-items: center;
|
||||
column-gap: $s-8;
|
||||
height: $s-36;
|
||||
margin-bottom: $s-4;
|
||||
padding: $s-2;
|
||||
|
@ -107,55 +104,6 @@
|
|||
background-color: var(--assets-item-background-color);
|
||||
cursor: pointer;
|
||||
|
||||
svg,
|
||||
img {
|
||||
@include flexCenter;
|
||||
flex-shrink: 0;
|
||||
padding: $s-2;
|
||||
height: $s-32;
|
||||
width: $s-32;
|
||||
border-radius: $br-6;
|
||||
background-color: var(--color-foreground-secondary);
|
||||
}
|
||||
|
||||
.item-name {
|
||||
@include titleTipography;
|
||||
@include textEllipsis;
|
||||
padding-left: $s-8;
|
||||
color: var(--assets-item-name-foreground-color);
|
||||
&.editing {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: $s-32;
|
||||
border: $s-1 solid var(--input-border-color-focus);
|
||||
border-radius: $br-8;
|
||||
background-color: var(--input-background-color);
|
||||
input {
|
||||
@include textEllipsis;
|
||||
@include titleTipography;
|
||||
@include removeInputStyle;
|
||||
flex-grow: 1;
|
||||
height: $s-28;
|
||||
max-width: calc(var(--parent-size) - (var(--depth) * var(--layer-indentation-size)));
|
||||
padding-left: $s-6;
|
||||
margin: 0;
|
||||
border-radius: $br-8;
|
||||
color: var(--input-foreground-color);
|
||||
}
|
||||
span {
|
||||
@include flexCenter;
|
||||
height: $s-28;
|
||||
background-color: transparent;
|
||||
border-radius: $br-8;
|
||||
svg {
|
||||
@extend .button-icon-small;
|
||||
stroke: var(--input-foreground-color);
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: var(--assets-item-background-color-hover);
|
||||
.item-name {
|
||||
|
@ -176,6 +124,45 @@
|
|||
}
|
||||
}
|
||||
|
||||
.item-name {
|
||||
@include titleTipography;
|
||||
@include textEllipsis;
|
||||
order: 2;
|
||||
color: var(--assets-item-name-foreground-color);
|
||||
input {
|
||||
@include textEllipsis;
|
||||
@include titleTipography;
|
||||
@include removeInputStyle;
|
||||
height: $s-32;
|
||||
padding: $s-4;
|
||||
}
|
||||
span {
|
||||
display: flex;
|
||||
place-items: center;
|
||||
padding-inline-end: $s-4;
|
||||
}
|
||||
|
||||
&.editing {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
align-items: center;
|
||||
column-gap: $s-8;
|
||||
border: $s-1 solid var(--input-border-color-focus);
|
||||
border-radius: $br-8;
|
||||
background-color: var(--input-background-color);
|
||||
}
|
||||
}
|
||||
|
||||
.asset-list-thumbnail {
|
||||
@include flexCenter;
|
||||
flex-shrink: 0;
|
||||
padding: $s-2;
|
||||
height: $s-32;
|
||||
width: $s-32;
|
||||
border-radius: $br-6;
|
||||
background-color: var(--assets-component-background-color);
|
||||
}
|
||||
|
||||
.grid-placeholder {
|
||||
height: $s-2;
|
||||
width: 100%;
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
}
|
||||
|
||||
.path {
|
||||
@include textEllipsis;
|
||||
max-width: 90%;
|
||||
margin-left: $s-2;
|
||||
text-transform: initial;
|
||||
color: var(--title-foreground-color-hover);
|
||||
|
|
|
@ -47,6 +47,8 @@
|
|||
.component-name {
|
||||
@include titleTipography;
|
||||
@include textEllipsis;
|
||||
direction: rtl;
|
||||
text-align: left;
|
||||
width: 70%;
|
||||
flex-grow: 2;
|
||||
margin-left: $s-8;
|
||||
|
@ -55,6 +57,9 @@
|
|||
.component-parent-name {
|
||||
@include titleTipography;
|
||||
@include textEllipsis;
|
||||
direction: rtl;
|
||||
text-align: left;
|
||||
max-width: 95%;
|
||||
padding-left: $s-36;
|
||||
color: var(--title-foreground-color);
|
||||
}
|
||||
|
@ -224,6 +229,7 @@
|
|||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: $s-4;
|
||||
padding-right: $s-8;
|
||||
font-size: $s-12;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
|
|
|
@ -147,7 +147,7 @@
|
|||
border-radius: $br-6;
|
||||
background-color: var(--input-checkbox-inactive-background-color);
|
||||
&.checked {
|
||||
background-color: var(--input-checkbox-active-background-color);
|
||||
background-color: var(--input-checkbox-background-color-active);
|
||||
svg {
|
||||
@extend .button-icon-small;
|
||||
stroke: var(--input-details-color);
|
||||
|
|
|
@ -654,7 +654,8 @@
|
|||
[:span {:class (stl/css :interaction-name)} (tr "workspace.options.interaction-duration")]
|
||||
[:div {:class (stl/css :input-element-wrapper)
|
||||
:title (tr "workspace.options.interaction-ms")}
|
||||
[:span.after (tr "workspace.options.interaction-ms")]
|
||||
[:span {:class (stl/css :after)}
|
||||
(tr "workspace.options.interaction-ms")]
|
||||
[:> numeric-input* {:ref ext-duration-ref
|
||||
:on-change change-duration
|
||||
:value (-> interaction :animation :duration)
|
||||
|
@ -719,9 +720,9 @@
|
|||
[:button {:class (stl/css :add-interaction-btn)
|
||||
:on-click add-interaction}
|
||||
i/add-refactor]]])
|
||||
[:div {:class (stl/css :help-content)}
|
||||
|
||||
(when (= (count interactions) 0)
|
||||
[:*
|
||||
[:div {:class (stl/css :help-content)}
|
||||
(when (and shape (not (cfh/unframed-shape? shape)))
|
||||
[:div {:class (stl/css :help-group)}
|
||||
[:div {:class (stl/css :interactions-help-icon)} i/add-refactor]
|
||||
|
@ -734,7 +735,7 @@
|
|||
[:div {:class (stl/css :help-group)}
|
||||
[:div {:class (stl/css :interactions-help-icon)} i/play-refactor]
|
||||
[:div {:class (stl/css :interactions-help)}
|
||||
(tr "workspace.options.use-play-button")]]])]
|
||||
(tr "workspace.options.use-play-button")]]])
|
||||
[:div {:class (stl/css :groups)}
|
||||
(for [[index interaction] (d/enumerate interactions)]
|
||||
[:& interaction-entry {:key (dm/str (:id shape) "-" index)
|
||||
|
|
|
@ -54,6 +54,11 @@
|
|||
}
|
||||
}
|
||||
|
||||
.after {
|
||||
@include titleTipography;
|
||||
margin-top: $s-1;
|
||||
}
|
||||
|
||||
.interactions-help {
|
||||
@include titleTipography;
|
||||
text-align: center;
|
||||
|
|
|
@ -137,7 +137,11 @@
|
|||
:is-shared (:shared context)
|
||||
:project-id (:project-id context)
|
||||
:create-page false
|
||||
:features features})))
|
||||
|
||||
;; If the features object exists send that. Otherwise we remove the components/v2 because
|
||||
;; if the features attribute doesn't exist is a version < 2.0. The other features will
|
||||
;; be kept so the shapes are created full featured
|
||||
:features (d/nilv (:features context) (disj features "components/v2"))})))
|
||||
|
||||
(defn link-file-libraries
|
||||
"Create a new file on the back-end"
|
||||
|
@ -154,7 +158,8 @@
|
|||
[context file]
|
||||
(let [file-id (:id file)
|
||||
session-id (uuid/next)
|
||||
batches (->> (fb/generate-changes file)
|
||||
changes (fb/generate-changes file)
|
||||
batches (->> changes
|
||||
(partition change-batch-size change-batch-size nil)
|
||||
(mapv vec))
|
||||
|
||||
|
@ -538,7 +543,9 @@
|
|||
(rx/merge-map (comp d/kebab-keys parser/string->uuid))
|
||||
(rx/mapcat
|
||||
(fn [[id media]]
|
||||
(let [media (assoc media :id (resolve id))]
|
||||
(let [media (-> media
|
||||
(assoc :id (resolve id))
|
||||
(update :name str))]
|
||||
(->> (get-file context :media id media)
|
||||
(rx/map (fn [blob]
|
||||
(let [content (.slice blob 0 (.-size blob) (:mtype media))]
|
||||
|
@ -625,7 +632,7 @@
|
|||
"other")))
|
||||
|
||||
(defmethod impl/handler :analyze-import
|
||||
[{:keys [files]}]
|
||||
[{:keys [files features]}]
|
||||
|
||||
(->> (rx/from files)
|
||||
(rx/merge-map
|
||||
|
@ -646,7 +653,16 @@
|
|||
(rx/merge-map #(zip/loadAsync (:body %)))
|
||||
(rx/merge-map #(get-file {:zip %} :manifest))
|
||||
(rx/map (comp d/kebab-keys parser/string->uuid))
|
||||
(rx/map #(hash-map :uri (:uri file) :data % :type "application/zip")))
|
||||
(rx/map
|
||||
(fn [data]
|
||||
;; Checks if the file is exported with components v2 and the current team only
|
||||
;; supports components v1
|
||||
(let [has-file-v2?
|
||||
(->> (:files data)
|
||||
(d/seek (fn [[_ file]] (contains? (set (:features file)) "components/v2"))))]
|
||||
(if (and has-file-v2? (not (contains? features "components/v2")))
|
||||
{:uri (:uri file) :error "dashboard.import.analyze-error.components-v2"}
|
||||
(hash-map :uri (:uri file) :data data :type "application/zip"))))))
|
||||
(->> st
|
||||
(rx/filter (fn [data] (= "application/octet-stream" (:type data))))
|
||||
(rx/map (fn [_]
|
||||
|
|
|
@ -534,6 +534,9 @@ msgstr "Import Penpot files"
|
|||
msgid "dashboard.import.analyze-error"
|
||||
msgstr "Oops! We couldn't import this file"
|
||||
|
||||
msgid "dashboard.import.analyze-error.components-v2"
|
||||
msgstr "File with components v2 activated but this team doesn't support it yet."
|
||||
|
||||
msgid "dashboard.import.import-error"
|
||||
msgstr "There was a problem importing the file. The file wasn't imported."
|
||||
|
||||
|
|
|
@ -542,6 +542,9 @@ msgstr "Importar archivos Penpot"
|
|||
msgid "dashboard.import.analyze-error"
|
||||
msgstr "¡Vaya! No hemos podido importar el fichero"
|
||||
|
||||
msgid "dashboard.import.analyze-error.components-v2"
|
||||
msgstr "Fichero exportado con componentes-v2 pero el equipo actual no lo soporta aún."
|
||||
|
||||
msgid "dashboard.import.import-error"
|
||||
msgstr "Hubo un problema importando el fichero. No ha podido ser importado."
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue