├── smartboards.sketchplugin
├── Contents
│ └── Sketch
│ │ ├── align.js
│ │ ├── align-and-rename.js
│ │ ├── manifest.json
│ │ ├── batch-custom-rename.js
│ │ └── common.js
└── appcast.xml
└── README.md
/smartboards.sketchplugin/Contents/Sketch/align.js:
--------------------------------------------------------------------------------
1 | // import common code
2 | @import "common.js"
3 |
4 | var onRun = function(context) {
5 | var shouldRename = false;
6 | align(context, shouldRename);
7 | var doc = context.document;
8 | [doc showMessage: 'Smartboards: Artboards aligned.'];
9 | };
10 |
--------------------------------------------------------------------------------
/smartboards.sketchplugin/Contents/Sketch/align-and-rename.js:
--------------------------------------------------------------------------------
1 | // import common code
2 | @import "common.js"
3 |
4 | var onRun = function(context) {
5 | var shouldRename = true;
6 | align(context, shouldRename);
7 | var doc = context.document;
8 | [doc showMessage: 'Smartboards: Artboards aligned and renamed.'];
9 | };
10 |
--------------------------------------------------------------------------------
/smartboards.sketchplugin/appcast.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Smartboards Sketch Plugin
5 | http://sparkle-project.org/files/sparkletestcast.xml
6 | Smartboards Sketch Plugin
7 | en
8 | -
9 | Version 1.1
10 |
11 |
13 | Support for mixed size artboards.
14 |
15 | ]]>
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/smartboards.sketchplugin/Contents/Sketch/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "author" : "Eli Horne",
3 | "description": "Plugin to make managing and exporting artboards easier in Sketch",
4 | "appcast": "https://raw.githubusercontent.com/elihorne/smartboards/master/appcast.xml",
5 | "version": "1.1",
6 | "commands" : [
7 | {
8 | "script" : "align.js",
9 | "handler" : "onRun",
10 | "shortcut" : "shift cmd alt G",
11 | "name" : "Align",
12 | "identifier" : "align"
13 | },
14 | {
15 | "script" : "align-and-rename.js",
16 | "handler" : "onRun",
17 | "shortcut" : "cmd alt G",
18 | "name" : "Align and Number",
19 | "identifier" : "align-and-rename"
20 | },
21 | {
22 | "script" : "batch-custom-rename.js",
23 | "handler" : "onRun",
24 | "shortcut" : "cmd alt R",
25 | "name" : "Rename Page Artboards",
26 | "identifier" : "customRename"
27 | }
28 | ],
29 | "identifier" : "com.elihorne.smartboards",
30 | "version" : "1.3",
31 | "homepage" : "https://github.com/elihorne/smartboards",
32 | "description" : "Align and rename artboards for easy organization.",
33 | "authorEmail" : "elihorne@gmail.com",
34 | "name" : "Smartboards"
35 | }
36 |
--------------------------------------------------------------------------------
/smartboards.sketchplugin/Contents/Sketch/batch-custom-rename.js:
--------------------------------------------------------------------------------
1 | // import common code
2 | @import "common.js"
3 |
4 | var onRun = function(context) {
5 |
6 | function createDialog() {
7 |
8 | var alert = COSAlertWindow.new();
9 |
10 | function createTextFieldWithLabel(label,defaultValue) {
11 | alert.addTextLabelWithValue(label);
12 | alert.addTextFieldWithValue(defaultValue);
13 | }
14 |
15 | alert.setMessageText("Rename Page Artboards");
16 | alert.setInformativeText("This will replace the existing names for all artboards on this page. Leave the field empty to remove custom names.");
17 |
18 | // Name
19 | createTextFieldWithLabel("Name:","");
20 |
21 | // Actions buttons.
22 | alert.addButtonWithTitle('OK');
23 | alert.addButtonWithTitle('Cancel');
24 |
25 | return alert;
26 | }
27 |
28 | var alert = createDialog();
29 | var result = alert.runModal();
30 | if (result == 1000) {
31 |
32 | var doc = context.document;
33 | var artboards = [[doc currentPage] artboards];
34 |
35 | for (var i = 0; i < artboards.count(); i++) {
36 | var artboardObject = artboards[i];
37 |
38 | var artboardName = artboardObject.name();
39 | var customRename = alert.viewAtIndex(1).stringValue();
40 |
41 |
42 | if(artboardPrefixRegex.test(artboardName)){
43 | var prefix = artboardName.split('_')[0];
44 | if(customRename.length() === 0) {
45 | log('empty string');
46 | artboardName = prefix;
47 | } else {
48 | artboardName = prefix + '_' + customRename;
49 | }
50 | } else {
51 | artboardName = alert.viewAtIndex(1).stringValue();
52 | }
53 | renameArtboard(artboardObject, artboardName);
54 | }
55 | } else {
56 | return;
57 | }
58 |
59 | };
60 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Smartboards aims to make managing and exporting artboards easier in Sketch.
2 | > Thanks to [xsaddi](https://github.com/xsaddi) for mixed artboard size support.
3 |
4 | # Installation
5 |
6 | #### Easiest Method
7 | Use the terrific [Sketch Toolbox](http://sketchtoolbox.com/). Just search for `Smartboards` and click "`Install`"
8 |
9 | #### Slightly Harder
10 | Download `Smartboards` [as a zip file](https://github.com/elihorne/smartboards/archive/master.zip) and then add the folder to your Sketch plugin folder.
11 |
12 | How to find your Sketch plugin folder: (In Sketch 3) choose `Plugins` > `Manage Plugins...` then click the cog icon near the bottom left corner, and select `Show Plugins Folder`.
13 |
14 | # Features
15 |
16 | #### Align and Rename
17 | > Shortcut: cmd + opt + g
18 |
19 | * Aligns artboards to a grid with `100px` gutters
20 | * Renames the artboards based on column (number) and row (letter) [`A00`, `A01`, `B00`, `B01`, `B02`]
21 | * Organizes the artboards in the layers list by row and column.
22 |
23 | 
24 |
25 | Notes: `Align` expects that artboards that are meant to be in the same row are top aligned on the same Y-axis value. It doesn't care about the X-axis value.
26 |
27 | There's a slightly hidden feature that I use a lot but is hard to describe. If you place an artboard in between two rows on the Y-axis and run `Align`, it will create room for a new row by shifting existing rows down by one, and then will rename accordingly. Imagine you have `Artboard 1` that is `10x10` at `Y = 1`, and `Artboard 2` that is `10x10` at `Y = 111`. If you place a third artboard where `1 < Y < 111`, `Align` will do the rest of the heavy lifting for you.
28 |
29 | 
30 |
31 | #### Align
32 | >Shortcut: shift + cmd + opt + g
33 |
34 | Aligns artboard to the same grid, but does not rename the artboards. Use this if you don't want your artboard names messed with. `Align and Rename` does its best to preserve custom artboard names, but sometimes you might not want it.
35 |
36 | #### Rename Page Artboards
37 |
38 | Allows you to specify a custom name for all artboards. If you have Column and Row indicators (ex: A00), these will be preserved.
39 |
40 | If you'd like to remove the custom naming from all artboards, just leave the input field empty.
41 |
--------------------------------------------------------------------------------
/smartboards.sketchplugin/Contents/Sketch/common.js:
--------------------------------------------------------------------------------
1 | var artboardPrefixRegex = /^[A-Z]{1,2}\d{2,3}\_/;
2 | var artboardPrefixOnly = /^[A-Z]{1,2}\d{2,3}$/;
3 |
4 | var renameArtboard = function(artboardObject, finalName) {
5 |
6 | [artboardObject setName:finalName];
7 | }
8 |
9 | var align = function(context, shouldRename) {
10 |
11 | // Organize artboards by row and column and rename for alphabetical sort.
12 |
13 | var doc = context.document;
14 |
15 | // options
16 | var PADDING = 100;
17 |
18 | // Get all the artboards on the current page.
19 | var artboards = [[doc currentPage] artboards];
20 | var page = [doc currentPage];
21 |
22 | // Variables to figure out the names (letter for row, number for column).
23 | var currentRow = -1;
24 | var currentColumn = -1;
25 | var lastTop = -10000000000000000000;
26 | var rowHeight = 0;
27 | var lastWidth = 0;
28 | var lastX = 0;
29 | var lastY = 0;
30 |
31 | // Set up the artboards object.
32 | var artboardsMeta = [];
33 |
34 | // Add artboard data to the object.
35 | for (var i = 0; i < artboards.count(); i++) {
36 | var artboard = artboards[i];
37 | var frame = artboard.frame();
38 | var artboardName = artboard.name();
39 | // run the name through the regex. If it matches, split and replace name with split result
40 |
41 | if(artboardPrefixRegex.test(artboardName)){
42 | artboardName = artboardName.split(artboardPrefixRegex)[1]
43 | };
44 |
45 | artboardsMeta.push({
46 | artboard: artboard,
47 | name: artboardName,
48 | width: frame.width(),
49 | height: frame.height(),
50 | left: frame.x(),
51 | top: frame.y()
52 | });
53 | }
54 |
55 | // Sort artboards by x and y position (grouping).
56 | artboardsMeta.sort(function(a, b) {
57 | if (a.top != b.top) {
58 | return a.top - b.top;
59 | }
60 | return a.left - b.left;
61 | });
62 |
63 | // artboard object with
64 | var artboardRows = [];
65 |
66 | // Align artboards to grid, assign names.
67 | for (var i = 0; i < artboardsMeta.length; ++i) {
68 | var obj = artboardsMeta[i];
69 | var artboard = obj.artboard;
70 | var height = obj.height;
71 | var width = obj.width;
72 | var name = obj.name;
73 | var newRow = 0;
74 | var oLeft = obj.left;
75 | var oTop = obj.top;
76 |
77 | var artboard = artboardsMeta[i];
78 | if (artboard.top > lastTop) {
79 | ++currentRow;
80 | currentColumn = 0;
81 | lastTop = artboard.top;
82 | newRow = 1;
83 | }
84 |
85 | if(shouldRename) {
86 | // Get the letter for the row
87 | if(currentRow <= 25) {
88 | var charCode = String.fromCharCode(65 + currentRow);
89 | }
90 |
91 | if(currentRow > 25) {
92 | var charCode = 'A' + String.fromCharCode(65 + parseInt(currentRow - 26));
93 | }
94 |
95 | // Get the zero based number for the column
96 | var formattedRow = currentColumn < 10 ? '0' + currentColumn : currentColumn;
97 |
98 |
99 | // Assemble the new artboard name -- test if name matches a generated prefix
100 | if(artboardPrefixOnly.test(name)){
101 | //if it does, just overwrite
102 | var finalName = charCode + formattedRow;
103 | } else {
104 | //otherwise add prefix to current name
105 | var finalName = charCode + formattedRow + '_' + name;
106 | };
107 |
108 | // finalName = lastY + "_" + rowHeight;
109 |
110 | artboardObject = artboard.artboard;
111 | renameArtboard(artboardObject, finalName);
112 | }
113 |
114 | //
115 | // LAYER POSITIONING
116 | //
117 |
118 | var artboardInternal = artboard.artboard;
119 | var frame = [artboardInternal frame];
120 | [frame setX: (currentColumn ? lastX + lastWidth + PADDING : 0)];
121 | [frame setY: (currentRow ? (newRow ? lastY + rowHeight + PADDING : lastY):0)];
122 |
123 | if ((height>rowHeight) || (newRow)) {
124 | rowHeight = height;
125 | }
126 |
127 | lastWidth = width;
128 | lastX = artboardInternal.frame().x();
129 | lastY = artboardInternal.frame().y();
130 |
131 | ++currentColumn;
132 | }
133 |
134 | //
135 | // LAYER ORDERING
136 | //
137 |
138 | // Sort artboards in the Layers List.
139 | var layersList = [];
140 | for (var i = 0; i < artboards.count(); i++) {
141 | var artboard = artboards[i];
142 | var name = artboard.name();
143 | layersList.push({
144 | artboard: artboard,
145 | name: name
146 | });
147 | }
148 |
149 | // Sort layers list by name.
150 | layersList.sort(function(a, b){
151 | if(a.name < b.name) {
152 | return 1
153 | }
154 | if(a.name > b.name) {
155 | return -1
156 | }
157 | return 0
158 | });
159 |
160 | // Helper function to add artboards.
161 | function addArtboard(page, artboard) {
162 | var frame = artboard.frame();
163 | frame.constrainProportions = false;
164 | page.addLayers([artboard]);
165 | return artboard;
166 | };
167 |
168 | // Helper function to remove artboards.
169 | function removeArtboardFromPage(page, name) {
170 | var theArtboard = null;
171 | var abs = page.artboards().objectEnumerator();
172 |
173 | while (a = abs.nextObject()) {
174 | if (a.name() == name) {
175 | page.removeLayer(a)
176 | break;
177 | }
178 | }
179 | }
180 |
181 | // Loop through the alphabetized items, remove the old ones and add the new ones.
182 | for (var i = 0; i < layersList.length; i++) {
183 | var artboard = layersList[i];
184 | removeArtboardFromPage(page, artboard.name)
185 | addArtboard(page, artboard.artboard);
186 | }
187 |
188 | };
189 |
--------------------------------------------------------------------------------