├── .agignore
├── .gitignore
├── README.md
├── _versions
├── zenb.sketchplugin
│ └── Contents
│ │ └── Sketch
│ │ ├── Layers
│ │ ├── Append-BEM.cocoascript
│ │ ├── Make-Font-Artboard-Icons.cocoascript
│ │ ├── Remove-Empty-Groups.cocoascript
│ │ ├── Resize-Group-Area.cocoascript
│ │ ├── Send-To-Artboard.cocoascript
│ │ ├── Snap-Layer-To-Eight.cocoascript
│ │ ├── Toggle-Click-Throught.cocoascript
│ │ ├── Toggle-User-Guides.cocoascript
│ │ └── Transform-Each.cocoascript
│ │ ├── Preview
│ │ ├── Preview-Artboard-Desktop.cocoascript
│ │ └── Preview-Artboard-Mobile.cocoascript
│ │ ├── Typography
│ │ └── ModularScale.cocoascript
│ │ ├── _Wip
│ │ ├── _Filter Shapes.cocoascript
│ │ ├── _Filter Texts.cocoascript
│ │ ├── _Fit Artobard Width.cocoascript
│ │ ├── _Fit Group Size.cocoascript
│ │ └── _clipboard.cocoascript
│ │ ├── manifest.json
│ │ └── sQuery
│ │ ├── liveQuery.js
│ │ ├── plugins
│ │ ├── core.areGroups.js
│ │ ├── core.areShapes.js
│ │ ├── core.move.js
│ │ └── core.parentRoot.js
│ │ └── sQuery.js
└── zenc.sketchplugin
│ └── Contents
│ └── Sketch
│ ├── Layers
│ ├── Append-BEM.cocoascript
│ ├── Make-Font-Artboard-Icons.cocoascript
│ ├── Remove-Empty-Groups.cocoascript
│ ├── Resize-Group-Area.cocoascript
│ ├── Send-To-Artboard.cocoascript
│ ├── Snap-Layer-To-Eight.cocoascript
│ ├── Toggle-Click-Throught.cocoascript
│ ├── Toggle-User-Guides.cocoascript
│ ├── Transform-Each.cocoascript
│ └── UnlockAllLayers.cocoascript
│ ├── Preview
│ ├── Preview-Artboard-Desktop.cocoascript
│ └── Preview-Artboard-Mobile.cocoascript
│ ├── Typography
│ └── ModularScale.cocoascript
│ ├── _Wip
│ ├── _Filter Shapes.cocoascript
│ ├── _Filter Texts.cocoascript
│ ├── _Fit Artobard Width.cocoascript
│ ├── _Fit Group Size.cocoascript
│ └── _clipboard.cocoascript
│ ├── manifest.json
│ └── sQuery
│ ├── liveQuery.js
│ ├── liveQuery
│ ├── _liveQuery.js
│ └── liveQuery.js
│ ├── plugins
│ ├── sQuery.areGroups.js
│ ├── sQuery.areShapes.js
│ ├── sQuery.move.js
│ └── sQuery.sendToRoot.js
│ └── sQuery.js
├── appcast.xml
├── gulpfile.js
├── package.json
└── zen.sketchplugin
└── Contents
└── Sketch
├── Layers
├── Append-BEM.cocoascript
├── Make-Font-Artboard-Icons.cocoascript
├── Remove-Empty-Groups.cocoascript
├── Resize-Group-Area.cocoascript
├── Select-Childs-Layers.js
├── Send-To-Artboard.cocoascript
├── Snap-Layer-To-Eight.cocoascript
├── Toggle-Click-Throught.cocoascript
├── Toggle-User-Guides.cocoascript
├── Transform-Each.cocoascript
└── UnlockAllLayers.cocoascript
├── Preview
├── Preview-Artboard-Desktop.cocoascript
├── Preview-Artboard-Mobile.cocoascript
├── Preview-Artboard-Simple.cocoascript
├── Preview-Artboard-iphonex.cocoascript
└── common-preview.js
├── Typography
└── ModularScale.cocoascript
├── manifest.json
└── sQuery
├── liveQuery.js
├── liveQuery
├── _liveQuery.js
└── liveQuery.js
├── plugins
├── sQuery.areGroups.js
├── sQuery.areShapes.js
├── sQuery.move.js
└── sQuery.sendToRoot.js
└── sQuery.js
/.agignore:
--------------------------------------------------------------------------------
1 | .git
2 | node_modules
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by https://www.gitignore.io/api/node
2 |
3 | ### Node ###
4 | # Logs
5 | logs
6 | *.log
7 | npm-debug.log*
8 |
9 | # Runtime data
10 | pids
11 | *.pid
12 | *.seed
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
21 | .grunt
22 |
23 | # node-waf configuration
24 | .lock-wscript
25 |
26 | # Compiled binary addons (http://nodejs.org/api/addons.html)
27 | build/Release
28 |
29 | # Dependency directory
30 | # https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
31 | node_modules
32 |
33 | # Created by https://www.gitignore.io/api/osx
34 |
35 | ### OSX ###
36 | .DS_Store
37 | .AppleDouble
38 | .LSOverride
39 |
40 | # Icon must end with two \r
41 | Icon
42 |
43 | # Thumbnails
44 | ._*
45 |
46 | # Files that might appear in the root of a volume
47 | .DocumentRevisions-V100
48 | .fseventsd
49 | .Spotlight-V100
50 | .TemporaryItems
51 | .Trashes
52 | .VolumeIcon.icns
53 |
54 | # Directories potentially created on remote AFP share
55 | .AppleDB
56 | .AppleDesktop
57 | Network Trash Folder
58 | Temporary Items
59 | .apdisk
60 |
61 | zen.sketchplugin/Contents/Sketch/_Wip
62 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ZEN Sketch
2 | A very personal collection of Sketch plugins.
3 |
--------------------------------------------------------------------------------
/_versions/zenb.sketchplugin/Contents/Sketch/Layers/Append-BEM.cocoascript:
--------------------------------------------------------------------------------
1 | // Append BEM
2 | // @shortcut alt cmd r
3 |
4 | var onRun = function(context) {
5 | @import '../sQuery/sQuery.js';
6 |
7 | $("%selected%").each(function(){
8 |
9 | var layer = $(this).MSLayer();
10 | var B = /^[^__]*/g.exec(layer.parentGroup().name())[0];
11 | var EM = /__.*/g.exec(layer.name());
12 | if (EM) {
13 | layer.name = B+EM;
14 | } else {
15 | layer.name = B+"__"+layer.name();
16 | }
17 |
18 | });
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/_versions/zenb.sketchplugin/Contents/Sketch/Layers/Make-Font-Artboard-Icons.cocoascript:
--------------------------------------------------------------------------------
1 | var onRun = function(context) {
2 |
3 | @import '../sQuery/sQuery.js';
4 |
5 | function pad(n, width, z) {
6 | z = z || '0';
7 | n = n + '';
8 | return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
9 | }
10 |
11 | function iconNameRename(glyphName, withIconName) {
12 | withIconName = withIconName || false;
13 | var artboards = $("%artboards%");
14 | var iconName;
15 | //artboards.layers.reverse();
16 | artboards.each(function(idx) {
17 | if (withIconName) {
18 | iconName = "-" + this.layers().array()[0].name();
19 | } else {
20 | iconName = '';
21 | }
22 | this.name = glyphName + pad(idx, 3) + iconName;
23 | });
24 | }
25 |
26 |
27 | function reorderArtboards(itemsPerFile, offset) {
28 | var artboards = $("%artboards%");
29 | var artboardWidth = 560;
30 | var artboardHeight = 560;
31 | var file = 0;
32 | var row = 0;
33 |
34 | //artboards.layers.reverse();
35 |
36 | for(j=0; j<(artboards.length); j++) {
37 | if(file>itemsPerFile-1) { row +=1; file=0; }
38 | artboards.layers[j].frame().x = (artboardWidth + offset) * file;
39 | artboards.layers[j].frame().y = (artboardHeight + offset) * row;
40 | file +=1;
41 | }
42 | }
43 |
44 |
45 | var CURRENTPAGE = context.document.currentPage();
46 | var CURRENTARTBOARD = context.document.currentPage().currentArtboard();
47 |
48 | $("%shapes%").each(function(){
49 |
50 | var artboard = $(CURRENTPAGE).createArtboard("newArtboard", 0, 0, 560, 560); // <- sQuery
51 | artboard.addLayers([this]);
52 | CURRENTARTBOARD.removeLayer(this);
53 | this.frame().x = (560-this.frame().width())/2;
54 | this.frame().y = (560-this.frame().height())/2;
55 |
56 | })
57 |
58 | CURRENTPAGE.removeLayer(CURRENTARTBOARD);
59 | reorderArtboards(10, 300);
60 | iconNameRename("rIcon_", false);
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/_versions/zenb.sketchplugin/Contents/Sketch/Layers/Remove-Empty-Groups.cocoascript:
--------------------------------------------------------------------------------
1 | // Remove empty groups
2 | // @shortcut cmd e
3 | var onRun = function(context) {
4 | const selectedEmptyGroups = () => {
5 | const DOC = context.document;
6 | const PAGE = DOC.currentPage();
7 | const ARTBOARD = PAGE.currentArtboard();
8 | const allLayers = ARTBOARD.children().slice();
9 | const emptyGroups = allLayers.filter(layer => {
10 | try {
11 | return layer.layers().length === 0;
12 | } catch(e) { }
13 | });
14 | ARTBOARD.deselectAllLayers();
15 | emptyGroups.map(layer => layer.setIsSelected(true));
16 | }
17 | selectedEmptyGroups();
18 | }
19 |
--------------------------------------------------------------------------------
/_versions/zenb.sketchplugin/Contents/Sketch/Layers/Resize-Group-Area.cocoascript:
--------------------------------------------------------------------------------
1 | // Fit group bounding box size
2 |
3 | var onRun = function(context) {
4 | @import '../sQuery/sQuery.js';
5 | $("%groups%").each(function(){
6 | $(this).MSLayer().resizeRoot(1);
7 | });
8 | }
9 |
--------------------------------------------------------------------------------
/_versions/zenb.sketchplugin/Contents/Sketch/Layers/Send-To-Artboard.cocoascript:
--------------------------------------------------------------------------------
1 | var onRun = function(context) {
2 | @import '../sQuery/sQuery.js';
3 | @import '../sQuery/plugins/core.parentRoot.js';
4 |
5 | $("%selected%").parentRoot();
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/_versions/zenb.sketchplugin/Contents/Sketch/Layers/Snap-Layer-To-Eight.cocoascript:
--------------------------------------------------------------------------------
1 | // Round Int near to 8 mult
2 | // Ej: 15 -> 16 or 25 -> 24
3 | function roundIntToGrid(v, n) {
4 | return Math.round((v/n))*n
5 | }
6 |
7 | // Set layer position (x,y) to eight pixel grid
8 | function snapToEight(layer) {
9 | pixelGrid = 8
10 | newX = roundIntToGrid([[layer frame] x], pixelGrid)
11 | newY = roundIntToGrid([[layer frame] y], pixelGrid)
12 | [[layer frame] setX:newX]
13 | [[layer frame] setY:newY]
14 | }
15 |
16 | // Do it!
17 | snapToEight(context.selection[0])
18 |
--------------------------------------------------------------------------------
/_versions/zenb.sketchplugin/Contents/Sketch/Layers/Toggle-Click-Throught.cocoascript:
--------------------------------------------------------------------------------
1 | // Toggle click throught
2 | // @shortcut cmd shift d
3 |
4 | var onRun = function(context) {
5 | @import '../sQuery/sQuery.js';
6 | $('%groups%').toggleClickThrought();
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/_versions/zenb.sketchplugin/Contents/Sketch/Layers/Toggle-User-Guides.cocoascript:
--------------------------------------------------------------------------------
1 | // Tootle User Guides Layer
2 | // @shortcut cmd l
3 |
4 | var onRun = function(context) {
5 | // Import sQuery
6 | @import '../sQuery/sQuery.js';
7 |
8 | // Toggle Guides layer visibility
9 | var guidesGroup = $('*').withName('Guides').MSLayer();
10 | guidesGroup.setIsVisible(!guidesGroup.isVisible());
11 |
12 | }
13 |
14 |
--------------------------------------------------------------------------------
/_versions/zenb.sketchplugin/Contents/Sketch/Layers/Transform-Each.cocoascript:
--------------------------------------------------------------------------------
1 | // Transform Each
2 |
3 | var onRun = function(context) {
4 |
5 | @import '../sQuery/sQuery.js';
6 |
7 | var size = context.document.askForUserInput_initialValue("Enter Size Multiplier", "100%");
8 | var re = /\d*\.*\d/;
9 | var pValue = (parseFloat(re.exec(size)[0]))/100;
10 |
11 | var x, y, w, h, frame;
12 | $('%selected%').each(function(){
13 |
14 | // Transform data
15 | frame = this.frame();
16 | x = frame.x();
17 | y = frame.y();
18 | w = frame.width();
19 | h = frame.height();
20 |
21 | // Moving and scaling
22 | frame.width = w*pValue;
23 | frame.height = h*pValue;
24 | frame.x = x+(w-(w*(pValue)))/2
25 | frame.y = y+(h-(h*(pValue)))/2
26 |
27 | });
28 |
29 | };
30 |
31 |
--------------------------------------------------------------------------------
/_versions/zenb.sketchplugin/Contents/Sketch/Preview/Preview-Artboard-Desktop.cocoascript:
--------------------------------------------------------------------------------
1 | var onRun = function(context){
2 |
3 | function writeFile(filename, the_string) {
4 | var path =[@"" stringByAppendingString: filename];
5 | var str = [@"" stringByAppendingString: the_string];
6 | str.dataUsingEncoding_(NSUTF8StringEncoding).writeToFile_atomically_(path, true)
7 | }
8 |
9 | //var documentPath = "/" //[[doc fileURL] path].split([doc displayName] + ".sketch")[0];
10 |
11 | // GLOBAL
12 | var doc = context.document;
13 | var previzFolder = "/.previz";
14 | var path = NSHomeDirectory() + previzFolder;
15 | var artboardHeight = doc.currentPage().currentArtboard().frame().height();
16 | var artboardWidth = doc.currentPage().currentArtboard().frame().width();
17 |
18 | // PNG
19 | var currentArtboard = doc.currentPage().currentArtboard()
20 | var currentArtboardName = currentArtboard.name()
21 | var exportImageFilePath = path + "/" + currentArtboardName + ".png"
22 | [doc saveArtboardOrSlice:currentArtboard toFile:exportImageFilePath]
23 |
24 | // HTML
25 | var content = '\
26 | \
32 | \
33 | \
34 | \
35 |
\
36 | Zen Previz\
37 | \
50 | \
51 | \
52 | \
53 | \
54 | ';
55 |
56 | writeFile(path + "/previz.html", content);
57 |
58 | [doc showMessage: "Desktop Previz create" + path];
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/_versions/zenb.sketchplugin/Contents/Sketch/Preview/Preview-Artboard-Mobile.cocoascript:
--------------------------------------------------------------------------------
1 | var onRun = function(context){
2 |
3 | function writeFile(filename, the_string) {
4 | var path =[@"" stringByAppendingString: filename];
5 | var str = [@"" stringByAppendingString: the_string];
6 | str.dataUsingEncoding_(NSUTF8StringEncoding).writeToFile_atomically_(path, true)
7 | }
8 |
9 | //var documentPath = "/" //[[doc fileURL] path].split([doc displayName] + ".sketch")[0];
10 |
11 | // GLOBAL
12 | var doc = context.document;
13 | var previzFolder = "/.previz";
14 | var path = NSHomeDirectory() + previzFolder;
15 | var artboardHeight = doc.currentPage().currentArtboard().frame().height();
16 | var artboardWidth = doc.currentPage().currentArtboard().frame().width();
17 |
18 | // PNG
19 | var currentArtboard = doc.currentPage().currentArtboard()
20 | var currentArtboardName = currentArtboard.name()
21 | var exportImageFilePath = path + "/" + currentArtboardName + ".png"
22 | [doc saveArtboardOrSlice:currentArtboard toFile:exportImageFilePath]
23 |
24 | // HTML
25 | var content = '\
26 | \
27 | \
28 | Presentacion\
29 | \
39 | \
40 | \
41 | \
42 |

\
43 |
\
44 | \
45 | '
46 |
47 | writeFile(path + "/previz.html", content);
48 | [doc showMessage: "Mobile Previz create" + path];
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/_versions/zenb.sketchplugin/Contents/Sketch/Typography/ModularScale.cocoascript:
--------------------------------------------------------------------------------
1 | // Modular Scale
2 |
3 | var onRun = function(context) {
4 |
5 | @import '../sQuery/sQuery.js';
6 |
7 |
8 |
9 | };
10 |
11 |
--------------------------------------------------------------------------------
/_versions/zenb.sketchplugin/Contents/Sketch/_Wip/_Filter Shapes.cocoascript:
--------------------------------------------------------------------------------
1 | // Filter selection with shape layers
2 | // Set keyboard preferences (F2)
3 |
4 | @import "common.js"
5 |
6 | filterSelectionWithShapeLayers()
7 |
--------------------------------------------------------------------------------
/_versions/zenb.sketchplugin/Contents/Sketch/_Wip/_Filter Texts.cocoascript:
--------------------------------------------------------------------------------
1 | // Filter selection with text layers
2 | // Set keyboard preferences (F1)
3 |
4 | @import "common.js"
5 |
6 | filterSelectionWithTextLayers()
7 |
--------------------------------------------------------------------------------
/_versions/zenb.sketchplugin/Contents/Sketch/_Wip/_Fit Artobard Width.cocoascript:
--------------------------------------------------------------------------------
1 | // (alt cmd +)
2 | var layers = selection
3 |
4 | for (var i=0; i<[selection count]; ++i) {
5 |
6 | var layer = selection[i]
7 |
8 | if ([layer class] != "MSTextLayer" && [layer class] != "MSLayerGroup") {
9 | var frame = layer.frame()
10 | var parent = layer.parentGroup()
11 |
12 | frame.setX(0)
13 | frame.setWidth(parent.frame().width())
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/_versions/zenb.sketchplugin/Contents/Sketch/_Wip/_Fit Group Size.cocoascript:
--------------------------------------------------------------------------------
1 | // Resizes the selected groups to fit around all of its sub-layers
2 |
3 | var sel = context.selection
4 | var len = sel.length();
5 | var i;
6 |
7 | for(i=0;i 1) {
495 | _layers.push(this.layers[i]);
496 | }
497 | }
498 |
499 | this.layers = _layers.slice();
500 |
501 | return this;
502 | },
503 |
504 | /**
505 | * ...
506 | * @return {sQuery}
507 | */
508 |
509 | UISelect: function(){
510 | // Primero deseleccionamos todo
511 | doc.currentPage().deselectAllLayers();
512 | for(var i=0, len=this.layers.length; i= width ? n : new Array(width - n.length + 1).join(z) + n;
9 | }
10 |
11 | function iconNameRename(glyphName, withIconName) {
12 | withIconName = withIconName || false;
13 | var artboards = $("%artboards%");
14 | var iconName;
15 | //artboards.layers.reverse();
16 | artboards.each(function(idx) {
17 | if (withIconName) {
18 | fullIconName = glyphName + this.layers().array()[0].name();
19 | } else {
20 | fullIconName = glyphName + pad(idx, 3) + iconName;
21 | }
22 | this.name = fullIconName;
23 | log(this.name)
24 | });
25 | }
26 |
27 |
28 | function reorderArtboards(itemsPerFile, offset) {
29 | var artboards = $("%artboards%");
30 | var artboardWidth = 560;
31 | var artboardHeight = 560;
32 | var file = 0;
33 | var row = 0;
34 |
35 | //artboards.layers.reverse();
36 |
37 | for(j=0; j<(artboards.length); j++) {
38 | if(file>itemsPerFile-1) { row +=1; file=0; }
39 | artboards.layers[j].frame().x = (artboardWidth + offset) * file;
40 | artboards.layers[j].frame().y = (artboardHeight + offset) * row;
41 | file +=1;
42 | }
43 | }
44 |
45 |
46 | var CURRENTPAGE = context.document.currentPage();
47 | var CURRENTARTBOARD = context.document.currentPage().currentArtboard();
48 |
49 | $("%shapes%").each(function(){
50 |
51 | var artboard = $(CURRENTPAGE).createArtboard("newArtboard", 0, 0, 560, 560); // <- sQuery
52 | artboard.addLayers([this]);
53 | CURRENTARTBOARD.removeLayer(this);
54 | this.frame().x = (560-this.frame().width())/2;
55 | this.frame().y = (560-this.frame().height())/2;
56 |
57 | })
58 |
59 | CURRENTPAGE.removeLayer(CURRENTARTBOARD);
60 | reorderArtboards(10, 300);
61 | iconNameRename("", true);
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/_versions/zenc.sketchplugin/Contents/Sketch/Layers/Remove-Empty-Groups.cocoascript:
--------------------------------------------------------------------------------
1 | // Remove empty groups
2 | // @shortcut cmd e
3 | var onRun = function(context) {
4 | const selectedEmptyGroups = () => {
5 | const DOC = context.document;
6 | const PAGE = DOC.currentPage();
7 | const ARTBOARD = PAGE.currentArtboard();
8 | const allLayers = ARTBOARD.children().slice();
9 | const emptyGroups = allLayers.filter(layer => {
10 | try {
11 | return layer.layers().length === 0;
12 | } catch(e) { }
13 | });
14 | ARTBOARD.deselectAllLayers();
15 | emptyGroups.map(layer => layer.setIsSelected(true));
16 | };
17 | selectedEmptyGroups();
18 | };
19 |
--------------------------------------------------------------------------------
/_versions/zenc.sketchplugin/Contents/Sketch/Layers/Resize-Group-Area.cocoascript:
--------------------------------------------------------------------------------
1 | // Fit group bounding box size
2 |
3 | var onRun = function(context) {
4 | @import '../sQuery/sQuery.js';
5 | $("%groups%").each(function(){
6 | $(this).MSLayer().resizeRoot(1);
7 | });
8 | }
9 |
--------------------------------------------------------------------------------
/_versions/zenc.sketchplugin/Contents/Sketch/Layers/Send-To-Artboard.cocoascript:
--------------------------------------------------------------------------------
1 | var onRun = function(context) {
2 | const getArtboardFromLayer = layer => {
3 | let parent = layer.parentGroup()
4 | if(parent.class() == 'MSArtboardGroup') {
5 | artboard = parent
6 | } else {
7 | getArtboardFromLayer(parent)
8 | }
9 | return artboard
10 | }
11 |
12 | // Put a layer in Artboard root
13 | function parentToRoot(layer) {
14 | if (layer.parentGroup().class() != 'MSArtboardGroup') {
15 | // Get the artboard
16 | const artboard = getArtboardFromLayer(layer);
17 | const parent = layer.parentGroup();
18 | // Get layer absolute position
19 | const x = layer.absoluteRect().x() - artboard.absoluteRect().x();
20 | const y = layer.absoluteRect().y() - artboard.absoluteRect().y();
21 | // Parent to it
22 | artboard.addLayers([layer]);
23 | // Remove from previous parent
24 | parent.removeLayer(layer);
25 | // Position new layer
26 | layer.frame().setX(x);
27 | layer.frame().setY(y);
28 | }
29 | }
30 |
31 | context.selection.slice().map(layer => parentToRoot(layer))
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/_versions/zenc.sketchplugin/Contents/Sketch/Layers/Snap-Layer-To-Eight.cocoascript:
--------------------------------------------------------------------------------
1 | // Round Int near to 8 mult
2 | // Ej: 15 -> 16 or 25 -> 24
3 | function roundIntToGrid(v, n) {
4 | return Math.round((v/n))*n
5 | }
6 |
7 | // Set layer position (x,y) to eight pixel grid
8 | function snapToEight(layer) {
9 | pixelGrid = 8
10 | newX = roundIntToGrid([[layer frame] x], pixelGrid)
11 | newY = roundIntToGrid([[layer frame] y], pixelGrid)
12 | [[layer frame] setX:newX]
13 | [[layer frame] setY:newY]
14 | }
15 |
16 | // Do it!
17 | snapToEight(context.selection[0])
18 |
--------------------------------------------------------------------------------
/_versions/zenc.sketchplugin/Contents/Sketch/Layers/Toggle-Click-Throught.cocoascript:
--------------------------------------------------------------------------------
1 | // Toggle click throught
2 | // @shortcut cmd shift d
3 |
4 | var onRun = function(context) {
5 | @import '../sQuery/sQuery.js';
6 | $('%groups%').toggleClickThrought();
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/_versions/zenc.sketchplugin/Contents/Sketch/Layers/Toggle-User-Guides.cocoascript:
--------------------------------------------------------------------------------
1 | // Tootle User Guides Layer
2 | // @shortcut cmd l
3 |
4 | var onRun = function(context) {
5 | // Import sQuery
6 | @import '../sQuery/sQuery.js';
7 |
8 | // Toggle Guides layer visibility
9 | var guidesGroup = $('*').withName('Guides').MSLayer();
10 | guidesGroup.setIsVisible(!guidesGroup.isVisible());
11 |
12 | }
13 |
14 |
--------------------------------------------------------------------------------
/_versions/zenc.sketchplugin/Contents/Sketch/Layers/Transform-Each.cocoascript:
--------------------------------------------------------------------------------
1 | // Transform Each
2 |
3 | var onRun = function(context) {
4 |
5 | @import '../sQuery/sQuery.js';
6 |
7 | var size = context.document.askForUserInput_initialValue("Enter Size Multiplier", "100%");
8 | var re = /\d*\.*\d/;
9 | var pValue = (parseFloat(re.exec(size)[0]))/100;
10 |
11 | var x, y, w, h, frame;
12 | $('%selected%').each(function(){
13 |
14 | // Transform data
15 | frame = this.frame();
16 | x = frame.x();
17 | y = frame.y();
18 | w = frame.width();
19 | h = frame.height();
20 |
21 | // Moving and scaling
22 | frame.width = w*pValue;
23 | frame.height = h*pValue;
24 | frame.x = x+(w-(w*(pValue)))/2
25 | frame.y = y+(h-(h*(pValue)))/2
26 |
27 | });
28 |
29 | };
30 |
31 |
--------------------------------------------------------------------------------
/_versions/zenc.sketchplugin/Contents/Sketch/Layers/UnlockAllLayers.cocoascript:
--------------------------------------------------------------------------------
1 | var onRun = function(context) {
2 | @import '../sQuery/sQuery.js';
3 | $("*").unlock();
4 | }
5 |
--------------------------------------------------------------------------------
/_versions/zenc.sketchplugin/Contents/Sketch/Preview/Preview-Artboard-Desktop.cocoascript:
--------------------------------------------------------------------------------
1 | var onRun = function(context){
2 |
3 | function writeFile(filename, the_string) {
4 | var path =[@"" stringByAppendingString: filename];
5 | var str = [@"" stringByAppendingString: the_string];
6 | str.dataUsingEncoding_(NSUTF8StringEncoding).writeToFile_atomically_(path, true)
7 | }
8 |
9 | //var documentPath = "/" //[[doc fileURL] path].split([doc displayName] + ".sketch")[0];
10 |
11 | // GLOBAL
12 | var doc = context.document;
13 | var previzFolder = "/.previz";
14 | var path = NSHomeDirectory() + previzFolder;
15 | var artboardHeight = doc.currentPage().currentArtboard().frame().height();
16 | var artboardWidth = doc.currentPage().currentArtboard().frame().width();
17 |
18 | // PNG
19 | var currentArtboard = doc.currentPage().currentArtboard()
20 | var currentArtboardName = currentArtboard.name()
21 | var exportImageFilePath = path + "/" + currentArtboardName + ".png"
22 | [doc saveArtboardOrSlice:currentArtboard toFile:exportImageFilePath]
23 |
24 | // HTML
25 | var content = '\
26 | \
32 | \
33 | \
34 | \
35 | \
36 | Zen Previz\
37 | \
50 | \
51 | \
52 | \
53 | \
54 | ';
55 |
56 | writeFile(path + "/previz.html", content);
57 |
58 | [doc showMessage: "Desktop Previz create" + path];
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/_versions/zenc.sketchplugin/Contents/Sketch/Preview/Preview-Artboard-Mobile.cocoascript:
--------------------------------------------------------------------------------
1 | var onRun = function(context){
2 |
3 | function writeFile(filename, the_string) {
4 | var path =[@"" stringByAppendingString: filename];
5 | var str = [@"" stringByAppendingString: the_string];
6 | str.dataUsingEncoding_(NSUTF8StringEncoding).writeToFile_atomically_(path, true)
7 | }
8 |
9 | //var documentPath = "/" //[[doc fileURL] path].split([doc displayName] + ".sketch")[0];
10 |
11 | // GLOBAL
12 | var doc = context.document;
13 | var previzFolder = "/.previz";
14 | var path = NSHomeDirectory() + previzFolder;
15 | var artboardHeight = doc.currentPage().currentArtboard().frame().height();
16 | var artboardWidth = doc.currentPage().currentArtboard().frame().width();
17 |
18 | // PNG
19 | var currentArtboard = doc.currentPage().currentArtboard()
20 | var currentArtboardName = currentArtboard.name()
21 | var exportImageFilePath = path + "/" + currentArtboardName + ".png"
22 | [doc saveArtboardOrSlice:currentArtboard toFile:exportImageFilePath]
23 |
24 | // HTML
25 | var content = '\
26 | \
27 | \
28 | Presentacion\
29 | \
39 | \
40 | \
41 | \
42 |

\
43 |
\
44 | \
45 | '
46 |
47 | writeFile(path + "/previz.html", content);
48 | [doc showMessage: "Mobile Previz create" + path];
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/_versions/zenc.sketchplugin/Contents/Sketch/Typography/ModularScale.cocoascript:
--------------------------------------------------------------------------------
1 | // Modular Scale
2 |
3 | var onRun = function(context) {
4 |
5 | @import '../sQuery/sQuery.js';
6 |
7 |
8 |
9 | };
10 |
11 |
--------------------------------------------------------------------------------
/_versions/zenc.sketchplugin/Contents/Sketch/_Wip/_Filter Shapes.cocoascript:
--------------------------------------------------------------------------------
1 | // Filter selection with shape layers
2 | // Set keyboard preferences (F2)
3 |
4 | @import "common.js"
5 |
6 | filterSelectionWithShapeLayers()
7 |
--------------------------------------------------------------------------------
/_versions/zenc.sketchplugin/Contents/Sketch/_Wip/_Filter Texts.cocoascript:
--------------------------------------------------------------------------------
1 | // Filter selection with text layers
2 | // Set keyboard preferences (F1)
3 |
4 | @import "common.js"
5 |
6 | filterSelectionWithTextLayers()
7 |
--------------------------------------------------------------------------------
/_versions/zenc.sketchplugin/Contents/Sketch/_Wip/_Fit Artobard Width.cocoascript:
--------------------------------------------------------------------------------
1 | // (alt cmd +)
2 | var layers = selection
3 |
4 | for (var i=0; i<[selection count]; ++i) {
5 |
6 | var layer = selection[i]
7 |
8 | if ([layer class] != "MSTextLayer" && [layer class] != "MSLayerGroup") {
9 | var frame = layer.frame()
10 | var parent = layer.parentGroup()
11 |
12 | frame.setX(0)
13 | frame.setWidth(parent.frame().width())
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/_versions/zenc.sketchplugin/Contents/Sketch/_Wip/_Fit Group Size.cocoascript:
--------------------------------------------------------------------------------
1 | // Resizes the selected groups to fit around all of its sub-layers
2 |
3 | var sel = context.selection
4 | var len = sel.length();
5 | var i;
6 |
7 | for(i=0;i layer.class() == MSLayerGroup);
16 | return this;
17 | }
18 |
19 | }(sQuery));
20 |
--------------------------------------------------------------------------------
/_versions/zenc.sketchplugin/Contents/Sketch/sQuery/plugins/sQuery.areShapes.js:
--------------------------------------------------------------------------------
1 | /**
2 | * sQuery plugin - areShapes 1.0
3 | * Francis Vega
4 | *
5 | * @desc Filter elements and return just ShapeGroups
6 | * @return {sQuery}
7 | * @example
8 | * $('%selected%').areShapes().UISelect();
9 | * @desc Filter the selection (in Sketchapp UI) and make a selection only
10 | * with shape layers.
11 | */
12 |
13 | (function($){
14 |
15 | $.fn.areShapes = function() {
16 | this.layers = this.layers.slice().filter(layer => layer.class() == MSShapeGroup);
17 | return this;
18 | }
19 |
20 | }(sQuery));
21 |
--------------------------------------------------------------------------------
/_versions/zenc.sketchplugin/Contents/Sketch/sQuery/plugins/sQuery.move.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * sQuery plugin - move 1.0
4 | * Francis Vega
5 | *
6 | * @desc Move query layers
7 | * @param {object} coords
8 | * @param {object} coords.x Position x value
9 | * @param {object} coords.y Position y value
10 | * @return {sQuery}
11 | * @example
12 | * $('%selected%').move({"x":100, "y":234})
13 | * @desc Move "selected" layers by x100, y234
14 | */
15 |
16 | (function($){
17 | $.fn.move = function(coords, pixelFit = false) {
18 |
19 | let finalX, finalY;
20 |
21 | this.each(function() {
22 |
23 | if(pixelFit) {
24 | finalX = Math.round( this.absoluteRect().x() - this.parentRootForAbsoluteRect().rect().origin.x + coords.x );
25 | finalY = Math.round( this.absoluteRect().y() - this.parentRootForAbsoluteRect().rect().origin.y + coords.y );
26 | } else {
27 | finalX = this.absoluteRect().x() - this.parentRootForAbsoluteRect().rect().origin.x + coords.x;
28 | finalY = this.absoluteRect().y() - this.parentRootForAbsoluteRect().rect().origin.y + coords.y;
29 | }
30 |
31 | this.absoluteRect().x = finalX + this.parentRootForAbsoluteRect().rect().origin.x
32 | this.absoluteRect().y = finalY + this.parentRootForAbsoluteRect().rect().origin.y
33 |
34 | });
35 |
36 | return this;
37 |
38 | }
39 | }(sQuery));
40 |
--------------------------------------------------------------------------------
/_versions/zenc.sketchplugin/Contents/Sketch/sQuery/plugins/sQuery.sendToRoot.js:
--------------------------------------------------------------------------------
1 | /**
2 | * sQuery plugin - sendToRoot 1.0
3 | * Francis Vega
4 | *
5 | * @desc Send layers "back" to Artboard
6 | * @return {sQuery}
7 | * @example
8 | * $('%selected%').sendToRoot();
9 | */
10 |
11 | (function($) {
12 | $.fn.sendToRoot = function() {
13 | // For each query
14 | this.each(function() {
15 | const parent = this.parentGroup();
16 | if (parent.class() != MSArtboardGroup) {
17 | // Get the artboard
18 | const artboard = this.parentRootForAbsoluteRect();
19 | // Get this absolute position
20 | const x = this.absoluteRect().x() - artboard.absoluteRect().x();
21 | const y = this.absoluteRect().y() - artboard.absoluteRect().y();
22 | // Parent to it
23 | artboard.addLayers([this]);
24 | // Remove from previous parent
25 | parent.removeLayer(this);
26 | // Position new this
27 | this.frame().setX(x);
28 | this.frame().setY(y);
29 | }
30 | });
31 | return this;
32 | }
33 | }(sQuery));
34 |
--------------------------------------------------------------------------------
/_versions/zenc.sketchplugin/Contents/Sketch/sQuery/sQuery.js:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 | Copyright (c) 2017 Francis Vega
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
5 | associated documentation files (the "Software"), to deal in the Software without restriction,
6 | including without limitation the rights to use, copy, modify, merge, publish, distribute,
7 | sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this
11 | permission notice shall be included in all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
14 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
16 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18 | */
19 |
20 | /*
21 | *
22 | * sQuery 0.1
23 | *
24 | */
25 |
26 | let sQuery, $;
27 |
28 | (function(){
29 |
30 | sQuery = $ = (selector, page, artboard) => new SQUERY(selector, page, artboard)
31 |
32 | /**
33 | * findObjectsByName
34 | * @param {string} name The name of the object (layer)
35 | * @param {scope} scope The scope (layers) of search
36 | * @return {MSArray}
37 | */
38 | const findObjectsByName = (name, scope) => {
39 | const predicate = NSPredicate.predicateWithFormat("name == %@",name)
40 | return scope.filteredArrayUsingPredicate(predicate)
41 | }
42 |
43 | /**
44 | * findObjectsOfType
45 | * @param {string|classType} classType The name of the class type
46 | * @param {scope} scope The scope (layers) of search
47 | * @return {MSArray}
48 | */
49 | const findObjectsOfType = (classType, scope) => {
50 | const predicate = NSPredicate.predicateWithFormat("self isKindOfClass: %@", classType)
51 | return scope.filteredArrayUsingPredicate(predicate)
52 | }
53 |
54 | /**
55 | * flattenArray
56 | * @param {array} arr The array to flatten
57 | * @return {array} return a one level deep array
58 | */
59 | const flattenArray = arr => arr.reduce(
60 | (flat, toFlatten) => flat.concat(
61 | Array.isArray(toFlatten) ? flattenArray(toFlatten) : toFlatten), [])
62 |
63 | const SQUERY = function(selector, page, artboard) {
64 |
65 | if (typeof selector == "string") {
66 | switch(selector) {
67 | // All
68 | case "*":
69 | this.layers = context.document.currentPage().currentArtboard().children().slice().filter(layer => layer.class() != "MSArtboardGroup" && layer.class() != "MSRectangleShape")
70 | break
71 |
72 | case "%hierarchy%":
73 | this.layers = context.document.currentPage().currentArtboard().layers()
74 | break
75 |
76 | case "%pages%":
77 | this.layers = context.document.pages()
78 | break
79 |
80 | case "%artboards%":
81 | this.layers = context.document.currentPage().artboards()
82 | break
83 |
84 | case "%images%":
85 | this.layers = findObjectsOfType(MSBitmapLayer, context.document.currentPage().currentArtboard().children())
86 | break
87 |
88 | case "%layers%":
89 | this.layers = context.document.currentPage().currentArtboard().children().slice().filter(layer => layer.class() != "MSArtboardGroup" && layer.class() != "MSRectangleShape" && layer.class() != "MSLayerGroup")
90 | break
91 |
92 | case "%shapes%":
93 | this.layers = findObjectsOfType(MSShapeGroup, context.document.currentPage().currentArtboard().children())
94 | break
95 |
96 | case "%groups%":
97 | this.layers = findObjectsOfType(MSLayerGroup, context.document.currentPage().currentArtboard().children())
98 | break
99 |
100 | case "%textLayers%":
101 | this.layers = findObjectsOfType(MSTextLayer, context.document.currentPage().currentArtboard().children())
102 | break
103 |
104 | case "%selected%":
105 | this.layers = context.selection
106 | break
107 |
108 | // Default: Layer name.
109 | default:
110 | this.layers = findObjectsByName(selector, context.document.currentPage().currentArtboard().children())
111 | break
112 | }
113 | }
114 |
115 | if (typeof selector == "object") {
116 | this.layers = [selector]
117 | }
118 |
119 | return this
120 | }
121 |
122 | /* @sQuery API */
123 |
124 | sQuery.fn = SQUERY.prototype = {
125 |
126 | /**
127 | * Return an array with the queried layers
128 | * @return {array}
129 | */
130 | sLayers: function() {
131 | return this.layers
132 | },
133 |
134 | /**
135 | * Query text layers
136 | * @return {sQuery}
137 | */
138 | texts: function() {
139 | this.layers = this.layers.slice().filter(layer => layer.class() == MSTextLayer)
140 | return this
141 | },
142 |
143 | /**
144 | * Query groups
145 | * @return {sQuery}
146 | */
147 | groups: function() {
148 | this.layers = this.layers.slice().filter(layer => layer.class() == MSLayerGroup)
149 | return this
150 | },
151 |
152 | /**
153 | * Query pages
154 | * @return {sQuery}
155 | */
156 | pages: function() {
157 | this.layers = this.layers.slice().filter(layer => layer.class() == MSPage)
158 | return this
159 | },
160 |
161 | /**
162 | * Query artboards
163 | * @return {sQuery}
164 | */
165 | artboards: function() {
166 | this.layers = this.layers.slice().filter(layer => layer.class() == MSArtboardGroup)
167 | return this
168 | },
169 |
170 | /**
171 | * Query shape layers
172 | * @return {sQuery}
173 | */
174 | shapes: function() {
175 | this.layers = this.layers.slice().filter(layer => layer.class() == MSShapeGroup)
176 | return this
177 | },
178 |
179 | /**
180 | * images
181 | * @return {sQuery}
182 | */
183 | images: function() {
184 | this.layers = this.layers.slice().filter(layer => layer.class() == MSBitmapLayer)
185 | return this
186 | },
187 |
188 | /**
189 | * isLocked
190 | * @return {sQuery}
191 | */
192 | isLocked: function() {
193 | this.layers = this.layers.slice().filter(layer => layer.isLocked())
194 | return this
195 | },
196 |
197 | /**
198 | * startsWith
199 | * @param {string} str
200 | * @return {sQuery}
201 | */
202 | startsWith: function(str) {
203 | this.layers = this.layers.slice().filter(layer => layer.name().substr(0, str.length) == str)
204 | return this
205 | },
206 |
207 | /**
208 | * endsWith
209 | * @param {string} str
210 | * @return {sQuery}
211 | */
212 | endsWith: function(str) {
213 | this.layers = this.layers.slice().filter(layer => layer.name().substr(layer.name().length() - str.length) == str)
214 | return this
215 | },
216 |
217 | /**
218 | * contains
219 | * @param {string} str
220 | * @return {sQuery}
221 | */
222 | contains: function(str) {
223 | this.layers = this.layers.slice().filter(layer => layer.name().indexOf(str) != -1)
224 | return this
225 | },
226 |
227 | /**
228 | * withName
229 | * @param {string} name
230 | * @return {sQuery}
231 | */
232 | withName: function(name) {
233 | this.layers = this.layers.slice().filter(layer => layer.name() == name)
234 | return this
235 | },
236 |
237 | /**
238 | * childs
239 | * @return {sQuery}
240 | */
241 | childs: function() {
242 | this.layers = flattenArray(
243 | this.layers.slice().map(function(layer) {
244 | if (layer.class() == MSSymbolInstance) {
245 | const symbolMasterId = layer.symbolMaster().objectID()
246 | const symbolChilds = layer.symbolMaster().children().slice()
247 | const symbolChildsWithoutSymbolItself = symbolChilds.filter(symbolChildsLayer => symbolChildsLayer.objectID() != symbolMasterId)
248 | return symbolChildsWithoutSymbolItself
249 | } else {
250 | return layer.children().slice()
251 | }
252 | })
253 | )
254 | return this
255 | },
256 |
257 | /**
258 | * hasClickThrought
259 | * @return {sQuery}
260 | */
261 | hasClickThrought: function() {
262 | const groups = this.layers.slice().filter(layer => layer.class() == MSLayerGroup)
263 | this.layers = groups.filter(layer => layer.hasClickThrough())
264 | return this
265 | },
266 |
267 | /**
268 | * setHasClickThrough
269 | * @return {sQuery}
270 | */
271 | setHasClickThrough: function(status = false) {
272 | const groups = this.layers.slice().filter(layer => layer.class() == MSLayerGroup)
273 | groups.map(layer => layer.setHasClickThrough(status))
274 | return this
275 | },
276 |
277 | /**
278 | * toggleClickThrought
279 | * @return {sQuery}
280 | */
281 | toggleClickThrought: function() {
282 | const groups = this.layers.slice().filter(layer => layer.class() == MSLayerGroup)
283 | groups.map(layer => layer.setHasClickThrough(!layer.hasClickThrough()))
284 | return this
285 | },
286 |
287 | /**
288 | * isEmpty
289 | * @return {sQuery}
290 | */
291 | isEmpty: function() {
292 | const groups = this.layers.slice().filter(layer => layer.class() == MSLayerGroup)
293 | this.layers = groups.filter(layer => layer.layers().length === 0)
294 | return this
295 | },
296 |
297 | /**
298 | * isVisible
299 | * @return {sQuery}
300 | */
301 | isVisible: function() {
302 | this.layers = this.layers.slice().filter(layer => layer.isVisible() == 1)
303 | return this
304 | },
305 |
306 | /**
307 | * isHidden
308 | * @return {sQuery}
309 | */
310 | isHidden: function() {
311 | this.layers = this.layers.slice().filter(layer => layer.isVisible() == 0)
312 | return this
313 | },
314 |
315 | /**
316 | * visibility
317 | * @param {bool} status
318 | * @return {sQuery}
319 | */
320 | visibility: function(status) {
321 | this.layers.slice().map(layer => layer.setIsVisible(status))
322 | return this
323 | },
324 |
325 | /**
326 | * show
327 | * @return {sQuery}
328 | */
329 | show: function() {
330 | this.layers.slice().map(layer => layer.setIsVisible(true))
331 | return this
332 | },
333 |
334 | /**
335 | * hide
336 | * @return {sQuery}
337 | */
338 | hide: function() {
339 | this.layers.slice().map(layer => layer.setIsVisible(false))
340 | return this
341 | },
342 |
343 | /**
344 | * lock
345 | * @return {sQuery}
346 | */
347 | lock: function() {
348 | this.layers.slice().map(layer => layer.setIsLocked(true))
349 | return this
350 | },
351 |
352 | /**
353 | * unlock
354 | * @return {sQuery}
355 | */
356 | unlock: function() {
357 | this.layers.slice().map(layer => layer.setIsLocked(false))
358 | return this
359 | },
360 |
361 | /**
362 | * duplicate
363 | * @param {string} name
364 | * @return {sQuery}
365 | */
366 | duplicate: function(name) {
367 | const duplicateLayers = this.layers.slice().map(layer => layer.duplicate())
368 | duplicateLayers.map(layer => layer.name = name)
369 | this.layers = duplicateLayers
370 | return this
371 | },
372 |
373 | /**
374 | * remove
375 | * @return {sQuery}
376 | */
377 | remove: function() {
378 | this.layers.slice().map(layer => layer.removeFromParent())
379 | },
380 |
381 | /**
382 | * opacity
383 | * @param {number} val
384 | * @return {sQuery}
385 | */
386 | opacity: function(val) {
387 | if (val) {
388 | this.layers.slice().map(layer => layer.style().contextSettings().opacity = val / 100)
389 | } else {
390 | return this.layers.slice().map(layer => layer.style().contextSettings().opacity())
391 | }
392 | },
393 |
394 | /**
395 | * absolutePosition
396 | * @return {sQuery}
397 | */
398 | absolutePosition: function() {
399 | return this.layers.slice().map(layer => [layer.absoluteRect().x(), layer.absoluteRect().y()])
400 | },
401 |
402 | /**
403 | * relativePosition
404 | * @return {sQuery}
405 | */
406 | relativePosition: function() {
407 | return this.layers.slice().map(layer =>
408 | [
409 | layer.absoluteRect().x() - layer.parentRootForAbsoluteRect().rect().origin.x,
410 | layer.absoluteRect().y() - layer.parentRootForAbsoluteRect().rect().origin.y
411 | ]
412 | )
413 | },
414 |
415 | /**
416 | * rename
417 | * @param {string} name
418 | * @return {sQuery}
419 | */
420 | rename: function(name) {
421 | this.layers.slice().map(layer => layer.name = name)
422 | return this
423 | },
424 |
425 | /**
426 | * UISelect
427 | * @return {sQuery}
428 | */
429 | UISelect: function() {
430 | context.document.currentPage().deselectAllLayers()
431 | this.layers.slice().map(layer => layer.select_byExpandingSelection(true, true))
432 | return this
433 | },
434 |
435 | /**
436 | * Itera por cada uno de los elementos previamente seleccionados y devuelve el elemento.
437 | * @param {function} callback Una función a la que each llama por cada iteración.
438 | * @return {sQuery}
439 | */
440 | each: function(callback) {
441 | for(let i=0, len=this.layers.length; i
2 |
3 |
4 | -
5 |
6 |
7 | -
8 |
9 |
10 | -
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | //
2 | // ZEN Sketch Gulpfile
3 | // 2015
4 | //
5 |
6 | // Gulp itself
7 | var gulp = require('gulp');
8 |
9 | // Directorios del proyecto
10 | //
11 | var dirs = {
12 | src: '',
13 | dst: '/sketchplugins',
14 | };
15 |
16 | // Watch
17 | //
18 | gulp.task('watch', function(){
19 | gulp.watch(dirs.src + 'zen.sketchplugin/**/*', ['copy']);
20 | });
21 |
22 |
23 | // Copia los plugins en la carpeta de plugins de sketch mediante el softlink
24 | // /sketchplugins
25 | gulp.task('copy', function() {
26 | // Archivos en el raiz
27 | gulp.src(['zen.sketchplugin'], {cwd: dirs.src})
28 | .pipe(gulp.dest(dirs.dst));
29 | gulp.src(['zen.sketchplugin/**/*'], {cwd: dirs.src})
30 | .pipe(gulp.dest(dirs.dst + "/zen.sketchplugin"));
31 | });
32 |
33 | // TAREAS GULP
34 | gulp.task('default', ['watch']);
35 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "zen-sketch",
3 | "version": "1.0.0",
4 | "description": "A very personal collection of Sketch plugins",
5 | "main": "common.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/FrancisVega/ZEN-Sketch.git"
12 | },
13 | "author": "",
14 | "license": "ISC",
15 | "bugs": {
16 | "url": "https://github.com/FrancisVega/ZEN-Sketch/issues"
17 | },
18 | "homepage": "https://github.com/FrancisVega/ZEN-Sketch#readme",
19 | "devDependencies": {
20 | "gulp": "^3.9.0",
21 | "gulp-rename": "^1.2.2",
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/zen.sketchplugin/Contents/Sketch/Layers/Append-BEM.cocoascript:
--------------------------------------------------------------------------------
1 | // Append BEM
2 | // @shortcut alt cmd r
3 |
4 | var onRun = function(context) {
5 | @import '../sQuery/sQuery.js';
6 |
7 | $("%selected%").each(function(){
8 |
9 | var layer = $(this).MSLayer();
10 | var B = /^[^__]*/g.exec(layer.parentGroup().name())[0];
11 | var EM = /__.*/g.exec(layer.name());
12 | if (EM) {
13 | layer.name = B+EM;
14 | } else {
15 | layer.name = B+"__"+layer.name();
16 | }
17 |
18 | });
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/zen.sketchplugin/Contents/Sketch/Layers/Make-Font-Artboard-Icons.cocoascript:
--------------------------------------------------------------------------------
1 | var onRun = function(context) {
2 |
3 |
4 | @import '../sQuery/sQuery.js';
5 |
6 | const ICON_SIZE = 16;
7 |
8 | function pad(n, width, z) {
9 | z = z || '0';
10 | n = n + '';
11 | return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
12 | }
13 |
14 | function iconNameRename(glyphName, withIconName) {
15 | withIconName = withIconName || false;
16 | var artboards = $("%artboards%");
17 | var iconName;
18 | //artboards.layers.reverse();
19 | artboards.each(function(idx) {
20 | if (withIconName) {
21 | fullIconName = glyphName + this.layers()[0].name();
22 |
23 | } else {
24 | fullIconName = glyphName + pad(idx, 3) + iconName;
25 | }
26 | this.name = fullIconName;
27 | });
28 | }
29 |
30 |
31 | function reorderArtboards(itemsPerFile, offset) {
32 | var artboards = $("%artboards%");
33 | var artboardWidth = ICON_SIZE;
34 | var artboardHeight = ICON_SIZE;
35 | var file = 0;
36 | var row = 0;
37 | //artboards.layers.reverse();
38 | for(j=0; j<(artboards.layers.length); j++) {
39 | if(file>itemsPerFile-1) { row +=1; file=0; }
40 | artboards.layers[j].frame().x = (artboardWidth + offset) * file;
41 | artboards.layers[j].frame().y = (artboardHeight + offset) * row;
42 | file +=1;
43 | }
44 | }
45 |
46 |
47 | var CURRENTPAGE = context.document.currentPage();
48 | var CURRENTARTBOARD = context.document.currentPage().currentArtboard();
49 |
50 | $("%shapes%").each(function(){
51 |
52 | var artboard = $(CURRENTPAGE).createArtboard("newArtboard", 0, 0, ICON_SIZE, ICON_SIZE); // <- sQuery
53 | artboard.addLayers([this]);
54 | CURRENTARTBOARD.removeLayer(this);
55 | this.frame().x = (ICON_SIZE-this.frame().width())/2;
56 | this.frame().y = (ICON_SIZE-this.frame().height())/2;
57 |
58 | })
59 |
60 | CURRENTPAGE.removeLayer(CURRENTARTBOARD);
61 | reorderArtboards(10, 32);
62 | iconNameRename("", true);
63 |
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/zen.sketchplugin/Contents/Sketch/Layers/Remove-Empty-Groups.cocoascript:
--------------------------------------------------------------------------------
1 | // Remove empty groups
2 | // @shortcut cmd e
3 | var onRun = function(context) {
4 | const selectedEmptyGroups = () => {
5 | const DOC = context.document;
6 | const PAGE = DOC.currentPage();
7 | const ARTBOARD = PAGE.currentArtboard();
8 | const allLayers = ARTBOARD.children().slice();
9 | const emptyGroups = allLayers.filter(layer => {
10 | try {
11 | return layer.layers().length === 0;
12 | } catch(e) { }
13 | });
14 | ARTBOARD.deselectAllLayers();
15 | emptyGroups.map(layer => layer.setIsSelected(true));
16 | };
17 | selectedEmptyGroups();
18 | };
19 |
--------------------------------------------------------------------------------
/zen.sketchplugin/Contents/Sketch/Layers/Resize-Group-Area.cocoascript:
--------------------------------------------------------------------------------
1 | // Fit group bounding box size
2 |
3 | var onRun = function(context) {
4 | @import '../sQuery/sQuery.js';
5 | $("%groups%").each(function(){
6 | $(this).MSLayer().resizeRoot(1);
7 | });
8 | }
9 |
--------------------------------------------------------------------------------
/zen.sketchplugin/Contents/Sketch/Layers/Select-Childs-Layers.js:
--------------------------------------------------------------------------------
1 | // @format
2 | // Seleccionas las capas / grupos hijas
3 | // @shortcut alt cmd g
4 |
5 | var onRun = function(context) {
6 |
7 | const artboard = context.selection[0];
8 | artboard.select_byExpandingSelection(0, 0);
9 | artboard.layers().slice().map((layer) => layer.select_byExpandingSelection(true, true));
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/zen.sketchplugin/Contents/Sketch/Layers/Send-To-Artboard.cocoascript:
--------------------------------------------------------------------------------
1 | var onRun = function(context) {
2 | const getArtboardFromLayer = layer => {
3 | let parent = layer.parentGroup()
4 | if(parent.class() == 'MSArtboardGroup') {
5 | artboard = parent
6 | } else {
7 | getArtboardFromLayer(parent)
8 | }
9 | return artboard
10 | }
11 |
12 | // Put a layer in Artboard root
13 | function parentToRoot(layer) {
14 | if (layer.parentGroup().class() != 'MSArtboardGroup') {
15 | // Get the artboard
16 | const artboard = getArtboardFromLayer(layer);
17 | const parent = layer.parentGroup();
18 | // Get layer absolute position
19 | const x = layer.absoluteRect().x() - artboard.absoluteRect().x();
20 | const y = layer.absoluteRect().y() - artboard.absoluteRect().y();
21 | // Parent to it
22 | artboard.addLayers([layer]);
23 | // Remove from previous parent
24 | parent.removeLayer(layer);
25 | // Position new layer
26 | layer.frame().setX(x);
27 | layer.frame().setY(y);
28 | }
29 | }
30 |
31 | context.selection.slice().map(layer => parentToRoot(layer))
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/zen.sketchplugin/Contents/Sketch/Layers/Snap-Layer-To-Eight.cocoascript:
--------------------------------------------------------------------------------
1 | // Round Int near to 8 mult
2 | // Ej: 15 -> 16 or 25 -> 24
3 | function roundIntToGrid(v, n) {
4 | return Math.round((v/n))*n
5 | }
6 |
7 | // Set layer position (x,y) to eight pixel grid
8 | function snapToEight(layer) {
9 | pixelGrid = 8
10 | newX = roundIntToGrid([[layer frame] x], pixelGrid)
11 | newY = roundIntToGrid([[layer frame] y], pixelGrid)
12 | [[layer frame] setX:newX]
13 | [[layer frame] setY:newY]
14 | }
15 |
16 | // Do it!
17 | snapToEight(context.selection[0])
18 |
--------------------------------------------------------------------------------
/zen.sketchplugin/Contents/Sketch/Layers/Toggle-Click-Throught.cocoascript:
--------------------------------------------------------------------------------
1 | // Toggle click throught
2 | // @shortcut cmd shift d
3 |
4 | var onRun = function(context) {
5 | @import '../sQuery/sQuery.js';
6 | $('%groups%').toggleClickThrought();
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/zen.sketchplugin/Contents/Sketch/Layers/Toggle-User-Guides.cocoascript:
--------------------------------------------------------------------------------
1 | // Tootle User Guides Layer
2 | // @shortcut cmd l
3 |
4 | var onRun = function(context) {
5 | // Import sQuery
6 | @import '../sQuery/sQuery.js';
7 |
8 | // Toggle Guides layer visibility
9 | var guidesGroup = $('*').withName('Guides').MSLayer();
10 | guidesGroup.setIsVisible(!guidesGroup.isVisible());
11 |
12 | }
13 |
14 |
--------------------------------------------------------------------------------
/zen.sketchplugin/Contents/Sketch/Layers/Transform-Each.cocoascript:
--------------------------------------------------------------------------------
1 | // Transform Each
2 |
3 | var onRun = function(context) {
4 |
5 | @import '../sQuery/sQuery.js';
6 |
7 | var size = context.document.askForUserInput_initialValue("Enter Size Multiplier", "100%");
8 | var re = /\d*\.*\d/;
9 | var pValue = (parseFloat(re.exec(size)[0]))/100;
10 |
11 | var x, y, w, h, frame;
12 | $('%selected%').each(function(){
13 |
14 | // Transform data
15 | frame = this.frame();
16 | x = frame.x();
17 | y = frame.y();
18 | w = frame.width();
19 | h = frame.height();
20 |
21 | // Moving and scaling
22 | frame.width = w*pValue;
23 | frame.height = h*pValue;
24 | frame.x = x+(w-(w*(pValue)))/2
25 | frame.y = y+(h-(h*(pValue)))/2
26 |
27 | });
28 |
29 | };
30 |
31 |
--------------------------------------------------------------------------------
/zen.sketchplugin/Contents/Sketch/Layers/UnlockAllLayers.cocoascript:
--------------------------------------------------------------------------------
1 | var onRun = function(context) {
2 | @import '../sQuery/sQuery.js';
3 | $("*").unlock();
4 | }
5 |
--------------------------------------------------------------------------------
/zen.sketchplugin/Contents/Sketch/Preview/Preview-Artboard-Desktop.cocoascript:
--------------------------------------------------------------------------------
1 | var onRun = function(context) {
2 |
3 | @import "common-preview.js";
4 |
5 | const doc = context.document;
6 |
7 | const template = `
8 |
9 |
10 |
11 | Zen Previz - {{htmlName}}
12 |
26 |
27 |
28 |
33 |
34 | `;
35 |
36 | const exportTemplate = exportArboardsWithTemplate ( context.selection, template );
37 |
38 | if (exportTemplate) {
39 | [doc showMessage: "🖥 Desktop Previz"];
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/zen.sketchplugin/Contents/Sketch/Preview/Preview-Artboard-Mobile.cocoascript:
--------------------------------------------------------------------------------
1 | var onRun = function(context) {
2 |
3 | @import "common-preview.js";
4 |
5 | const doc = context.document;
6 |
7 | const template = `
8 |
9 |
10 |
11 | Zen Previz - {{htmlName}}
12 |
20 |
21 |
22 |
27 |
28 | `;
29 |
30 | const exportTemplate = exportArboardsWithTemplate ( context.selection, template );
31 |
32 | if (exportTemplate) {
33 | [doc showMessage: "📱 Mobile Previz"];
34 | }
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/zen.sketchplugin/Contents/Sketch/Preview/Preview-Artboard-Simple.cocoascript:
--------------------------------------------------------------------------------
1 | var onRun = function(context) {
2 |
3 | @import "common-preview.js";
4 |
5 | const doc = context.document;
6 |
7 | const template = `
8 |
9 |
10 |
11 | Zen Previz - {{htmlName}}
12 |
21 |
22 |
23 |
28 |
29 | `;
30 |
31 | const exportTemplate = exportArboardsWithTemplate ( context.selection, template );
32 | if (exportTemplate) {
33 | [doc showMessage: "🖥 Simple Previz"];
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/zen.sketchplugin/Contents/Sketch/Preview/Preview-Artboard-iphonex.cocoascript:
--------------------------------------------------------------------------------
1 | var onRun = function(context){
2 |
3 | function writeFile(filename, the_string) {
4 | var path =[@"" stringByAppendingString: filename];
5 | var str = [@"" stringByAppendingString: the_string];
6 | str.dataUsingEncoding_(NSUTF8StringEncoding).writeToFile_atomically_(path, true)
7 | }
8 |
9 | //var documentPath = "/" //[[doc fileURL] path].split([doc displayName] + ".sketch")[0];
10 |
11 | // GLOBAL
12 | var doc = context.document;
13 | var previzFolder = "/.previz";
14 | var path = NSHomeDirectory() + previzFolder;
15 | var artboardHeight = doc.currentPage().currentArtboard().frame().height();
16 | var artboardWidth = doc.currentPage().currentArtboard().frame().width();
17 |
18 | // PNG
19 | var currentArtboard = doc.currentPage().currentArtboard()
20 | var currentArtboardName = currentArtboard.name()
21 | var exportImageFilePath = path + "/" + currentArtboardName + ".png"
22 | [doc saveArtboardOrSlice:currentArtboard toFile:exportImageFilePath]
23 |
24 | // HTML
25 | var content = '\
26 | \
27 | \
28 | Presentacion\
29 | \
45 | \
46 | \
47 | \
48 | \
49 |

\
50 |
\
51 | \
52 | '
53 |
54 | writeFile(path + "/previz.html", content);
55 | [doc showMessage: "Mobile Previz create" + path];
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/zen.sketchplugin/Contents/Sketch/Preview/common-preview.js:
--------------------------------------------------------------------------------
1 | // Ordena un array de capas según su posición horizontal, de menor a mayor.
2 | // Función para la función sort().
3 | const sortByHorizontalPosition = (a, b) => a.frame().left() - b.frame().left();
4 |
5 | const writeFile = (filename, the_string) => {
6 | const path =[@"" stringByAppendingString: filename];
7 | const str = [@"" stringByAppendingString: the_string];
8 | str.dataUsingEncoding_(NSUTF8StringEncoding).writeToFile_atomically_(path, true)
9 | }
10 |
11 | // Get slice
12 | const getSlice = artboard => {
13 | const sliceLayerAncestry = MSImmutableLayerAncestry.ancestryWithMSLayer(artboard);
14 | const rect = MSSliceTrimming.trimmedRectForLayerAncestry(sliceLayerAncestry);
15 | const slices = MSExportRequest.exportRequestsFromExportableLayer_inRect_useIDForName(artboard, rect, false);
16 | return slices[0];
17 | }
18 |
19 | // Export slice
20 | const exportSlice = (doc, slice, filename) => {
21 | doc.saveArtboardOrSlice_toFile(slice, filename + "." + slice.format());
22 | }
23 |
24 | // Copy to clipboard
25 | function copyToPasteboard ( string ) {
26 | const pasteboard = NSPasteboard.generalPasteboard();
27 | pasteboard.clearContents();
28 | pasteboard.setString_forType( NSMutableString.stringWithString( string ), NSPasteboardTypeString );
29 | }
30 |
31 | const exportArboardsWithTemplate = ( artboards, template ) => {
32 |
33 | const previzFolder = "/.previz";
34 | const path = NSHomeDirectory() + previzFolder;
35 | copyToPasteboard(`${path}/previz.html` );
36 |
37 |
38 | let finalSelection;
39 | if (artboards.length == 1) {
40 | finalSelection = [context.document.currentPage().currentArtboard()];
41 | }
42 | if (artboards.length > 1) {
43 | finalSelection = artboards;
44 | }
45 | if (artboards.length < 1) {
46 | [doc showMessage: "💩 Select at least one artboard"];
47 | return false;
48 | }
49 |
50 | // Artboard
51 | finalSelection.slice().filter(ab => ab.class() == "MSArtboardGroup").sort(sortByHorizontalPosition)
52 | .map(function( artboard, idx, array ) {
53 | const artboardHeight = artboard.frame().height();
54 | const artboardWidth = artboard.frame().width();
55 | const currentArtboard = artboard;
56 | //const currentArtboardName = currentArtboard.name().replace(/[^a-zA-Z0-9]/g,'')
57 |
58 | if(idx == array.length - 1) {
59 | next = ""
60 | } else {
61 | next = idx + 1;
62 | }
63 |
64 | const htmlName = idx == 0 ? "previz.html" : "previz" + idx + ".html"
65 | const imageName = htmlName.split(".html")[0];
66 |
67 | // Export
68 | const exportImageFilePath = path + "/" + imageName;
69 | exportSlice( context.document, getSlice(currentArtboard), exportImageFilePath );
70 |
71 | const contentTemplate = template
72 | .replace(/{{htmlName}}/g, htmlName)
73 | .replace(/{{artboardWidth}}/g, artboardWidth + "px")
74 | .replace(/{{artboardHeight}}/g, artboardHeight + "px")
75 | .replace(/{{next}}/g, next)
76 | .replace(/{{imageName}}/g, imageName)
77 | .replace(/{{imageFormat}}/g, getSlice(currentArtboard).format())
78 |
79 | writeFile(`${path}/${htmlName}`, contentTemplate);
80 |
81 | }) // End Map
82 |
83 | return true;
84 | }
85 |
--------------------------------------------------------------------------------
/zen.sketchplugin/Contents/Sketch/Typography/ModularScale.cocoascript:
--------------------------------------------------------------------------------
1 | // Modular Scale
2 |
3 | var onRun = function(context) {
4 |
5 | @import '../sQuery/sQuery.js';
6 |
7 |
8 |
9 | };
10 |
11 |
--------------------------------------------------------------------------------
/zen.sketchplugin/Contents/Sketch/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Zen Sketch",
3 | "description": "A very personal plugin collection for Sketch",
4 | "author": "Francis Vega",
5 | "email": "hisconer@gmail.com",
6 | "homepage": "https://github.com/FrancisVega/ZEN-Sketch",
7 | "version": 1.2,
8 | "identifier": "com.example.sketch.zen",
9 | "compatibleVersion": "40",
10 | "bundleVersion": 1,
11 | "appcast": "https://raw.githubusercontent.com/FrancisVega/ZEN-Sketch/master/appcast.xml",
12 | "commands": [
13 | {
14 | "name": "Selec childs layers",
15 | "identifier": "selectChildsLayers",
16 | "handler": "onRun",
17 | "shortcut": "alt cmd g",
18 | "script": "Layers/Select-Childs-Layers.js"
19 | },
20 | {
21 | "name": "Unlock All Layers",
22 | "identifier": "unlockalllayers",
23 | "handler": "onRun",
24 | "shortcut": "",
25 | "script": "Layers/UnlockAllLayers.cocoascript"
26 | },
27 | {
28 | "name": "Transform Each",
29 | "identifier": "transformEach",
30 | "handler": "onRun",
31 | "shortcut": "alt cmd shift d",
32 | "script": "Layers/Transform-Each.cocoascript"
33 | },
34 | {
35 | "name": "Make font grid icons",
36 | "identifier": "makeFontGridIcons",
37 | "handler": "onRun",
38 | "shortcut": "",
39 | "script": "Layers/Make-Font-Artboard-Icons.cocoascript"
40 | },
41 | {
42 | "name": "Send to Artboard",
43 | "identifier": "sendToArtboard",
44 | "handler": "onRun",
45 | "shortcut": "",
46 | "script": "Layers/Send-To-Artboard.cocoascript"
47 | },
48 | {
49 | "name": "Append BEM",
50 | "identifier": "appendBEM",
51 | "handler": "onRun",
52 | "shortcut": "alt cmd r",
53 | "script": "Layers/Append-BEM.cocoascript"
54 | },
55 | {
56 | "name": "Remove Empty Groups",
57 | "identifier": "removeEmptyGroups",
58 | "handler": "onRun",
59 | "shortcut": "cmd e",
60 | "script": "Layers/Remove-Empty-Groups.cocoascript"
61 | },
62 | {
63 | "name": "Resize Group Area",
64 | "identifier": "resizeGroupArea",
65 | "handler": "onRun",
66 | "shortcut": "",
67 | "script": "Layers/Resize-Group-Area.cocoascript"
68 | },
69 | {
70 | "name": "Snap Layer To Eight",
71 | "identifier": "snapLayerToEight",
72 | "handler": "onRun",
73 | "shortcut": "",
74 | "script": "Layers/Snap-Layer-To-Eight.cocoascript"
75 | },
76 | {
77 | "name": "Togge Click Throught",
78 | "identifier": "toggleClickThrought",
79 | "handler": "onRun",
80 | "shortcut": "cmd shift d",
81 | "script": "Layers/Toggle-Click-Throught.cocoascript"
82 | },
83 | {
84 | "name": "Toggle User Guides",
85 | "identifier": "toggleUserGuides",
86 | "handler": "onRun",
87 | "shortcut": "cmd l",
88 | "script": "Layers/Toggle-User-Guides.cocoascript"
89 | },
90 | {
91 | "name": "Preview Artboard (iPhone X)",
92 | "identifier": "previewArtboardiphonex",
93 | "shortcut": "alt cmd x",
94 | "handler": "onRun",
95 | "script": "Preview/Preview-Artboard-iphonex.cocoascript"
96 | },
97 | {
98 | "name": "Preview Artboard (Simple)",
99 | "identifier": "previewArtboardSimple",
100 | "shortcut": "alt cmd l",
101 | "handler": "onRun",
102 | "script": "Preview/Preview-Artboard-Simple.cocoascript"
103 | },
104 | {
105 | "name": "Preview Artboard (Desktop)",
106 | "identifier": "previewArtboardDesktop",
107 | "shortcut": "alt cmd ´",
108 | "handler": "onRun",
109 | "script": "Preview/Preview-Artboard-Desktop.cocoascript"
110 | },
111 | {
112 | "name": "Preview Artboard (Mobile)",
113 | "identifier": "previewArtboardMobile",
114 | "shortcut": "alt cmd ñ",
115 | "handler": "onRun",
116 | "script": "Preview/Preview-Artboard-Mobile.cocoascript"
117 | },
118 | {
119 | "name": "Live Query",
120 | "identifier": "liveQuery",
121 | "shortcut": "cmd ¡",
122 | "handler": "onRun",
123 | "script": "sQuery/liveQuery/liveQuery.js"
124 | }
125 | ],
126 | "menu": {
127 | "isRoot": false,
128 | "items": [
129 | {
130 | "title":"Layers",
131 | "items":[
132 | "selectChildsLayers",
133 | "unlockalllayers",
134 | "makeFontGridIcons",
135 | "sendToArtboard",
136 | "transformEach",
137 | "removeEmptyGroups",
138 | "appendBEM",
139 | "resizeGroupArea",
140 | "snapLayerToEight",
141 | "toggleClickThrought",
142 | "toggleUserGuides"
143 | ]
144 | },
145 | {
146 | "title":"sQuery",
147 | "items":[
148 | "liveQuery"
149 | ]
150 | },
151 | {
152 | "title":"Preview",
153 | "items":[
154 | "previewArtboardSimple",
155 | "previewArtboardDesktop",
156 | "previewArtboardMobile"
157 | ]
158 | }
159 | ]
160 | }
161 | }
162 |
--------------------------------------------------------------------------------
/zen.sketchplugin/Contents/Sketch/sQuery/liveQuery.js:
--------------------------------------------------------------------------------
1 | // liveQuery
2 | // @shortcut cmd '
3 |
4 | var onRun = function(context) {
5 | @import '../sQuery/sQuery.js';
6 | @import '../sQuery/plugins/sQuery.areGroups.js';
7 | @import '../sQuery/plugins/sQuery.areShapes.js';
8 | @import '../sQuery/plugins/sQuery.move.js';
9 | @import '../sQuery/plugins/sQuery.parentRoot.js';
10 |
11 | var doc = context.document;
12 | var sq = [doc askForUserInput:"sQuery?" initialValue:"*"];
13 |
14 | var sel = context.selection;
15 |
16 | if (sel[0].class() == "MSArtboardGroup") {
17 |
18 | // Query
19 | if(sq == "*") {
20 | $("*").UISelect();
21 | }
22 |
23 | // Query
24 | if(sq == "t" || sq == "text" || sq == "textlayers") {
25 | $("%textLayers%").UISelect();
26 | }
27 |
28 | // Query
29 | if(sq == "v" || sq == "s" || sq == "shapes") {
30 | $("%shapes%").UISelect();
31 | }
32 |
33 | // Query
34 | if(sq == "h") {
35 | $("%hierarchy%").UISelect();
36 | }
37 |
38 | // Query
39 | if(sq == "g" || sq == "groups") {
40 | $("%groups%").UISelect();
41 | }
42 |
43 | // Query
44 | if(sq == "i" || sq == "images" || sq == "img" || sq == "imgs") {
45 | $("%images%").UISelect();
46 | }
47 |
48 | // Query
49 | if(sq == "l" || sq == "layers") {
50 | var shapes = $("%shapes%");
51 | var images = $("%images%");
52 | var text = $("%textLayers%");
53 | //$("*").areShapes().areImages().areTextLayers().UISelect();
54 | }
55 |
56 | } else {
57 |
58 | log("SELECCION")
59 | var SELECTED = $("%selected%");
60 |
61 | // Query
62 | if(sq == "*") { }
63 |
64 | // Query
65 | if(sq == "t" || sq == "text" || sq == "textlayers") {
66 | SELECTED.filter(function(){
67 | log("ok")
68 | return this.class() == "MSTextLayer";
69 | }).UISelect();
70 | }
71 |
72 | // Query
73 | if(sq == "v" || sq == "s" || sq == "shapes") {
74 | SELECTED.areShapes().UISelect();
75 | }
76 |
77 | // Query
78 | if(sq == "h") {
79 | $("%hierarchy%").UISelect();
80 | }
81 |
82 | // Query
83 | if(sq == "g" || sq == "groups") {
84 | $("%groups%").UISelect();
85 | }
86 |
87 | // Query
88 | if(sq == "i" || sq == "images" || sq == "img" || sq == "imgs") {
89 | $("%images%").UISelect();
90 | }
91 |
92 | // Query
93 | if(sq == "l" || sq == "layers") {
94 | var shapes = $("%shapes%");
95 | var images = $("%images%");
96 | var text = $("%textLayers%");
97 | //$("*").areShapes().areImages().areTextLayers().UISelect();
98 | }
99 |
100 | }
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/zen.sketchplugin/Contents/Sketch/sQuery/liveQuery/_liveQuery.js:
--------------------------------------------------------------------------------
1 | // liveQuery
2 | // @shortcut cmd '
3 |
4 | var onRun = function(context) {
5 | @import '../sQuery/sQuery.js';
6 | @import '../sQuery/plugins/sQuery.areGroups.js';
7 | @import '../sQuery/plugins/sQuery.areShapes.js';
8 | @import '../sQuery/plugins/sQuery.move.js';
9 | @import '../sQuery/plugins/sQuery.parentRoot.js';
10 | @import '../sQuery/plugins/sQuery.removeEmptyGroupsRecursive.js';
11 |
12 | var doc = context.document;
13 | var sq = [doc askForUserInput:"sQuery?" initialValue:"*"];
14 |
15 | var sel = context.selection;
16 |
17 | if (sel[0].class() == "MSArtboardGroup") {
18 |
19 | // Query
20 | if(sq == "*") {
21 | $("*").UISelect();
22 | }
23 |
24 | // Query
25 | if(sq == "t" || sq == "text" || sq == "textlayers") {
26 | $("%textLayers%").UISelect();
27 | }
28 |
29 | // Query
30 | if(sq == "v" || sq == "s" || sq == "shapes") {
31 | $("%shapes%").UISelect();
32 | }
33 |
34 | // Query
35 | if(sq == "h") {
36 | $("%hierarchy%").UISelect();
37 | }
38 |
39 | // Query
40 | if(sq == "g" || sq == "groups") {
41 | $("%groups%").UISelect();
42 | }
43 |
44 | // Query
45 | if(sq == "i" || sq == "images" || sq == "img" || sq == "imgs") {
46 | $("%images%").UISelect();
47 | }
48 |
49 | // Query
50 | if(sq == "l" || sq == "layers") {
51 | var shapes = $("%shapes%");
52 | var images = $("%images%");
53 | var text = $("%textLayers%");
54 | $("*").areShapes().areImages().areTextLayers().UISelect();
55 | }
56 |
57 | } else {
58 |
59 | log("SELECCION")
60 | var SELECTED = $("%selected%");
61 |
62 | // Query
63 | if(sq == "*") { }
64 |
65 | // Query
66 | if(sq == "t" || sq == "text" || sq == "textlayers") {
67 | SELECTED.filter(function(){
68 | log("ok")
69 | return this.class() == "MSTextLayer";
70 | }).UISelect();
71 | }
72 |
73 | // Query
74 | if(sq == "v" || sq == "s" || sq == "shapes") {
75 | SELECTED.areShapes().UISelect();
76 | }
77 |
78 | // Query
79 | if(sq == "h") {
80 | $("%hierarchy%").UISelect();
81 | }
82 |
83 | // Query
84 | if(sq == "g" || sq == "groups") {
85 | $("%groups%").UISelect();
86 | }
87 |
88 | // Query
89 | if(sq == "i" || sq == "images" || sq == "img" || sq == "imgs") {
90 | $("%images%").UISelect();
91 | }
92 |
93 | // Query
94 | if(sq == "l" || sq == "layers") {
95 | var shapes = $("%shapes%");
96 | var images = $("%images%");
97 | var text = $("%textLayers%");
98 | $("*").areShapes().areImages().areTextLayers().UISelect();
99 | }
100 |
101 | }
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/zen.sketchplugin/Contents/Sketch/sQuery/liveQuery/liveQuery.js:
--------------------------------------------------------------------------------
1 | // liveQuery
2 | // @shortcut cmd ¡
3 |
4 | var onRun = function(context) {
5 | @import '../sQuery.js';
6 |
7 | const doc = context.document;
8 | let sq = [doc askForUserInput:'sQuery?' initialValue:''].toLowerCase();
9 |
10 | switch (sq) {
11 | case '':
12 | case 'shapes':
13 | case 'shape':
14 | case 's':
15 | case 'l':
16 | case 'v':
17 | $('%selected%').filter(function() {
18 | return this.class() == 'MSShapeGroup';
19 | }).UISelect();
20 | break;
21 |
22 | case 'group':
23 | case 'groups':
24 | case 'g':
25 | $('%selected%').filter(function() {
26 | return this.class() == 'MSLayerGroup';
27 | }).UISelect();
28 | break;
29 |
30 | case 'text':
31 | case 'texts':
32 | case 't':
33 | $('%selected%').filter(function() {
34 | return this.class() == 'MSTextLayer';
35 | }).UISelect();
36 | break;
37 |
38 | case 'image':
39 | case 'images':
40 | case 'i':
41 | $('%selected%').filter(function() {
42 | return this.class() == 'MSBitmapLayer';
43 | }).UISelect();
44 | break;
45 |
46 | default:
47 | $('%selected%').filter(function() {
48 | return this.class() == 'MSShapeGroup';
49 | }).UISelect();
50 | break;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/zen.sketchplugin/Contents/Sketch/sQuery/plugins/sQuery.areGroups.js:
--------------------------------------------------------------------------------
1 | /**
2 | * sQuery plugin - areGroups 1.0
3 | * Francis Vega
4 | *
5 | * @desc Filter elements and return just LayerGroups
6 | * @return {sQuery}
7 | * @example
8 | * $('%selected%').areGroups().UISelect();
9 | * @desc Filter the selection (in Sketchapp UI) and make a selection only with groups.
10 | */
11 |
12 | (function($){
13 |
14 | $.fn.areGroups = function() {
15 | this.layers = this.layers.slice().filter(layer => layer.class() == MSLayerGroup);
16 | return this;
17 | }
18 |
19 | }(sQuery));
20 |
--------------------------------------------------------------------------------
/zen.sketchplugin/Contents/Sketch/sQuery/plugins/sQuery.areShapes.js:
--------------------------------------------------------------------------------
1 | /**
2 | * sQuery plugin - areShapes 1.0
3 | * Francis Vega
4 | *
5 | * @desc Filter elements and return just ShapeGroups
6 | * @return {sQuery}
7 | * @example
8 | * $('%selected%').areShapes().UISelect();
9 | * @desc Filter the selection (in Sketchapp UI) and make a selection only
10 | * with shape layers.
11 | */
12 |
13 | (function($){
14 |
15 | $.fn.areShapes = function() {
16 | this.layers = this.layers.slice().filter(layer => layer.class() == MSShapeGroup);
17 | return this;
18 | }
19 |
20 | }(sQuery));
21 |
--------------------------------------------------------------------------------
/zen.sketchplugin/Contents/Sketch/sQuery/plugins/sQuery.move.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * sQuery plugin - move 1.0
4 | * Francis Vega
5 | *
6 | * @desc Move query layers
7 | * @param {object} coords
8 | * @param {object} coords.x Position x value
9 | * @param {object} coords.y Position y value
10 | * @return {sQuery}
11 | * @example
12 | * $('%selected%').move({"x":100, "y":234})
13 | * @desc Move "selected" layers by x100, y234
14 | */
15 |
16 | (function($){
17 | $.fn.move = function(coords, pixelFit = false) {
18 |
19 | let finalX, finalY;
20 |
21 | this.each(function() {
22 |
23 | if(pixelFit) {
24 | finalX = Math.round( this.absoluteRect().x() - this.parentRootForAbsoluteRect().rect().origin.x + coords.x );
25 | finalY = Math.round( this.absoluteRect().y() - this.parentRootForAbsoluteRect().rect().origin.y + coords.y );
26 | } else {
27 | finalX = this.absoluteRect().x() - this.parentRootForAbsoluteRect().rect().origin.x + coords.x;
28 | finalY = this.absoluteRect().y() - this.parentRootForAbsoluteRect().rect().origin.y + coords.y;
29 | }
30 |
31 | this.absoluteRect().x = finalX + this.parentRootForAbsoluteRect().rect().origin.x
32 | this.absoluteRect().y = finalY + this.parentRootForAbsoluteRect().rect().origin.y
33 |
34 | });
35 |
36 | return this;
37 |
38 | }
39 | }(sQuery));
40 |
--------------------------------------------------------------------------------
/zen.sketchplugin/Contents/Sketch/sQuery/plugins/sQuery.sendToRoot.js:
--------------------------------------------------------------------------------
1 | /**
2 | * sQuery plugin - sendToRoot 1.0
3 | * Francis Vega
4 | *
5 | * @desc Send layers "back" to Artboard
6 | * @return {sQuery}
7 | * @example
8 | * $('%selected%').sendToRoot();
9 | */
10 |
11 | (function($) {
12 | $.fn.sendToRoot = function() {
13 | // For each query
14 | this.each(function() {
15 | const parent = this.parentGroup();
16 | if (parent.class() != MSArtboardGroup) {
17 | // Get the artboard
18 | const artboard = this.parentRootForAbsoluteRect();
19 | // Get this absolute position
20 | const x = this.absoluteRect().x() - artboard.absoluteRect().x();
21 | const y = this.absoluteRect().y() - artboard.absoluteRect().y();
22 | // Parent to it
23 | artboard.addLayers([this]);
24 | // Remove from previous parent
25 | parent.removeLayer(this);
26 | // Position new this
27 | this.frame().setX(x);
28 | this.frame().setY(y);
29 | }
30 | });
31 | return this;
32 | }
33 | }(sQuery));
34 |
--------------------------------------------------------------------------------
/zen.sketchplugin/Contents/Sketch/sQuery/sQuery.js:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 | Copyright (c) 2017 Francis Vega
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
5 | associated documentation files (the "Software"), to deal in the Software without restriction,
6 | including without limitation the rights to use, copy, modify, merge, publish, distribute,
7 | sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this
11 | permission notice shall be included in all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
14 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
16 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18 | */
19 |
20 | /*
21 | *
22 | * sQuery 0.1
23 | *
24 | */
25 |
26 | let sQuery, $;
27 |
28 | (function(){
29 |
30 | sQuery = $ = (selector, page, artboard) => new SQUERY(selector, page, artboard)
31 |
32 | /**
33 | * findObjectsByName
34 | * @param {string} name The name of the object (layer)
35 | * @param {scope} scope The scope (layers) of search
36 | * @return {MSArray}
37 | */
38 | const findObjectsByName = (name, scope) => {
39 | const predicate = NSPredicate.predicateWithFormat("name == %@", name)
40 | return scope.filteredArrayUsingPredicate(predicate)
41 | }
42 |
43 | /**
44 | * findObjectsOfType
45 | * @param {string|classType} classType The name of the class type
46 | * @param {scope} scope The scope (layers) of search
47 | * @return {MSArray}
48 | */
49 | const findObjectsOfType = (classType, scope) => scope.slice().filter(lyr => lyr.class() == classType)
50 |
51 | /**
52 | * flattenArray
53 | * @param {array} arr The array to flatten
54 | * @return {array} return a one level deep array
55 | */
56 | const flattenArray = arr => arr.reduce( (flat, toFlatten) =>
57 | flat.concat( Array.isArray(toFlatten) ? flattenArray(toFlatten) : toFlatten), []
58 | )
59 |
60 | const SQUERY = function(selector, page, artboard) {
61 |
62 | if (typeof selector == "string") {
63 |
64 | // Consts
65 | const DOC = context.document;
66 | const CURRENTPAGE = DOC.currentPage();
67 | const CURRENTARTBOARD = CURRENTPAGE.currentArtboard();
68 |
69 | switch(selector) {
70 | // All
71 | case "*":
72 | this.layers = CURRENTARTBOARD.children().slice().filter(layer => layer.class() != "MSArtboardGroup" && layer.class() != "MSRectangleShape")
73 | break
74 |
75 | case "%hierarchy%":
76 | this.layers = CURRENTARTBOARD.layers()
77 | break
78 |
79 | case "%pages%":
80 | this.layers = DOC.pages()
81 | break
82 |
83 | case "%artboards%":
84 | this.layers = CURRENTPAGE.artboards()
85 | break
86 |
87 | case "%images%":
88 | this.layers = findObjectsOfType(MSBitmapLayer, CURRENTARTBOARD.children())
89 | break
90 |
91 | case "%layers%":
92 | this.layers = CURRENTARTBOARD.children().slice().filter(layer => layer.class() != "MSArtboardGroup" && layer.class() != "MSRectangleShape" && layer.class() != "MSLayerGroup")
93 | break
94 |
95 | case "%shapes%":
96 | this.layers = findObjectsOfType(MSShapeGroup, CURRENTARTBOARD.children())
97 | break
98 |
99 | case "%groups%":
100 | this.layers = findObjectsOfType(MSLayerGroup, CURRENTARTBOARD.children())
101 | break
102 |
103 | case "%textLayers%":
104 | this.layers = findObjectsOfType(MSTextLayer, CURRENTARTBOARD.children())
105 | break
106 |
107 | case "%selected%":
108 | this.layers = context.selection
109 | break
110 |
111 | // Default: Layer name.
112 | default:
113 | this.layers = findObjectsByName(selector, CURRENTARTBOARD.children())
114 | break
115 | }
116 | }
117 |
118 | if (typeof selector == "object") {
119 | this.layers = [selector]
120 | }
121 |
122 | return this
123 | }
124 |
125 | /* @sQuery API */
126 |
127 | sQuery.fn = SQUERY.prototype = {
128 |
129 | /**
130 | * Return an array with the queried layers
131 | * @return {array}
132 | */
133 | sLayers: function() {
134 | return this.layers
135 | },
136 |
137 | /**
138 | * Query text layers
139 | * @return {sQuery}
140 | */
141 | texts: function() {
142 | this.layers = this.layers.slice().filter(layer => layer.class() == MSTextLayer)
143 | return this
144 | },
145 |
146 | /**
147 | * Query groups
148 | * @return {sQuery}
149 | */
150 | groups: function() {
151 | this.layers = this.layers.slice().filter(layer => layer.class() == MSLayerGroup)
152 | return this
153 | },
154 |
155 | /**
156 | * Query pages
157 | * @return {sQuery}
158 | */
159 | pages: function() {
160 | this.layers = this.layers.slice().filter(layer => layer.class() == MSPage)
161 | return this
162 | },
163 |
164 | /**
165 | * Query artboards
166 | * @return {sQuery}
167 | */
168 | artboards: function() {
169 | this.layers = this.layers.slice().filter(layer => layer.class() == MSArtboardGroup)
170 | return this
171 | },
172 |
173 | /**
174 | * Query shape layers
175 | * @return {sQuery}
176 | */
177 | shapes: function() {
178 | this.layers = this.layers.slice().filter(layer => layer.class() == MSShapeGroup)
179 | return this
180 | },
181 |
182 | /**
183 | * images
184 | * @return {sQuery}
185 | */
186 | images: function() {
187 | this.layers = this.layers.slice().filter(layer => layer.class() == MSBitmapLayer)
188 | return this
189 | },
190 |
191 | /**
192 | * isLocked
193 | * @return {sQuery}
194 | */
195 | isLocked: function() {
196 | this.layers = this.layers.slice().filter(layer => layer.isLocked())
197 | return this
198 | },
199 |
200 | /**
201 | * startsWith
202 | * @param {string} str
203 | * @return {sQuery}
204 | */
205 | startsWith: function(str) {
206 | this.layers = this.layers.slice().filter(layer => layer.name().substr(0, str.length) == str)
207 | return this
208 | },
209 |
210 | /**
211 | * endsWith
212 | * @param {string} str
213 | * @return {sQuery}
214 | */
215 | endsWith: function(str) {
216 | this.layers = this.layers.slice().filter(layer => layer.name().substr(layer.name().length() - str.length) == str)
217 | return this
218 | },
219 |
220 | /**
221 | * contains
222 | * @param {string} str
223 | * @return {sQuery}
224 | */
225 | contains: function(str) {
226 | this.layers = this.layers.slice().filter(layer => layer.name().indexOf(str) != -1)
227 | return this
228 | },
229 |
230 | /**
231 | * withName
232 | * @param {string} name
233 | * @return {sQuery}
234 | */
235 | withName: function(name) {
236 | this.layers = this.layers.slice().filter(layer => layer.name() == name)
237 | return this
238 | },
239 |
240 | /**
241 | * childs
242 | * @return {sQuery}
243 | */
244 | childs: function() {
245 | this.layers = flattenArray(
246 | this.layers.slice().map(function(layer) {
247 | if (layer.class() == MSSymbolInstance) {
248 | const symbolMasterId = layer.symbolMaster().objectID()
249 | const symbolChilds = layer.symbolMaster().children().slice()
250 | const symbolChildsWithoutSymbolItself = symbolChilds.filter(symbolChildsLayer => symbolChildsLayer.objectID() != symbolMasterId)
251 | return symbolChildsWithoutSymbolItself
252 | } else {
253 | return layer.children().slice()
254 | }
255 | })
256 | )
257 | return this
258 | },
259 |
260 | /**
261 | * hasClickThrought
262 | * @return {sQuery}
263 | */
264 | hasClickThrought: function() {
265 | const groups = this.layers.slice().filter(layer => layer.class() == MSLayerGroup)
266 | this.layers = groups.filter(layer => layer.hasClickThrough())
267 | return this
268 | },
269 |
270 | /**
271 | * setHasClickThrough
272 | * @return {sQuery}
273 | */
274 | setHasClickThrough: function(status = false) {
275 | const groups = this.layers.slice().filter(layer => layer.class() == MSLayerGroup)
276 | groups.map(layer => layer.setHasClickThrough(status))
277 | return this
278 | },
279 |
280 | /**
281 | * toggleClickThrought
282 | * @return {sQuery}
283 | */
284 | toggleClickThrought: function() {
285 | const groups = this.layers.slice().filter(layer => layer.class() == MSLayerGroup)
286 | groups.map(layer => layer.setHasClickThrough(!layer.hasClickThrough()))
287 | return this
288 | },
289 |
290 | /**
291 | * isEmpty
292 | * @return {sQuery}
293 | */
294 | isEmpty: function() {
295 | const groups = this.layers.slice().filter(layer => layer.class() == MSLayerGroup)
296 | this.layers = groups.filter(layer => layer.layers().length === 0)
297 | return this
298 | },
299 |
300 | /**
301 | * isVisible
302 | * @return {sQuery}
303 | */
304 | isVisible: function() {
305 | this.layers = this.layers.slice().filter(layer => layer.isVisible() == 1)
306 | return this
307 | },
308 |
309 | /**
310 | * isHidden
311 | * @return {sQuery}
312 | */
313 | isHidden: function() {
314 | this.layers = this.layers.slice().filter(layer => layer.isVisible() == 0)
315 | return this
316 | },
317 |
318 | /**
319 | * visibility
320 | * @param {bool} status
321 | * @return {sQuery}
322 | */
323 | visibility: function(status) {
324 | this.layers.slice().map(layer => layer.setIsVisible(status))
325 | return this
326 | },
327 |
328 | /**
329 | * show
330 | * @return {sQuery}
331 | */
332 | show: function() {
333 | this.layers.slice().map(layer => layer.setIsVisible(true))
334 | return this
335 | },
336 |
337 | /**
338 | * hide
339 | * @return {sQuery}
340 | */
341 | hide: function() {
342 | this.layers.slice().map(layer => layer.setIsVisible(false))
343 | return this
344 | },
345 |
346 | /**
347 | * lock
348 | * @return {sQuery}
349 | */
350 | lock: function() {
351 | this.layers.slice().map(layer => layer.setIsLocked(true))
352 | return this
353 | },
354 |
355 | /**
356 | * unlock
357 | * @return {sQuery}
358 | */
359 | unlock: function() {
360 | this.layers.slice().map(layer => layer.setIsLocked(false))
361 | return this
362 | },
363 |
364 | /**
365 | * duplicate
366 | * @param {string} name
367 | * @return {sQuery}
368 | */
369 | duplicate: function(name) {
370 | const duplicateLayers = this.layers.slice().map(layer => layer.duplicate())
371 | duplicateLayers.map(layer => layer.name = name)
372 | this.layers = duplicateLayers
373 | return this
374 | },
375 |
376 | /**
377 | * remove
378 | * @return {sQuery}
379 | */
380 | remove: function() {
381 | this.layers.slice().map(layer => layer.removeFromParent())
382 | },
383 |
384 | /**
385 | * opacity
386 | * @param {number} val
387 | * @return {sQuery}
388 | */
389 | opacity: function(val) {
390 | if (val) {
391 | this.layers.slice().map(layer => layer.style().contextSettings().opacity = val / 100)
392 | } else {
393 | return this.layers.slice().map(layer => layer.style().contextSettings().opacity())
394 | }
395 | },
396 |
397 | /**
398 | * absolutePosition
399 | * @return {sQuery}
400 | */
401 | absolutePosition: function() {
402 | return this.layers.slice().map(layer => [layer.absoluteRect().x(), layer.absoluteRect().y()])
403 | },
404 |
405 | /**
406 | * relativePosition
407 | * @return {sQuery}
408 | */
409 | relativePosition: function() {
410 | return this.layers.slice().map(layer =>
411 | [
412 | layer.absoluteRect().x() - layer.parentRootForAbsoluteRect().rect().origin.x,
413 | layer.absoluteRect().y() - layer.parentRootForAbsoluteRect().rect().origin.y
414 | ]
415 | )
416 | },
417 |
418 | /**
419 | * rename
420 | * @param {string} name
421 | * @return {sQuery}
422 | */
423 | rename: function(name) {
424 | this.layers.slice().map(layer => layer.name = name)
425 | return this
426 | },
427 |
428 | /**
429 | * UISelect
430 | * @return {sQuery}
431 | */
432 | UISelect: function() {
433 | context.selection[0].select_byExpandingSelection(0, 0)
434 | this.layers.slice().map(layer => layer.select_byExpandingSelection(true, true))
435 | return this
436 | },
437 |
438 | /**
439 | * Itera por cada uno de los elementos previamente seleccionados y devuelve el elemento.
440 | * @param {function} callback Una función a la que each llama por cada iteración.
441 | * @return {sQuery}
442 | */
443 | each: function(callback) {
444 | for(let i=0, len=this.layers.length; i