mirror of
https://github.com/penpot/penpot.git
synced 2025-02-12 18:18:24 -05:00
🎉 Create reusable components
This commit is contained in:
parent
8396357f36
commit
5e585201d3
17 changed files with 515 additions and 168 deletions
|
@ -356,6 +356,12 @@
|
|||
(defmethod change-spec :del-media [_]
|
||||
(s/keys :req-un [::id]))
|
||||
|
||||
(defmethod change-spec :add-component [_]
|
||||
(s/keys :req-un [::id ::name ::new-shapes]))
|
||||
|
||||
(defmethod change-spec :del-component [_]
|
||||
(s/keys :req-un [::id]))
|
||||
|
||||
(s/def ::change (s/multi-spec change-spec :type))
|
||||
(s/def ::changes (s/coll-of ::change))
|
||||
|
||||
|
@ -473,6 +479,18 @@
|
|||
:points []
|
||||
:segments [])))
|
||||
|
||||
(defn make-minimal-group
|
||||
[frame-id selection-rect group-name]
|
||||
{:id (uuid/next)
|
||||
:type :group
|
||||
:name group-name
|
||||
:shapes []
|
||||
:frame-id frame-id
|
||||
:x (:x selection-rect)
|
||||
:y (:y selection-rect)
|
||||
:width (:width selection-rect)
|
||||
:height (:height selection-rect)})
|
||||
|
||||
(defn make-file-data
|
||||
([] (make-file-data (uuid/next)))
|
||||
([id]
|
||||
|
@ -745,6 +763,17 @@
|
|||
[data {:keys [id]}]
|
||||
(update data :media dissoc id))
|
||||
|
||||
(defmethod process-change :add-component
|
||||
[data {:keys [id name new-shapes]}]
|
||||
(assoc-in data [:components id]
|
||||
{:id id
|
||||
:name name
|
||||
:objects (d/index-by :id new-shapes)}))
|
||||
|
||||
(defmethod process-change :del-component
|
||||
[data {:keys [id]}]
|
||||
(d/dissoc-in data [:components id]))
|
||||
|
||||
(defmethod process-operation :set
|
||||
[shape op]
|
||||
(let [attr (:attr op)
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
(defn get-children
|
||||
"Retrieve all children ids recursively for a given object"
|
||||
[id objects]
|
||||
(let [shapes (get-in objects [id :shapes])]
|
||||
(let [shapes (vec (get-in objects [id :shapes]))]
|
||||
(if shapes
|
||||
(d/concat shapes (mapcat #(get-children % objects) shapes))
|
||||
[])))
|
||||
|
|
|
@ -52,4 +52,3 @@
|
|||
;; (assoc obj :parent-id parent-id)))
|
||||
;; objects)))))
|
||||
|
||||
|
||||
|
|
3
frontend/resources/images/icons/component.svg
Normal file
3
frontend/resources/images/icons/component.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">
|
||||
<path d="M385 15l112 222a30 30 0 010 27L385 486a23 23 0 01-22 14H137c-5 1-9-1-13-3-4-3-7-6-9-11L3 264a30 30 0 010-27L115 15c2-4 5-8 9-10 4-3 8-4 13-4h226c5 0 9 1 13 4 4 2 7 6 9 10zM152 445h196l98-194-98-195H152L54 251zm98-139c28 0 50-25 50-55 0-31-22-55-50-55s-50 24-50 55c0 30 22 55 50 55z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 366 B |
|
@ -288,7 +288,7 @@
|
|||
}
|
||||
},
|
||||
"dashboard.grid.add-shared" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/header.cljs:146", "src/app/main/ui/dashboard/grid.cljs:166" ],
|
||||
"used-in" : [ "src/app/main/ui/dashboard/grid.cljs:166", "src/app/main/ui/workspace/header.cljs:146" ],
|
||||
"translations" : {
|
||||
"en" : "Add as Shared Library",
|
||||
"fr" : "",
|
||||
|
@ -297,7 +297,7 @@
|
|||
}
|
||||
},
|
||||
"dashboard.grid.add-shared-accept" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/header.cljs:69", "src/app/main/ui/dashboard/grid.cljs:95" ],
|
||||
"used-in" : [ "src/app/main/ui/dashboard/grid.cljs:95", "src/app/main/ui/workspace/header.cljs:69" ],
|
||||
"translations" : {
|
||||
"en" : "Add as Shared Library",
|
||||
"fr" : "",
|
||||
|
@ -306,7 +306,7 @@
|
|||
}
|
||||
},
|
||||
"dashboard.grid.add-shared-hint" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/header.cljs:68", "src/app/main/ui/dashboard/grid.cljs:94" ],
|
||||
"used-in" : [ "src/app/main/ui/dashboard/grid.cljs:94", "src/app/main/ui/workspace/header.cljs:68" ],
|
||||
"translations" : {
|
||||
"en" : "Once added as Shared Library, the assets of this file library will be available to be used among the rest of your files.",
|
||||
"fr" : "",
|
||||
|
@ -315,7 +315,7 @@
|
|||
}
|
||||
},
|
||||
"dashboard.grid.add-shared-message" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/header.cljs:67", "src/app/main/ui/dashboard/grid.cljs:93" ],
|
||||
"used-in" : [ "src/app/main/ui/dashboard/grid.cljs:93", "src/app/main/ui/workspace/header.cljs:67" ],
|
||||
"translations" : {
|
||||
"en" : "Add “%s” as Shared Library",
|
||||
"fr" : "",
|
||||
|
@ -342,7 +342,7 @@
|
|||
}
|
||||
},
|
||||
"dashboard.grid.remove-shared" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/header.cljs:144", "src/app/main/ui/dashboard/grid.cljs:165" ],
|
||||
"used-in" : [ "src/app/main/ui/dashboard/grid.cljs:165", "src/app/main/ui/workspace/header.cljs:144" ],
|
||||
"translations" : {
|
||||
"en" : "Remove as Shared Library",
|
||||
"fr" : "",
|
||||
|
@ -351,7 +351,7 @@
|
|||
}
|
||||
},
|
||||
"dashboard.grid.remove-shared-accept" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/header.cljs:78", "src/app/main/ui/dashboard/grid.cljs:114" ],
|
||||
"used-in" : [ "src/app/main/ui/dashboard/grid.cljs:114", "src/app/main/ui/workspace/header.cljs:78" ],
|
||||
"translations" : {
|
||||
"en" : "Remove as Shared Library",
|
||||
"fr" : "",
|
||||
|
@ -360,7 +360,7 @@
|
|||
}
|
||||
},
|
||||
"dashboard.grid.remove-shared-hint" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/header.cljs:77", "src/app/main/ui/dashboard/grid.cljs:113" ],
|
||||
"used-in" : [ "src/app/main/ui/dashboard/grid.cljs:113", "src/app/main/ui/workspace/header.cljs:77" ],
|
||||
"translations" : {
|
||||
"en" : "Once removed as Shared Library, the File Library of this file will stop being available to be used among the rest of your files.",
|
||||
"fr" : "",
|
||||
|
@ -369,7 +369,7 @@
|
|||
}
|
||||
},
|
||||
"dashboard.grid.remove-shared-message" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/header.cljs:76", "src/app/main/ui/dashboard/grid.cljs:112" ],
|
||||
"used-in" : [ "src/app/main/ui/dashboard/grid.cljs:112", "src/app/main/ui/workspace/header.cljs:76" ],
|
||||
"translations" : {
|
||||
"en" : "Remove “%s” as Shared Library",
|
||||
"fr" : "",
|
||||
|
@ -621,6 +621,7 @@
|
|||
"unused" : true
|
||||
},
|
||||
"ds.button.save" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:66" ],
|
||||
"translations" : {
|
||||
"en" : "Save",
|
||||
"fr" : "Sauvegarder",
|
||||
|
@ -774,7 +775,7 @@
|
|||
}
|
||||
},
|
||||
"errors.media-type-mismatch" : {
|
||||
"used-in" : [ "src/app/main/data/media.cljs:62", "src/app/main/data/workspace/persistence.cljs:352" ],
|
||||
"used-in" : [ "src/app/main/data/workspace/persistence.cljs:352", "src/app/main/data/media.cljs:62" ],
|
||||
"translations" : {
|
||||
"en" : "Seems that the contents of the image does not match the file extension.",
|
||||
"fr" : "",
|
||||
|
@ -783,7 +784,7 @@
|
|||
}
|
||||
},
|
||||
"errors.media-type-not-allowed" : {
|
||||
"used-in" : [ "src/app/main/data/media.cljs:59", "src/app/main/data/workspace/persistence.cljs:349" ],
|
||||
"used-in" : [ "src/app/main/data/workspace/persistence.cljs:349", "src/app/main/data/media.cljs:59" ],
|
||||
"translations" : {
|
||||
"en" : "Seems that this is not a valid image.",
|
||||
"fr" : "",
|
||||
|
@ -828,7 +829,7 @@
|
|||
}
|
||||
},
|
||||
"errors.unexpected-error" : {
|
||||
"used-in" : [ "src/app/main/data/media.cljs:65", "src/app/main/ui/settings/change_email.cljs:51", "src/app/main/ui/auth/register.cljs:54", "src/app/main/ui/workspace/sidebar/options/exports.cljs:66" ],
|
||||
"used-in" : [ "src/app/main/data/media.cljs:65", "src/app/main/ui/settings/change_email.cljs:51", "src/app/main/ui/workspace/sidebar/options/exports.cljs:66", "src/app/main/ui/auth/register.cljs:54" ],
|
||||
"translations" : {
|
||||
"en" : "An unexpected error occurred.",
|
||||
"fr" : "Une erreur inattendue c'est produite",
|
||||
|
@ -873,7 +874,7 @@
|
|||
}
|
||||
},
|
||||
"media.loading" : {
|
||||
"used-in" : [ "src/app/main/data/media.cljs:44", "src/app/main/data/workspace/persistence.cljs:334" ],
|
||||
"used-in" : [ "src/app/main/data/workspace/persistence.cljs:334", "src/app/main/data/media.cljs:44" ],
|
||||
"translations" : {
|
||||
"en" : "Loading image...",
|
||||
"fr" : "Chargement de l'image...",
|
||||
|
@ -882,6 +883,7 @@
|
|||
}
|
||||
},
|
||||
"modal.create-color.new-color" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:59" ],
|
||||
"translations" : {
|
||||
"en" : "New Color",
|
||||
"fr" : "Nouvelle couleur",
|
||||
|
@ -1458,7 +1460,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.assets.assets" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:374" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:476" ],
|
||||
"translations" : {
|
||||
"en" : "Assets",
|
||||
"fr" : "",
|
||||
|
@ -1467,7 +1469,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.assets.box-filter-all" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:394" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:496" ],
|
||||
"translations" : {
|
||||
"en" : "All assets",
|
||||
"fr" : "",
|
||||
|
@ -1476,7 +1478,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.assets.box-filter-colors" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:396" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:498" ],
|
||||
"translations" : {
|
||||
"en" : "Colors",
|
||||
"fr" : "",
|
||||
|
@ -1485,7 +1487,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.assets.box-filter-graphics" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:395" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:497" ],
|
||||
"translations" : {
|
||||
"en" : "Graphics",
|
||||
"fr" : "",
|
||||
|
@ -1494,7 +1496,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.assets.colors" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:247" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:324" ],
|
||||
"translations" : {
|
||||
"en" : "Colors",
|
||||
"fr" : "",
|
||||
|
@ -1502,8 +1504,17 @@
|
|||
"es" : "Colores"
|
||||
}
|
||||
},
|
||||
"workspace.assets.components" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:106" ],
|
||||
"translations" : {
|
||||
"en" : "Components",
|
||||
"fr" : "",
|
||||
"ru" : "",
|
||||
"es" : "Componentes"
|
||||
}
|
||||
},
|
||||
"workspace.assets.delete" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:125", "src/app/main/ui/workspace/sidebar/assets.cljs:224" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:125", "src/app/main/ui/workspace/sidebar/assets.cljs:210", "src/app/main/ui/workspace/sidebar/assets.cljs:304" ],
|
||||
"translations" : {
|
||||
"en" : "Delete",
|
||||
"fr" : "",
|
||||
|
@ -1512,7 +1523,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.assets.edit" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:223" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:303" ],
|
||||
"translations" : {
|
||||
"en" : "Edit",
|
||||
"fr" : "",
|
||||
|
@ -1521,7 +1532,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.assets.file-library" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:309" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:401" ],
|
||||
"translations" : {
|
||||
"en" : "File library",
|
||||
"fr" : "",
|
||||
|
@ -1530,7 +1541,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.assets.graphics" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:99" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:184" ],
|
||||
"translations" : {
|
||||
"en" : "Graphics",
|
||||
"fr" : "",
|
||||
|
@ -1539,7 +1550,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.assets.libraries" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:377" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:479" ],
|
||||
"translations" : {
|
||||
"en" : "Libraries",
|
||||
"fr" : "",
|
||||
|
@ -1548,7 +1559,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.assets.not-found" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:339" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:440" ],
|
||||
"translations" : {
|
||||
"en" : "No assets found",
|
||||
"fr" : "",
|
||||
|
@ -1557,7 +1568,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.assets.rename" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:222" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:302" ],
|
||||
"translations" : {
|
||||
"en" : "Rename",
|
||||
"fr" : "",
|
||||
|
@ -1566,7 +1577,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.assets.search" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:381" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:483" ],
|
||||
"translations" : {
|
||||
"en" : "Search assets",
|
||||
"fr" : "",
|
||||
|
@ -1575,7 +1586,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.assets.shared" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:311" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:403" ],
|
||||
"translations" : {
|
||||
"en" : "SHARED",
|
||||
"fr" : "",
|
||||
|
|
|
@ -20,6 +20,8 @@ $color-warning: #FC8802;
|
|||
$color-danger: #E65244;
|
||||
$color-info: #59b9e2;
|
||||
$color-ocean: #4285f4;
|
||||
$color-component: #76B0B8;
|
||||
$color-component-highlight: #00E0FF;
|
||||
|
||||
// Gray scale
|
||||
$color-gray-10: #E3E3E3;
|
||||
|
|
|
@ -170,6 +170,21 @@
|
|||
grid-auto-rows: 7vh;
|
||||
column-gap: 0.5rem;
|
||||
row-gap: 0.5rem;
|
||||
|
||||
&.big {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-auto-rows: 10vh;
|
||||
|
||||
.grid-cell {
|
||||
background-color: transparent;
|
||||
border: 1px solid $color-gray-40;
|
||||
border-radius: 4px;
|
||||
|
||||
& svg {
|
||||
height: 10vh;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.grid-cell {
|
||||
|
|
|
@ -20,42 +20,42 @@
|
|||
margin-right: 8px;
|
||||
width: 13px;
|
||||
}
|
||||
|
||||
|
||||
&.group {
|
||||
&.open {
|
||||
.toggle-content {
|
||||
flex-shrink: 0;
|
||||
|
||||
|
||||
svg {
|
||||
transform: rotate(270deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&:hover {
|
||||
background-color: $color-primary;
|
||||
|
||||
|
||||
svg {
|
||||
fill: $color-gray-60 !important;
|
||||
}
|
||||
|
||||
|
||||
.element-icon,
|
||||
.element-actions {
|
||||
|
||||
|
||||
svg {
|
||||
fill: $color-gray-60;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.element-actions > * {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
|
||||
span {
|
||||
color: $color-gray-60;
|
||||
}
|
||||
|
||||
|
||||
.toggle-content {
|
||||
svg {
|
||||
fill: $color-gray-60;
|
||||
|
@ -64,13 +64,12 @@
|
|||
}
|
||||
|
||||
&.selected {
|
||||
|
||||
|
||||
svg {
|
||||
fill: $color-primary;
|
||||
}
|
||||
|
||||
|
||||
.element-icon {
|
||||
|
||||
svg {
|
||||
fill: $color-primary;
|
||||
}
|
||||
|
@ -79,10 +78,10 @@
|
|||
span {
|
||||
color: $color-primary;
|
||||
}
|
||||
|
||||
|
||||
&:hover {
|
||||
background-color: $color-primary;
|
||||
|
||||
|
||||
.element-icon,
|
||||
.element-actions {
|
||||
svg {
|
||||
|
@ -95,20 +94,55 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&.drag-top {
|
||||
border-top: 40px solid $color-gray-60 !important;
|
||||
}
|
||||
|
||||
|
||||
&.drag-bottom {
|
||||
border-bottom: 40px solid $color-gray-60 !important;
|
||||
}
|
||||
|
||||
|
||||
&.drag-inside {
|
||||
border: 2px solid $color-primary !important;
|
||||
}
|
||||
}
|
||||
|
||||
.element-list li.component {
|
||||
|
||||
.element-list-body {
|
||||
.element-name {
|
||||
color: $color-component;
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: $color-component;
|
||||
}
|
||||
|
||||
&.selected {
|
||||
.element-name {
|
||||
color: $color-component-highlight;
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: $color-component-highlight;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: $color-component-highlight;
|
||||
|
||||
.element-name {
|
||||
color: $color-gray-60;
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: $color-gray-60;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.element-icon {
|
||||
svg {
|
||||
fill: $color-gray-30;
|
||||
|
@ -132,7 +166,7 @@ span.element-name {
|
|||
white-space: nowrap;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
.element-actions {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
|
@ -149,13 +183,13 @@ span.element-name {
|
|||
> * {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
.toggle-element,
|
||||
.block-element {
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
||||
|
||||
&.selected {
|
||||
display: flex;
|
||||
|
||||
|
@ -177,17 +211,17 @@ span.element-name {
|
|||
.toggle-content {
|
||||
margin-left: auto;
|
||||
width: 12px;
|
||||
|
||||
|
||||
svg {
|
||||
fill: $color-gray-20;
|
||||
transform: rotate(90deg);
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
|
||||
&.inverse {
|
||||
svg { transform: rotate(270deg); }
|
||||
}
|
||||
|
||||
|
||||
&:hover {
|
||||
svg {
|
||||
fill: $color-gray-60;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
[app.config :as cfg]
|
||||
[app.main.constants :as c]
|
||||
[app.main.data.workspace.common :as dwc]
|
||||
[app.main.data.workspace.libraries :as dwl]
|
||||
[app.main.data.workspace.notifications :as dwn]
|
||||
[app.main.data.workspace.persistence :as dwp]
|
||||
[app.main.data.workspace.selection :as dws]
|
||||
|
@ -1266,70 +1267,19 @@
|
|||
;; GROUPS
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defn group-shape
|
||||
[id frame-id selected selection-rect]
|
||||
{:id id
|
||||
:type :group
|
||||
:name (name (gensym "Group-"))
|
||||
:shapes []
|
||||
:frame-id frame-id
|
||||
:x (:x selection-rect)
|
||||
:y (:y selection-rect)
|
||||
:width (:width selection-rect)
|
||||
:height (:height selection-rect)})
|
||||
|
||||
(def group-selected
|
||||
(ptk/reify ::group-selected
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [id (uuid/next)
|
||||
page-id (:current-page-id state)
|
||||
(let [page-id (:current-page-id state)
|
||||
objects (dwc/lookup-page-objects state page-id)
|
||||
selected (get-in state [:workspace-local :selected])
|
||||
items (->> selected
|
||||
(map #(get objects %))
|
||||
(filter #(not= :frame (:type %)))
|
||||
(map #(assoc % ::index (cph/position-on-parent (:id %) objects)))
|
||||
(sort-by ::index))]
|
||||
|
||||
(when (not-empty items)
|
||||
(let [selrect (geom/selection-rect items)
|
||||
frame-id (-> items first :frame-id)
|
||||
parent-id (-> items first :parent-id)
|
||||
group (-> (group-shape id frame-id selected selrect)
|
||||
(geom/setup selrect))
|
||||
|
||||
index (::index (first items))
|
||||
|
||||
rchanges [{:type :add-obj
|
||||
:id id
|
||||
:page-id page-id
|
||||
:frame-id frame-id
|
||||
:parent-id parent-id
|
||||
:obj group
|
||||
:index index}
|
||||
{:type :mov-objects
|
||||
:page-id page-id
|
||||
:parent-id id
|
||||
:shapes (->> items
|
||||
(map :id)
|
||||
(into #{})
|
||||
(vec))}]
|
||||
|
||||
uchanges
|
||||
(reduce (fn [res obj]
|
||||
(conj res {:type :mov-objects
|
||||
:page-id page-id
|
||||
:parent-id (:parent-id obj)
|
||||
:index (::index obj)
|
||||
:shapes [(:id obj)]}))
|
||||
[]
|
||||
items)
|
||||
|
||||
uchanges (conj uchanges {:type :del-obj :id id :page-id page-id})]
|
||||
|
||||
shapes (dws/shapes-for-grouping objects selected)]
|
||||
(when-not (empty? shapes)
|
||||
(let [[group rchanges uchanges]
|
||||
(dws/prepare-create-group page-id shapes "Group-" false)]
|
||||
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})
|
||||
(dws/select-shapes (d/ordered-set id)))))))))
|
||||
(dws/select-shapes (d/ordered-set (:id group))))))))))
|
||||
|
||||
(def ungroup-selected
|
||||
(ptk/reify ::ungroup-selected
|
||||
|
@ -1342,34 +1292,11 @@
|
|||
group (get objects group-id)]
|
||||
(when (and (= 1 (count selected))
|
||||
(= (:type group) :group))
|
||||
(let [shapes (:shapes group)
|
||||
parent-id (cph/get-parent group-id objects)
|
||||
parent (get objects parent-id)
|
||||
index-in-parent (->> (:shapes parent)
|
||||
(map-indexed vector)
|
||||
(filter #(#{group-id} (second %)))
|
||||
(ffirst))
|
||||
rchanges [{:type :mov-objects
|
||||
:page-id page-id
|
||||
:parent-id parent-id
|
||||
:shapes shapes
|
||||
:index index-in-parent}]
|
||||
uchanges [{:type :add-obj
|
||||
:page-id page-id
|
||||
:id group-id
|
||||
:frame-id (:frame-id group)
|
||||
:obj (assoc group :shapes [])}
|
||||
{:type :mov-objects
|
||||
:page-id page-id
|
||||
:parent-id group-id
|
||||
:shapes shapes}
|
||||
{:type :mov-objects
|
||||
:page-id page-id
|
||||
:parent-id parent-id
|
||||
:shapes [group-id]
|
||||
:index index-in-parent}]]
|
||||
(let [[rchanges uchanges]
|
||||
(dws/prepare-remove-group page-id group objects)]
|
||||
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true}))))))))
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Interactions
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -1512,6 +1439,7 @@
|
|||
"+" #(st/emit! (increase-zoom nil))
|
||||
"-" #(st/emit! (decrease-zoom nil))
|
||||
"ctrl+g" #(st/emit! group-selected)
|
||||
"ctrl+k" #(st/emit! dwl/add-component)
|
||||
"shift+g" #(st/emit! ungroup-selected)
|
||||
"shift+0" #(st/emit! reset-zoom)
|
||||
"shift+1" #(st/emit! zoom-to-fit-all)
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
[app.common.spec :as us]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.workspace.common :as dwc]
|
||||
[app.main.data.workspace.selection :as dws]
|
||||
[app.common.pages :as cp]
|
||||
[app.main.repo :as rp]
|
||||
[app.main.store :as st]
|
||||
|
@ -68,7 +69,7 @@
|
|||
(rx/of (dwc/commit-changes [rchg] [uchg] {:commit-local? true}))))))
|
||||
|
||||
(defn delete-color
|
||||
[{:keys [id] :as color}]
|
||||
[{:keys [id] :as params}]
|
||||
(us/assert ::us/uuid id)
|
||||
(ptk/reify ::delete-color
|
||||
ptk/WatchEvent
|
||||
|
@ -94,7 +95,7 @@
|
|||
|
||||
|
||||
(defn delete-media
|
||||
[{:keys [id] :as media}]
|
||||
[{:keys [id] :as params}]
|
||||
(us/assert ::us/uuid id)
|
||||
(ptk/reify ::delete-media
|
||||
ptk/WatchEvent
|
||||
|
@ -106,3 +107,118 @@
|
|||
:object prev}]
|
||||
(rx/of (dwc/commit-changes [rchg] [uchg] {:commit-local? true}))))))
|
||||
|
||||
(declare clone-shape)
|
||||
|
||||
(def add-component
|
||||
(ptk/reify ::add-component
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [page-id (:current-page-id state)
|
||||
objects (dwc/lookup-page-objects state page-id)
|
||||
selected (get-in state [:workspace-local :selected])
|
||||
shapes (dws/shapes-for-grouping objects selected)]
|
||||
(when-not (empty? shapes)
|
||||
(let [;; If the selected shape is a group, we can use it. If not,
|
||||
;; we need to create a group before creating the component.
|
||||
[group rchanges uchanges]
|
||||
(if (and (= (count shapes) 1)
|
||||
(= (:type (first shapes)) :group))
|
||||
[(first shapes) [] []]
|
||||
(dws/prepare-create-group page-id shapes "Component-" true))
|
||||
|
||||
[new-shape new-shapes updated-shapes]
|
||||
(clone-shape group nil objects)
|
||||
|
||||
rchanges (conj rchanges
|
||||
{:type :add-component
|
||||
:id (:id new-shape)
|
||||
:name (:name new-shape)
|
||||
:new-shapes new-shapes})
|
||||
|
||||
rchanges (into rchanges
|
||||
(map (fn [updated-shape]
|
||||
{:type :mod-obj
|
||||
:page-id page-id
|
||||
:id (:id updated-shape)
|
||||
:operations [{:type :set
|
||||
:attr :component-id
|
||||
:val (:component-id updated-shape)}]})
|
||||
updated-shapes))
|
||||
|
||||
uchanges (conj uchanges
|
||||
{:type :del-component
|
||||
:id (:id new-shape)})
|
||||
|
||||
uchanges (into uchanges
|
||||
(map (fn [updated-shape]
|
||||
{:type :mod-obj
|
||||
:page-id page-id
|
||||
:id (:id updated-shape)
|
||||
:operations [{:type :set
|
||||
:attr :component-id
|
||||
:val nil}]})
|
||||
updated-shapes))]
|
||||
|
||||
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})
|
||||
(dws/select-shapes (d/ordered-set (:id group))))))))))
|
||||
|
||||
(defn- clone-shape
|
||||
"Clone the shape and all children. Generate new ids and detach
|
||||
from parent and frame. Update the original shapes to have links
|
||||
to the new ones."
|
||||
[shape parent-id objects]
|
||||
(let [new-id (uuid/next)]
|
||||
(if (nil? (:shapes shape))
|
||||
|
||||
; TODO: unify this case with the empty child-ids case.
|
||||
(let [new-shape (assoc shape
|
||||
:id new-id
|
||||
:parent-id parent-id
|
||||
:frame-id nil)]
|
||||
[new-shape
|
||||
[new-shape]
|
||||
[(assoc shape :component-id (:id new-shape))]])
|
||||
|
||||
(loop [child-ids (seq (:shapes shape))
|
||||
new-children []
|
||||
updated-children []]
|
||||
|
||||
(if (empty? child-ids)
|
||||
(let [new-shape (assoc shape
|
||||
:id new-id
|
||||
:parent-id parent-id
|
||||
:frame-id nil
|
||||
:shapes (map :id new-children))]
|
||||
[new-shape
|
||||
(conj new-children new-shape)
|
||||
(conj updated-children
|
||||
(assoc shape :component-id (:id new-shape)))])
|
||||
|
||||
(let [child-id (first child-ids)
|
||||
child (get objects child-id)
|
||||
|
||||
[new-child new-child-shapes updated-child-shapes]
|
||||
(clone-shape child new-id objects)]
|
||||
|
||||
(recur
|
||||
(next child-ids)
|
||||
(into new-children new-child-shapes)
|
||||
(into updated-children updated-child-shapes))))))))
|
||||
|
||||
(defn delete-component
|
||||
[{:keys [id] :as params}]
|
||||
(ptk/reify ::delete-component
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [component (get-in state [:workspace-data :components id])
|
||||
|
||||
rchanges [{:type :del-component
|
||||
:id id}]
|
||||
|
||||
uchanges [{:type :add-component
|
||||
:id id
|
||||
:name (:name component)
|
||||
:new-shapes (:objects component)}]]
|
||||
|
||||
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true}))))))
|
||||
|
||||
|
|
|
@ -183,6 +183,86 @@
|
|||
(rx/of deselect-all (select-shape (:id selected))))))))
|
||||
|
||||
|
||||
;; --- Group shapes
|
||||
|
||||
(defn shapes-for-grouping
|
||||
[objects selected]
|
||||
(->> selected
|
||||
(map #(get objects %))
|
||||
(filter #(not= :frame (:type %)))
|
||||
(map #(assoc % ::index (cph/position-on-parent (:id %) objects)))
|
||||
(sort-by ::index)))
|
||||
|
||||
(defn- make-group
|
||||
[shapes prefix keep-name]
|
||||
(let [selrect (geom/selection-rect shapes)
|
||||
frame-id (-> shapes first :frame-id)
|
||||
parent-id (-> shapes first :parent-id)
|
||||
group-name (if (and keep-name (= (count shapes) 1))
|
||||
(:name (first shapes))
|
||||
(name (gensym prefix)))]
|
||||
(-> (cp/make-minimal-group frame-id selrect group-name)
|
||||
(geom/setup selrect)
|
||||
(assoc :shapes (map :id shapes)))))
|
||||
|
||||
(defn prepare-create-group
|
||||
[page-id shapes prefix keep-name]
|
||||
(let [group (make-group shapes prefix keep-name)
|
||||
rchanges [{:type :add-obj
|
||||
:id (:id group)
|
||||
:page-id page-id
|
||||
:frame-id (:frame-id (first shapes))
|
||||
:parent-id (:parent-id (first shapes))
|
||||
:obj group
|
||||
:index (::index (first shapes))}
|
||||
{:type :mov-objects
|
||||
:page-id page-id
|
||||
:parent-id (:id group)
|
||||
:shapes (map :id shapes)}]
|
||||
|
||||
uchanges (conj
|
||||
(map (fn [obj] {:type :mov-objects
|
||||
:page-id page-id
|
||||
:parent-id (:parent-id obj)
|
||||
:index (::index obj)
|
||||
:shapes [(:id obj)]})
|
||||
shapes)
|
||||
{:type :del-obj
|
||||
:id (:id group)
|
||||
:page-id page-id})]
|
||||
[group rchanges uchanges]))
|
||||
|
||||
(defn prepare-remove-group
|
||||
[page-id group objects]
|
||||
(let [shapes (:shapes group)
|
||||
parent-id (cph/get-parent (:id group) objects)
|
||||
parent (get objects parent-id)
|
||||
index-in-parent (->> (:shapes parent)
|
||||
(map-indexed vector)
|
||||
(filter #(#{(:id group)} (second %)))
|
||||
(ffirst))
|
||||
rchanges [{:type :mov-objects
|
||||
:page-id page-id
|
||||
:parent-id parent-id
|
||||
:shapes shapes
|
||||
:index index-in-parent}]
|
||||
uchanges [{:type :add-obj
|
||||
:page-id page-id
|
||||
:id (:id group)
|
||||
:frame-id (:frame-id group)
|
||||
:obj (assoc group :shapes [])}
|
||||
{:type :mov-objects
|
||||
:page-id page-id
|
||||
:parent-id (:id group)
|
||||
:shapes shapes}
|
||||
{:type :mov-objects
|
||||
:page-id page-id
|
||||
:parent-id parent-id
|
||||
:shapes [(:id group)]
|
||||
:index index-in-parent}]]
|
||||
[rchanges uchanges]))
|
||||
|
||||
|
||||
;; --- Duplicate Shapes
|
||||
(declare prepare-duplicate-change)
|
||||
(declare prepare-duplicate-frame-change)
|
||||
|
|
|
@ -156,3 +156,35 @@
|
|||
:xmlnsXlink "http://www.w3.org/1999/xlink"
|
||||
:xmlns "http://www.w3.org/2000/svg"}
|
||||
[:& wrapper {:shape frame :view-box vbox}]]))
|
||||
|
||||
;; TODO: unify with frame-svg?
|
||||
(mf/defc component-svg
|
||||
{::mf/wrap [mf/memo]}
|
||||
[{:keys [objects group zoom] :or {zoom 1} :as props}]
|
||||
(let [modifier (-> (gpt/point (:x group) (:y group))
|
||||
(gpt/negate)
|
||||
(gmt/translate-matrix))
|
||||
|
||||
group-id (:id group)
|
||||
|
||||
modifier-ids (concat [group-id] (cph/get-children group-id objects))
|
||||
update-fn #(assoc-in %1 [%2 :modifiers :displacement] modifier)
|
||||
objects (reduce update-fn objects modifier-ids)
|
||||
group (assoc-in group [:modifiers :displacement] modifier)
|
||||
|
||||
width (* (:width group) zoom)
|
||||
height (* (:height group) zoom)
|
||||
vbox (str "0 0 " (:width group 0)
|
||||
" " (:height group 0))
|
||||
wrapper (mf/use-memo
|
||||
(mf/deps objects)
|
||||
#(group-wrapper-factory objects))]
|
||||
|
||||
[:svg {:view-box vbox
|
||||
:width width
|
||||
:height height
|
||||
:version "1.1"
|
||||
:xmlnsXlink "http://www.w3.org/1999/xlink"
|
||||
:xmlns "http://www.w3.org/2000/svg"}
|
||||
[:& wrapper {:shape group :view-box vbox}]]))
|
||||
|
||||
|
|
|
@ -67,4 +67,4 @@
|
|||
|
||||
(defn ^:export dump-objects []
|
||||
(let [page-id (get @state :current-page-id)]
|
||||
(logjs "state" (get-in @state [:workspace-data page-id :objects]))))
|
||||
(logjs "state" (get-in @state [:workspace-data :pages-index page-id :objects]))))
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
(def chat (icon-xref :chat))
|
||||
(def circle (icon-xref :circle))
|
||||
(def close (icon-xref :close))
|
||||
(def component (icon-xref :component))
|
||||
(def copy (icon-xref :copy))
|
||||
(def curve (icon-xref :curve))
|
||||
(def download (icon-xref :download))
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
[app.main.ui.icons :as i]
|
||||
[app.util.dom :as dom]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.data.workspace.libraries :as dwl]
|
||||
[app.main.ui.hooks :refer [use-rxsub]]
|
||||
[app.main.ui.components.dropdown :refer [dropdown]]))
|
||||
|
||||
|
@ -59,7 +60,8 @@
|
|||
do-lock-shape #(st/emit! (dw/update-shape-flags id {:blocked true}))
|
||||
do-unlock-shape #(st/emit! (dw/update-shape-flags id {:blocked false}))
|
||||
do-create-group #(st/emit! dw/group-selected)
|
||||
do-remove-group #(st/emit! dw/ungroup-selected)]
|
||||
do-remove-group #(st/emit! dw/ungroup-selected)
|
||||
do-add-component #(st/emit! dwl/add-component)]
|
||||
[:*
|
||||
[:& menu-entry {:title "Copy"
|
||||
:shortcut "Ctrl + c"
|
||||
|
@ -101,13 +103,17 @@
|
|||
[:& menu-entry {:title "Hide"
|
||||
:on-click do-hide-shape}])
|
||||
|
||||
|
||||
|
||||
(if (:blocked shape)
|
||||
[:& menu-entry {:title "Unlock"
|
||||
:on-click do-unlock-shape}]
|
||||
[:& menu-entry {:title "Lock"
|
||||
:on-click do-lock-shape}])
|
||||
|
||||
[:& menu-separator]
|
||||
[:& menu-entry {:title "Create component"
|
||||
:shortcut "Ctrl + K"
|
||||
:on-click do-add-component}]
|
||||
|
||||
[:& menu-separator]
|
||||
[:& menu-entry {:title "Delete"
|
||||
:shortcut "Supr"
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
[app.common.geom.shapes :as geom]
|
||||
[app.common.media :as cm]
|
||||
[app.common.pages :as cp]
|
||||
[app.common.pages-helpers :as cph]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.config :as cfg]
|
||||
[app.main.data.workspace :as dw]
|
||||
|
@ -21,6 +22,7 @@
|
|||
[app.main.data.colors :as dc]
|
||||
[app.main.refs :as refs]
|
||||
[app.main.store :as st]
|
||||
[app.main.exports :as exports]
|
||||
[app.main.ui.components.context-menu :refer [context-menu]]
|
||||
[app.main.ui.components.file-uploader :refer [file-uploader]]
|
||||
[app.main.ui.components.tab-container :refer [tab-container tab-element]]
|
||||
|
@ -38,6 +40,62 @@
|
|||
[okulary.core :as l]
|
||||
[rumext.alpha :as mf]))
|
||||
|
||||
(mf/defc components-box
|
||||
[{:keys [file-id local? components] :as props}]
|
||||
(let [state (mf/use-state {:menu-open false
|
||||
:top nil
|
||||
:left nil
|
||||
:component-id nil})
|
||||
on-delete
|
||||
(mf/use-callback
|
||||
(mf/deps state)
|
||||
(fn []
|
||||
(let [params {:id (:component-id @state)}]
|
||||
(st/emit! (dwl/delete-component params)))))
|
||||
|
||||
on-context-menu
|
||||
(mf/use-callback
|
||||
(fn [component-id]
|
||||
(fn [event]
|
||||
(when local?
|
||||
(let [pos (dom/get-client-position event)
|
||||
top (:y pos)
|
||||
left (- (:x pos) 20)]
|
||||
(dom/prevent-default event)
|
||||
(swap! state assoc :menu-open true
|
||||
:top top
|
||||
:left left
|
||||
:component-id component-id))))))
|
||||
|
||||
on-drag-start
|
||||
(mf/use-callback
|
||||
(fn [path event]
|
||||
(dnd/set-data! event "text/uri-list" (cfg/resolve-media-path path))
|
||||
(dnd/set-allowed-effect! event "move")))]
|
||||
|
||||
[:div.asset-group
|
||||
[:div.group-title
|
||||
(tr "workspace.assets.components")
|
||||
[:span (str "\u00A0(") (count components) ")"]] ;; Unicode 00A0 is non-breaking space
|
||||
[:div.group-grid.big
|
||||
(for [component components]
|
||||
[:div.grid-cell {:key (:id component)
|
||||
:draggable true
|
||||
:on-context-menu (on-context-menu (:id component))
|
||||
:on-drag-start (partial on-drag-start (:path component))}
|
||||
[:& exports/component-svg {:group (get-in component [:objects (:id component)])
|
||||
:objects (:objects component)}]
|
||||
[:div.cell-name (:name component)]])
|
||||
|
||||
(when local?
|
||||
[:& context-menu
|
||||
{:selectable false
|
||||
:show (:menu-open @state)
|
||||
:on-close #(swap! state assoc :menu-open false)
|
||||
:top (:top @state)
|
||||
:left (:left @state)
|
||||
:options [[(tr "workspace.assets.delete") on-delete]]}])]]))
|
||||
|
||||
(mf/defc graphics-box
|
||||
[{:keys [file-id local? objects open? on-open on-close] :as props}]
|
||||
(let [input-ref (mf/use-ref nil)
|
||||
|
@ -126,7 +184,6 @@
|
|||
:left (:left @state)
|
||||
:options [[(tr "workspace.assets.delete") on-delete]]}])])]))
|
||||
|
||||
|
||||
(mf/defc color-item
|
||||
[{:keys [color local? locale file-id] :as props}]
|
||||
(let [rename? (= (:color-for-rename @refs/workspace-local) (:id color))
|
||||
|
@ -287,32 +344,45 @@
|
|||
(vals (get-in state [:workspace-libraries id :data :media])))))
|
||||
st/state =))
|
||||
|
||||
(defn file-components-ref
|
||||
[id]
|
||||
(l/derived (fn [state]
|
||||
(let [wfile (:workspace-file state)]
|
||||
(if (= (:id wfile) id)
|
||||
(vals (get-in wfile [:data :components]))
|
||||
(vals (get-in state [:workspace-libraries id :data :components])))))
|
||||
st/state =))
|
||||
|
||||
(defn apply-filters
|
||||
[coll filters]
|
||||
(filter (fn [item]
|
||||
(or (matches-search (:name item "!$!") (:term filters))
|
||||
(matches-search (:value item "!$!") (:term filters))))
|
||||
coll))
|
||||
(->> coll
|
||||
(filter (fn [item]
|
||||
(or (matches-search (:name item "!$!") (:term filters))
|
||||
(matches-search (:value item "!$!") (:term filters)))))
|
||||
(sort-by #(str/lower (:name %)))))
|
||||
|
||||
(mf/defc file-library
|
||||
[{:keys [file local? open? filters locale] :as props}]
|
||||
(let [open? (mf/use-state open?)
|
||||
shared? (:is-shared file)
|
||||
router (mf/deref refs/router)
|
||||
toggle-open #(swap! open? not)
|
||||
(let [open? (mf/use-state open?)
|
||||
shared? (:is-shared file)
|
||||
router (mf/deref refs/router)
|
||||
toggle-open #(swap! open? not)
|
||||
|
||||
toggles (mf/use-state #{:graphics :colors})
|
||||
|
||||
url (rt/resolve router :workspace
|
||||
{:project-id (:project-id file)
|
||||
:file-id (:id file)}
|
||||
{:page-id (get-in file [:data :pages 0])})
|
||||
url (rt/resolve router :workspace
|
||||
{:project-id (:project-id file)
|
||||
:file-id (:id file)}
|
||||
{:page-id (get-in file [:data :pages 0])})
|
||||
|
||||
colors-ref (mf/use-memo (mf/deps (:id file)) #(file-colors-ref (:id file)))
|
||||
colors (apply-filters (mf/deref colors-ref) filters)
|
||||
colors-ref (mf/use-memo (mf/deps (:id file)) #(file-colors-ref (:id file)))
|
||||
colors (apply-filters (mf/deref colors-ref) filters)
|
||||
|
||||
media-ref (mf/use-memo (mf/deps (:id file)) #(file-media-ref (:id file)))
|
||||
media (apply-filters (mf/deref media-ref) filters)]
|
||||
media-ref (mf/use-memo (mf/deps (:id file)) #(file-media-ref (:id file)))
|
||||
media (apply-filters (mf/deref media-ref) filters)
|
||||
|
||||
components-ref (mf/use-memo (mf/deps (:id file)) #(file-components-ref (:id file)))
|
||||
components (apply-filters (mf/deref components-ref) filters)]
|
||||
|
||||
[:div.tool-window
|
||||
[:div.tool-window-bar
|
||||
|
@ -332,15 +402,23 @@
|
|||
[:a {:href (str "#" url) :target "_blank"} i/chain]]])]
|
||||
|
||||
(when @open?
|
||||
(let [show-graphics? (and (or (= (:box filters) :all)
|
||||
(= (:box filters) :graphics))
|
||||
(or (> (count media) 0)
|
||||
(str/empty? (:term filters))))
|
||||
show-colors? (and (or (= (:box filters) :all)
|
||||
(= (:box filters) :colors))
|
||||
(or (> (count colors) 0)
|
||||
(str/empty? (:term filters))))]
|
||||
(let [show-components? (and (or (= (:box filters) :all)
|
||||
(= (:box filters) :components))
|
||||
(or (> (count components) 0)
|
||||
(str/empty? (:term filters))))
|
||||
show-graphics? (and (or (= (:box filters) :all)
|
||||
(= (:box filters) :graphics))
|
||||
(or (> (count media) 0)
|
||||
(str/empty? (:term filters))))
|
||||
show-colors? (and (or (= (:box filters) :all)
|
||||
(= (:box filters) :colors))
|
||||
(or (> (count colors) 0)
|
||||
(str/empty? (:term filters))))]
|
||||
[:div.tool-window-content
|
||||
(when show-components?
|
||||
[:& components-box {:file-id (:id file)
|
||||
:local? local?
|
||||
:components components}])
|
||||
(when show-graphics?
|
||||
[:& graphics-box {:file-id (:id file)
|
||||
:local? local?
|
||||
|
@ -357,10 +435,11 @@
|
|||
:on-open #(swap! toggles conj :colors)
|
||||
:on-close #(swap! toggles disj :colors)}])
|
||||
|
||||
(when (and (not show-graphics?) (not show-colors?))
|
||||
(when (and (not show-components?) (not show-graphics?) (not show-colors?))
|
||||
[:div.asset-group
|
||||
[:div.group-title (t locale "workspace.assets.not-found")]])]))]))
|
||||
|
||||
|
||||
(mf/defc assets-toolbox
|
||||
[{:keys [team-id file] :as props}]
|
||||
(let [libraries (mf/deref refs/workspace-libraries)
|
||||
|
|
|
@ -43,7 +43,9 @@
|
|||
:rect i/box
|
||||
:curve i/curve
|
||||
:text i/text
|
||||
:group i/folder
|
||||
:group (if (nil? (:component-id shape))
|
||||
i/folder
|
||||
i/component)
|
||||
nil))
|
||||
|
||||
;; --- Layer Name
|
||||
|
@ -186,6 +188,7 @@
|
|||
[:li {:on-context-menu on-context-menu
|
||||
:ref dref
|
||||
:class (dom/classnames
|
||||
:component (not (nil? (:component-id item)))
|
||||
:dnd-over (= (:over dprops) :center)
|
||||
:dnd-over-top (= (:over dprops) :top)
|
||||
:dnd-over-bot (= (:over dprops) :bot)
|
||||
|
@ -285,7 +288,16 @@
|
|||
|
||||
(defn- strip-objects
|
||||
[objects]
|
||||
(let [strip-data #(select-keys % [:id :name :blocked :hidden :shapes :type :content :parent-id :metadata])]
|
||||
(let [strip-data #(select-keys % [:id
|
||||
:name
|
||||
:blocked
|
||||
:hidden
|
||||
:shapes
|
||||
:type
|
||||
:content
|
||||
:parent-id
|
||||
:component-id
|
||||
:metadata])]
|
||||
(persistent!
|
||||
(reduce-kv (fn [res id obj]
|
||||
(assoc! res id (strip-data obj)))
|
||||
|
|
Loading…
Add table
Reference in a new issue