mirror of
https://github.com/penpot/penpot.git
synced 2025-02-13 02:28:18 -05:00
✨ Visual redesign for undo history
This commit is contained in:
parent
0e3c3ebfbd
commit
b8e47c87ba
4 changed files with 637 additions and 97 deletions
|
@ -1441,7 +1441,7 @@
|
|||
}
|
||||
},
|
||||
"settings.multiple" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:153", "src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:163", "src/app/main/ui/workspace/sidebar/options/typography.cljs:99", "src/app/main/ui/workspace/sidebar/options/typography.cljs:149", "src/app/main/ui/workspace/sidebar/options/typography.cljs:162", "src/app/main/ui/workspace/sidebar/options/stroke.cljs:156" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:153", "src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:163", "src/app/main/ui/workspace/sidebar/options/typography.cljs:99", "src/app/main/ui/workspace/sidebar/options/typography.cljs:149", "src/app/main/ui/workspace/sidebar/options/typography.cljs:162", "src/app/main/ui/workspace/sidebar/options/stroke.cljs:147" ],
|
||||
"translations" : {
|
||||
"en" : "Mixed",
|
||||
"fr" : null,
|
||||
|
@ -1666,7 +1666,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.assets.assets" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:629" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:628" ],
|
||||
"translations" : {
|
||||
"en" : "Assets",
|
||||
"fr" : "",
|
||||
|
@ -1675,7 +1675,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.assets.box-filter-all" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:649" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:648" ],
|
||||
"translations" : {
|
||||
"en" : "All assets",
|
||||
"fr" : "",
|
||||
|
@ -1702,7 +1702,7 @@
|
|||
"unused" : true
|
||||
},
|
||||
"workspace.assets.colors" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:329", "src/app/main/ui/workspace/sidebar/assets.cljs:652" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:329", "src/app/main/ui/workspace/sidebar/assets.cljs:651" ],
|
||||
"translations" : {
|
||||
"en" : "Colors",
|
||||
"fr" : "",
|
||||
|
@ -1711,7 +1711,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.assets.components" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:83", "src/app/main/ui/workspace/sidebar/assets.cljs:650" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:83", "src/app/main/ui/workspace/sidebar/assets.cljs:649" ],
|
||||
"translations" : {
|
||||
"en" : "Components",
|
||||
"fr" : "",
|
||||
|
@ -1738,7 +1738,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.assets.file-library" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:532" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:531" ],
|
||||
"translations" : {
|
||||
"en" : "File library",
|
||||
"fr" : "",
|
||||
|
@ -1747,7 +1747,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.assets.graphics" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:164", "src/app/main/ui/workspace/sidebar/assets.cljs:651" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:164", "src/app/main/ui/workspace/sidebar/assets.cljs:650" ],
|
||||
"translations" : {
|
||||
"en" : "Graphics",
|
||||
"fr" : "",
|
||||
|
@ -1756,7 +1756,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.assets.libraries" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:632" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:631" ],
|
||||
"translations" : {
|
||||
"en" : "Libraries",
|
||||
"fr" : "",
|
||||
|
@ -1765,7 +1765,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.assets.not-found" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:593" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:592" ],
|
||||
"translations" : {
|
||||
"en" : "No assets found",
|
||||
"fr" : "",
|
||||
|
@ -1783,7 +1783,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.assets.search" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:636" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:635" ],
|
||||
"translations" : {
|
||||
"en" : "Search assets",
|
||||
"fr" : "",
|
||||
|
@ -1792,7 +1792,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.assets.shared" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:534" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:533" ],
|
||||
"translations" : {
|
||||
"en" : "SHARED",
|
||||
"fr" : "",
|
||||
|
@ -1801,7 +1801,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.assets.typography" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:420", "src/app/main/ui/workspace/sidebar/assets.cljs:653" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/assets.cljs:420", "src/app/main/ui/workspace/sidebar/assets.cljs:652" ],
|
||||
"translations" : {
|
||||
"en" : "Typographies"
|
||||
}
|
||||
|
@ -1855,13 +1855,13 @@
|
|||
}
|
||||
},
|
||||
"workspace.gradients.linear" : {
|
||||
"used-in" : [ "src/app/main/data/workspace/libraries.cljs:39", "src/app/main/ui/components/color_bullet.cljs:30" ],
|
||||
"used-in" : [ "src/app/main/data/workspace/libraries.cljs:39", "src/app/main/ui/components/color_bullet.cljs:31" ],
|
||||
"translations" : {
|
||||
"en" : "Linear gradient"
|
||||
}
|
||||
},
|
||||
"workspace.gradients.radial" : {
|
||||
"used-in" : [ "src/app/main/data/workspace/libraries.cljs:40", "src/app/main/ui/components/color_bullet.cljs:31" ],
|
||||
"used-in" : [ "src/app/main/data/workspace/libraries.cljs:40", "src/app/main/ui/components/color_bullet.cljs:32" ],
|
||||
"translations" : {
|
||||
"en" : "Radial gradient"
|
||||
}
|
||||
|
@ -2044,19 +2044,19 @@
|
|||
}
|
||||
},
|
||||
"workspace.libraries.colors.big-thumbnails" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/colorpalette.cljs:171" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/colorpalette.cljs:169" ],
|
||||
"translations" : {
|
||||
"en" : "Big thumbnails"
|
||||
}
|
||||
},
|
||||
"workspace.libraries.colors.file-library" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/colorpicker/libraries.cljs:87", "src/app/main/ui/workspace/colorpalette.cljs:149" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/colorpicker/libraries.cljs:87", "src/app/main/ui/workspace/colorpalette.cljs:147" ],
|
||||
"translations" : {
|
||||
"en" : "File library"
|
||||
}
|
||||
},
|
||||
"workspace.libraries.colors.recent-colors" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/colorpicker/libraries.cljs:86", "src/app/main/ui/workspace/colorpalette.cljs:159" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/colorpicker/libraries.cljs:86", "src/app/main/ui/workspace/colorpalette.cljs:157" ],
|
||||
"translations" : {
|
||||
"en" : "Recent colors"
|
||||
}
|
||||
|
@ -2068,7 +2068,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.libraries.colors.small-thumbnails" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/colorpalette.cljs:176" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/colorpalette.cljs:174" ],
|
||||
"translations" : {
|
||||
"en" : "Small thumbnails"
|
||||
}
|
||||
|
@ -2173,13 +2173,13 @@
|
|||
}
|
||||
},
|
||||
"workspace.libraries.text.multiple-typography" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:266" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:267" ],
|
||||
"translations" : {
|
||||
"en" : "Multiple typographies"
|
||||
}
|
||||
},
|
||||
"workspace.libraries.text.multiple-typography-tooltip" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:268" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/text.cljs:269" ],
|
||||
"translations" : {
|
||||
"en" : "Unlink all typographies"
|
||||
}
|
||||
|
@ -2302,7 +2302,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.options.fill" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/fill.cljs:54" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/fill.cljs:53" ],
|
||||
"translations" : {
|
||||
"en" : "Fill",
|
||||
"fr" : "Remplissage",
|
||||
|
@ -2500,7 +2500,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.options.group-fill" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/fill.cljs:53" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/fill.cljs:52" ],
|
||||
"translations" : {
|
||||
"en" : "Group fill",
|
||||
"fr" : null,
|
||||
|
@ -2509,7 +2509,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.options.group-stroke" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/stroke.cljs:72" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/stroke.cljs:63" ],
|
||||
"translations" : {
|
||||
"en" : "Group stroke",
|
||||
"fr" : null,
|
||||
|
@ -2590,7 +2590,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.options.selection-fill" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/fill.cljs:52" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/fill.cljs:51" ],
|
||||
"translations" : {
|
||||
"en" : "Selection fill",
|
||||
"fr" : null,
|
||||
|
@ -2599,7 +2599,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.options.selection-stroke" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/stroke.cljs:71" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/stroke.cljs:62" ],
|
||||
"translations" : {
|
||||
"en" : "Selection stroke",
|
||||
"fr" : null,
|
||||
|
@ -2668,7 +2668,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.options.stroke" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/stroke.cljs:73" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/stroke.cljs:64" ],
|
||||
"translations" : {
|
||||
"en" : "Stroke",
|
||||
"fr" : "Bordure",
|
||||
|
@ -2677,7 +2677,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.options.stroke.center" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/stroke.cljs:163" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/stroke.cljs:154" ],
|
||||
"translations" : {
|
||||
"en" : "Center",
|
||||
"fr" : "Centre",
|
||||
|
@ -2686,7 +2686,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.options.stroke.dashed" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/stroke.cljs:173" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/stroke.cljs:164" ],
|
||||
"translations" : {
|
||||
"en" : "Dashed",
|
||||
"fr" : "Tiré",
|
||||
|
@ -2695,7 +2695,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.options.stroke.dotted" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/stroke.cljs:172" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/stroke.cljs:163" ],
|
||||
"translations" : {
|
||||
"en" : "Dotted",
|
||||
"fr" : "Pointillé",
|
||||
|
@ -2704,7 +2704,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.options.stroke.inner" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/stroke.cljs:164" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/stroke.cljs:155" ],
|
||||
"translations" : {
|
||||
"en" : "Inside",
|
||||
"fr" : "Intérieur",
|
||||
|
@ -2713,7 +2713,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.options.stroke.mixed" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/stroke.cljs:174" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/stroke.cljs:165" ],
|
||||
"translations" : {
|
||||
"en" : "Mixed",
|
||||
"fr" : "Mixte",
|
||||
|
@ -2722,7 +2722,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.options.stroke.outer" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/stroke.cljs:165" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/stroke.cljs:156" ],
|
||||
"translations" : {
|
||||
"en" : "Outside",
|
||||
"fr" : "Extérieur",
|
||||
|
@ -2731,7 +2731,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.options.stroke.solid" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/stroke.cljs:171" ],
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/options/stroke.cljs:162" ],
|
||||
"translations" : {
|
||||
"en" : "Solid",
|
||||
"fr" : "Solide",
|
||||
|
@ -3070,8 +3070,230 @@
|
|||
"es" : "Texto (T)"
|
||||
}
|
||||
},
|
||||
"workspace.undo.empty" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/history.cljs:272" ],
|
||||
"translations" : {
|
||||
"en" : "There are no history changes so far"
|
||||
}
|
||||
},
|
||||
"workspace.undo.entry.delete" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/history.cljs:110" ],
|
||||
"translations" : {
|
||||
"en" : "Deleted %s"
|
||||
}
|
||||
},
|
||||
"workspace.undo.entry.modify" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/history.cljs:109" ],
|
||||
"translations" : {
|
||||
"en" : "Modified %s"
|
||||
}
|
||||
},
|
||||
"workspace.undo.entry.move" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/history.cljs:111" ],
|
||||
"translations" : {
|
||||
"en" : "Moved objects"
|
||||
}
|
||||
},
|
||||
"workspace.undo.entry.multiple.circle" : {
|
||||
"translations" : {
|
||||
"en" : "circles"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"workspace.undo.entry.multiple.color" : {
|
||||
"translations" : {
|
||||
"en" : "color assets"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"workspace.undo.entry.multiple.component" : {
|
||||
"translations" : {
|
||||
"en" : "components"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"workspace.undo.entry.multiple.curve" : {
|
||||
"translations" : {
|
||||
"en" : "curves"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"workspace.undo.entry.multiple.frame" : {
|
||||
"translations" : {
|
||||
"en" : "artboard"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"workspace.undo.entry.multiple.group" : {
|
||||
"translations" : {
|
||||
"en" : "groups"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"workspace.undo.entry.multiple.image" : {
|
||||
"translations" : {
|
||||
"en" : "images"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"workspace.undo.entry.multiple.media" : {
|
||||
"translations" : {
|
||||
"en" : "graphic assets"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"workspace.undo.entry.multiple.multiple" : {
|
||||
"translations" : {
|
||||
"en" : "objects"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"workspace.undo.entry.multiple.page" : {
|
||||
"translations" : {
|
||||
"en" : "pages"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"workspace.undo.entry.multiple.path" : {
|
||||
"translations" : {
|
||||
"en" : "paths"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"workspace.undo.entry.multiple.rect" : {
|
||||
"translations" : {
|
||||
"en" : "rectangles"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"workspace.undo.entry.multiple.shape" : {
|
||||
"translations" : {
|
||||
"en" : "shapes"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"workspace.undo.entry.multiple.text" : {
|
||||
"translations" : {
|
||||
"en" : "texts"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"workspace.undo.entry.multiple.typography" : {
|
||||
"translations" : {
|
||||
"en" : "typography assets"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"workspace.undo.entry.new" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/history.cljs:108" ],
|
||||
"translations" : {
|
||||
"en" : "New %s"
|
||||
}
|
||||
},
|
||||
"workspace.undo.entry.single.circle" : {
|
||||
"translations" : {
|
||||
"en" : "circle"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"workspace.undo.entry.single.color" : {
|
||||
"translations" : {
|
||||
"en" : "color asset"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"workspace.undo.entry.single.component" : {
|
||||
"translations" : {
|
||||
"en" : "component"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"workspace.undo.entry.single.curve" : {
|
||||
"translations" : {
|
||||
"en" : "curve"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"workspace.undo.entry.single.frame" : {
|
||||
"translations" : {
|
||||
"en" : "frame"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"workspace.undo.entry.single.group" : {
|
||||
"translations" : {
|
||||
"en" : "group"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"workspace.undo.entry.single.image" : {
|
||||
"translations" : {
|
||||
"en" : "image"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"workspace.undo.entry.single.media" : {
|
||||
"translations" : {
|
||||
"en" : "graphic asset"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"workspace.undo.entry.single.multiple" : {
|
||||
"translations" : {
|
||||
"en" : "object"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"workspace.undo.entry.single.page" : {
|
||||
"translations" : {
|
||||
"en" : "page"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"workspace.undo.entry.single.path" : {
|
||||
"translations" : {
|
||||
"en" : "path"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"workspace.undo.entry.single.rect" : {
|
||||
"translations" : {
|
||||
"en" : "rectangle"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"workspace.undo.entry.single.shape" : {
|
||||
"translations" : {
|
||||
"en" : "shape"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"workspace.undo.entry.single.text" : {
|
||||
"translations" : {
|
||||
"en" : "text"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"workspace.undo.entry.single.typography" : {
|
||||
"translations" : {
|
||||
"en" : "typography asset"
|
||||
},
|
||||
"unused" : true
|
||||
},
|
||||
"workspace.undo.entry.unknown" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/history.cljs:112" ],
|
||||
"translations" : {
|
||||
"en" : "Operation over %s"
|
||||
}
|
||||
},
|
||||
"workspace.undo.title" : {
|
||||
"used-in" : [ "src/app/main/ui/workspace/sidebar/history.cljs:268" ],
|
||||
"translations" : {
|
||||
"en" : "History"
|
||||
}
|
||||
},
|
||||
"workspace.updates.dismiss" : {
|
||||
"used-in" : [ "src/app/main/data/workspace/libraries.cljs:538" ],
|
||||
"used-in" : [ "src/app/main/data/workspace/libraries.cljs:542" ],
|
||||
"translations" : {
|
||||
"en" : "Dismiss",
|
||||
"fr" : "",
|
||||
|
@ -3080,7 +3302,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.updates.there-are-updates" : {
|
||||
"used-in" : [ "src/app/main/data/workspace/libraries.cljs:534" ],
|
||||
"used-in" : [ "src/app/main/data/workspace/libraries.cljs:538" ],
|
||||
"translations" : {
|
||||
"en" : "There are updates in shared libraries",
|
||||
"fr" : "",
|
||||
|
@ -3089,7 +3311,7 @@
|
|||
}
|
||||
},
|
||||
"workspace.updates.update" : {
|
||||
"used-in" : [ "src/app/main/data/workspace/libraries.cljs:536" ],
|
||||
"used-in" : [ "src/app/main/data/workspace/libraries.cljs:540" ],
|
||||
"translations" : {
|
||||
"en" : "Update",
|
||||
"fr" : "",
|
||||
|
|
|
@ -8,37 +8,122 @@
|
|||
// Copyright (c) 2020 UXBOX Labs SL
|
||||
|
||||
.history-toolbox {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.history-toolbox-title {
|
||||
color: $color-gray-10;
|
||||
font-size: $fs14;
|
||||
padding: 0.5rem;
|
||||
color: $color-gray-10;
|
||||
font-size: $fs14;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.undo-history {
|
||||
.history-entry-empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 1rem;
|
||||
|
||||
.history-entry-empty-icon {
|
||||
margin-bottom: 1rem;
|
||||
svg {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
fill: $color-gray-40;
|
||||
}
|
||||
}
|
||||
|
||||
.history-entry-empty-msg {
|
||||
color: $color-gray-30;
|
||||
font-size: $fs12;
|
||||
color: $color-gray-10;
|
||||
|
||||
.undo-entry {
|
||||
max-height: 10rem;
|
||||
overflow: auto;
|
||||
margin: 0.5rem;
|
||||
|
||||
&.transaction {
|
||||
border: 2px solid $color-primary;
|
||||
}
|
||||
}
|
||||
|
||||
.undo-entry-change {
|
||||
background-color: #1F1F1F;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.separator {
|
||||
margin: 0.5rem;
|
||||
border-color: $color-primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.history-entries {
|
||||
font-size: $fs12;
|
||||
color: $color-gray-20;
|
||||
fill: $color-gray-20;
|
||||
}
|
||||
|
||||
.history-entry {
|
||||
border: 1px solid $color-gray-60;
|
||||
border-radius: 4px;
|
||||
margin: 0.5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0.5rem;
|
||||
cursor: pointer;
|
||||
|
||||
transition: border 0.2s;
|
||||
|
||||
&.disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
&.current {
|
||||
background-color: $color-gray-60;
|
||||
}
|
||||
|
||||
&.hover {
|
||||
border-color: $color-primary;
|
||||
}
|
||||
}
|
||||
|
||||
.history-entry-summary {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
* {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.history-entry-summary-icon {
|
||||
svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.history-entry-summary-text {
|
||||
flex: 1;
|
||||
margin: 0 0.5rem;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.history-entry-summary-button {
|
||||
opacity: 0;
|
||||
transition: transform 0.2s;
|
||||
|
||||
svg {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
.show-detail &,
|
||||
.hover & {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.show-detail & {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
|
||||
.history-entry-detail {
|
||||
display: none;
|
||||
|
||||
.show-detail & {
|
||||
display: block;
|
||||
padding: 1rem 0 0.5rem 0;
|
||||
}
|
||||
|
||||
.history-entry-details-list {
|
||||
margin: 0;
|
||||
|
||||
li {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -244,7 +244,10 @@
|
|||
:page-id page-id
|
||||
:parent-id parent-id
|
||||
:shapes shapes
|
||||
:index index-in-parent}]
|
||||
:index index-in-parent}
|
||||
{:type :del-obj
|
||||
:page-id page-id
|
||||
:id (:id group)}]
|
||||
uchanges [{:type :add-obj
|
||||
:page-id page-id
|
||||
:id (:id group)
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
(:require
|
||||
[rumext.alpha :as mf]
|
||||
[cuerdas.core :as str]
|
||||
[app.common.data :as d]
|
||||
[app.main.ui.icons :as i]
|
||||
[app.main.data.history :as udh]
|
||||
[app.main.data.workspace :as dw]
|
||||
|
@ -27,42 +28,271 @@
|
|||
(def workspace-undo
|
||||
(l/derived :workspace-undo st/state))
|
||||
|
||||
(mf/defc undo-entry [{:keys [index entry objects is-transaction?] :or {is-transaction? false}}]
|
||||
(let [{:keys [redo-changes]} entry]
|
||||
[:li.undo-entry {:class (when is-transaction? "transaction")}
|
||||
(for [[idx-change {:keys [type id operations]}] (map-indexed vector redo-changes)]
|
||||
[:div.undo-entry-change {:key (str "change-" idx-change)}
|
||||
[:div.undo-entry-change-data (when type (str type)) " " (when id (str (get-in objects [id :name] (subs (str id) 0 8))))]
|
||||
(when operations
|
||||
[:div.undo-entry-change-data (str/join ", "
|
||||
(map (comp name :attr)
|
||||
(filter #(= (:type %) :set) operations)))])])]))
|
||||
(defn get-object
|
||||
"Searchs for a shape inside the objects list or inside the undo history"
|
||||
[id entries objects]
|
||||
(let [search-deleted-shape
|
||||
(fn [id entries]
|
||||
(let [search-obj (fn [obj] (and (= (:type obj) :add-obj)
|
||||
(= (:id obj) id)))
|
||||
search-delete-entry (fn [{:keys [undo-changes redo-changes]}]
|
||||
(or (d/seek search-obj undo-changes)
|
||||
(d/seek search-obj redo-changes)))
|
||||
{:keys [obj]} (->> entries (d/seek search-delete-entry) search-delete-entry)]
|
||||
obj))]
|
||||
(or (get objects id)
|
||||
(search-deleted-shape id entries))))
|
||||
|
||||
|
||||
(defn extract-operation
|
||||
"Generalizes the type of operation for different types of change"
|
||||
[change]
|
||||
(case (:type change)
|
||||
(:add-obj :add-page :add-color :add-media :add-component :add-typography) :new
|
||||
(:mod-obj :mod-page :mod-color :mod-media :mod-component :mod-typography) :modify
|
||||
(:del-obj :del-page :del-color :del-media :del-component :del-typography) :delete
|
||||
:mov-objects :move
|
||||
nil))
|
||||
|
||||
(defn parse-change
|
||||
"Given a single change parses the information into an uniform map"
|
||||
[change]
|
||||
(let [r (fn [type id]
|
||||
{:type type
|
||||
:operation (extract-operation change)
|
||||
:detail (:operations change)
|
||||
:id (cond
|
||||
(and (coll? id) (= 1 (count id))) (first id)
|
||||
(coll? id) :multiple
|
||||
:else id)})]
|
||||
(case (:type change)
|
||||
:set-option (r :page (:page-id change))
|
||||
(:add-obj
|
||||
:mod-obj
|
||||
:del-obj) (r :shape (:id change))
|
||||
:reg-objects nil
|
||||
:mov-objects (r :shape (:shapes change))
|
||||
(:add-page
|
||||
:mod-page :del-page
|
||||
:mov-page) (r :page (:id change))
|
||||
(:add-color
|
||||
:mod-color) (r :color (get-in change [:color :id]))
|
||||
:del-color (r :color (:id change))
|
||||
:add-recent-color nil
|
||||
(:add-media
|
||||
:mod-media) (r :media (get-in change [:object :id]))
|
||||
:del-media (r :media (:id change))
|
||||
(:add-component
|
||||
:mod-component
|
||||
:del-component) (r :component (:id change))
|
||||
(:add-typography
|
||||
:mod-typography) (r :typography (get-in change [:typography :id]))
|
||||
:del-typography (r :typography (:id change))
|
||||
nil)))
|
||||
|
||||
(defn resolve-shape-types
|
||||
"Retrieve the type to be shown to the user"
|
||||
[entries objects]
|
||||
(let [resolve-type (fn [{:keys [type id]}]
|
||||
(if (or (not= type :shape) (= id :multiple))
|
||||
type
|
||||
(:type (get-object id entries objects))))
|
||||
|
||||
map-fn (fn [entry]
|
||||
(if (and (= (:type entry) :shape)
|
||||
(not= (:id entry) :multiple))
|
||||
(assoc entry :type (resolve-type entry))
|
||||
entry))]
|
||||
(fn [entries]
|
||||
(map map-fn entries))))
|
||||
|
||||
(defn entry-type->message
|
||||
"Formats the message that will be displayed to the user"
|
||||
[locale type multiple?]
|
||||
(let [arity (if multiple? "multiple" "single")
|
||||
attribute (name (or type :multiple))]
|
||||
(t locale (str/format "workspace.undo.entry.%s.%s" arity attribute))))
|
||||
|
||||
(defn entry->message [locale entry]
|
||||
(let [value (entry-type->message locale (:type entry) (= :multiple (:id entry)))]
|
||||
(case (:operation entry)
|
||||
:new (t locale "workspace.undo.entry.new" value)
|
||||
:modify (t locale "workspace.undo.entry.modify" value)
|
||||
:delete (t locale "workspace.undo.entry.delete" value)
|
||||
:move (t locale "workspace.undo.entry.move" value)
|
||||
(t locale "workspace.undo.entry.unknown" value))))
|
||||
|
||||
(defn entry->icon [{:keys [type]}]
|
||||
(case type
|
||||
:page i/file-html
|
||||
:shape i/layers
|
||||
:rect i/box
|
||||
:circle i/circle
|
||||
:text i/text
|
||||
:curve i/curve
|
||||
:path i/curve
|
||||
:frame i/artboard
|
||||
:group i/folder
|
||||
:color i/palette
|
||||
:typography i/titlecase
|
||||
:component i/component
|
||||
:media i/image
|
||||
:image i/image
|
||||
i/layers))
|
||||
|
||||
(defn is-shape? [type]
|
||||
#{:shape :rect :circle :text :curve :path :frame :group})
|
||||
|
||||
(defn parse-entry [{:keys [redo-changes]}]
|
||||
(->> redo-changes
|
||||
(map parse-change)))
|
||||
|
||||
(defn safe-name [maybe-keyword]
|
||||
(if (keyword? maybe-keyword)
|
||||
(name maybe-keyword)
|
||||
maybe-keyword))
|
||||
|
||||
(defn select-entry
|
||||
"Selects the entry the user will see inside a list of posible entries.
|
||||
Sometimes the result will be a combination."
|
||||
[candidates]
|
||||
(let [;; Group by id and type
|
||||
entries (->> candidates
|
||||
(remove nil?)
|
||||
(group-by #(vector (:type %) (:operation %) (:id %)) ))
|
||||
|
||||
single? (fn [coll] (= (count coll) 1))
|
||||
|
||||
;; Retrieve also by-type and by-operation
|
||||
types (group-by first (keys entries))
|
||||
operations (group-by second (keys entries))
|
||||
|
||||
;; The cases for the selection of the representative entry are a bit
|
||||
;; convoluted. Best to read the comments to clarify.
|
||||
;; At this stage we have cleaned the entries but we can have a batch
|
||||
;; of operations for a single undo-entry. We want to select the
|
||||
;; one that is most interesting for the user.
|
||||
selected-entry
|
||||
(cond
|
||||
;; If we only have one operation over one shape we return the last change
|
||||
(single? entries)
|
||||
(-> entries (get (first (keys entries))) (last))
|
||||
|
||||
;; If we're creating an object it will have priority
|
||||
(single? (:new operations))
|
||||
(-> entries (get (first (:new operations))) (last))
|
||||
|
||||
;; If there is only a deletion of 1 group we retrieve this operation because
|
||||
;; the others will be the children
|
||||
(single? (filter #(= :group (first %)) (:delete operations)))
|
||||
(-> entries (get (first (filter #(= :group (first %)) (:delete operations)))) (last))
|
||||
|
||||
;; Otherwise we could have the same operation between several
|
||||
;; types (i.e: delete various shapes). If that happens we return
|
||||
;; the operation with `:multiple` id
|
||||
(single? operations)
|
||||
{:type (if (every? is-shape? (keys types)) :shape :multiple)
|
||||
:id :multiple
|
||||
:operation (first (keys operations))}
|
||||
|
||||
;; Finally, if we have several operations over several shapes we return
|
||||
;; `:multiple` for operation and type and join the last of the operations for
|
||||
;; each shape
|
||||
:else
|
||||
{:type :multiple
|
||||
:id :multiple
|
||||
:operation :multiple})
|
||||
|
||||
|
||||
;; We add to the detail the information depending on the type of operation
|
||||
detail
|
||||
(case (:operation selected-entry)
|
||||
:new (:id selected-entry)
|
||||
:modify (->> candidates
|
||||
(filter #(= :modify (:operation %)))
|
||||
(group-by :id)
|
||||
(d/mapm (fn [k v] (->> v
|
||||
(mapcat :detail)
|
||||
(map (comp safe-name :attr))
|
||||
(remove nil?)
|
||||
(into #{})))))
|
||||
:delete (->> candidates
|
||||
(filter #(= :delete (:operation %)))
|
||||
(map :id))
|
||||
candidates)]
|
||||
|
||||
(assoc selected-entry :detail detail)))
|
||||
|
||||
(defn parse-entries [entries objects]
|
||||
(->> entries
|
||||
(map parse-entry)
|
||||
(map (resolve-shape-types entries objects))
|
||||
(mapv select-entry)))
|
||||
|
||||
(mf/defc history-entry-details [{:keys [entry]}]
|
||||
(let [{entries :items} (mf/deref workspace-undo)
|
||||
objects (mf/deref refs/workspace-page-objects)]
|
||||
|
||||
[:div.history-entry-detail
|
||||
(case (:operation entry)
|
||||
:new
|
||||
(:name (get-object (:detail entry) entries objects))
|
||||
|
||||
:delete
|
||||
[:ul.history-entry-details-list
|
||||
(for [id (:detail entry)]
|
||||
(let [shape-name (:name (get-object id entries objects))]
|
||||
[:li {:key id} shape-name]))]
|
||||
|
||||
|
||||
:modify
|
||||
[:ul.history-entry-details-list
|
||||
(for [[id attributes] (:detail entry)]
|
||||
(let [shape-name (:name (get-object id entries objects))]
|
||||
[:li {:key id}
|
||||
[:div shape-name]
|
||||
[:div (str/join ", " attributes)]]))]
|
||||
|
||||
nil)]))
|
||||
|
||||
(mf/defc history-entry [{:keys [locale entry disabled? current?]}]
|
||||
(let [hover? (mf/use-state false)
|
||||
show-detail? (mf/use-state false)]
|
||||
[:div.history-entry {:class (dom/classnames
|
||||
:disabled disabled?
|
||||
:current current?
|
||||
:hover @hover?
|
||||
:show-detail @show-detail?)
|
||||
:on-mouse-enter #(reset! hover? true)
|
||||
:on-mouse-leave #(reset! hover? false)
|
||||
:on-click #(when (:detail entry)
|
||||
(swap! show-detail? not))
|
||||
}
|
||||
[:div.history-entry-summary
|
||||
[:div.history-entry-summary-icon (entry->icon entry)]
|
||||
[:div.history-entry-summary-text (entry->message locale entry)]
|
||||
(when (:detail entry)
|
||||
[:div.history-entry-summary-button i/arrow-slide])]
|
||||
|
||||
(when show-detail?
|
||||
[:& history-entry-details {:entry entry}])]))
|
||||
|
||||
(mf/defc history-toolbox []
|
||||
(let [locale (mf/deref i18n/locale)
|
||||
objects (mf/deref refs/workspace-page-objects)
|
||||
{:keys [items index transaction]} (mf/deref workspace-undo)
|
||||
objects (mf/deref refs/workspace-page-objects)]
|
||||
entries (parse-entries items objects)]
|
||||
[:div.history-toolbox
|
||||
[:div.history-toolbox-title "History"]
|
||||
[:ul.undo-history
|
||||
[:*
|
||||
(when (and
|
||||
(> (count items) 0)
|
||||
(or (nil? index)
|
||||
(>= index (count items))))
|
||||
[:hr.separator])
|
||||
|
||||
(when transaction
|
||||
[:& undo-entry {:key (str "transaction")
|
||||
:objects objects
|
||||
:is-transaction? true
|
||||
:entry transaction}])
|
||||
|
||||
(for [[idx-entry entry] (->> items (map-indexed vector) reverse)]
|
||||
[:*
|
||||
(when (= index idx-entry) [:hr.separator {:data-index index}])
|
||||
[:& undo-entry {:key (str "entry-" idx-entry)
|
||||
:objects objects
|
||||
:entry entry}]])
|
||||
(when (= index -1) [:hr.separator])]]]))
|
||||
[:div.history-toolbox-title (t locale "workspace.undo.title")]
|
||||
(if (empty? entries)
|
||||
[:div.history-entry-empty
|
||||
[:div.history-entry-empty-icon i/undo-history]
|
||||
[:div.history-entry-empty-msg (t locale "workspace.undo.empty")]]
|
||||
[:ul.history-entries
|
||||
(for [[idx-entry entry] (->> entries (map-indexed vector) reverse)] #_[i (range 0 10)]
|
||||
[:& history-entry {:key (str "entry-" idx-entry)
|
||||
:locale locale
|
||||
:entry entry
|
||||
:current? (= idx-entry index)
|
||||
:disabled? (> idx-entry index)}])])]))
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue