├── Name Artboards.sketchplugin └── Contents │ └── Sketch │ ├── Name Artboards.cocoascript │ ├── lib │ └── FBSettings.js │ └── manifest.json └── README.md /Name Artboards.sketchplugin/Contents/Sketch/Name Artboards.cocoascript: -------------------------------------------------------------------------------- 1 | @import './lib/FBSettings.js' 2 | 3 | var onRun = function(context) { 4 | var doc = context.document; 5 | 6 | const settings = FBSettings.pluginSettings((context.plugin).identifier(), "JTNameArtboards"); 7 | const kSettingsKeys = { 8 | "drawSlice": "drawSlice", 9 | "selectedOptionIndex": "selectedOptionIndex", 10 | } 11 | 12 | // initialize defaults 13 | if (!settings.getSetting(kSettingsKeys.drawSlice)) { 14 | settings.updateSetting(kSettingsKeys.drawSlice, true); 15 | } 16 | var options = ['.5x', '1x', '1.5x', '2x', '3x']; 17 | if (!settings.getSetting(kSettingsKeys.selectedOptionIndex)) { 18 | settings.updateSetting(kSettingsKeys.selectedOptionIndex, 3); // for 2x 19 | } 20 | 21 | log("========================= sketch-name-artboards log ========================="); 22 | var groupName = 'Artboard labels' 23 | var artboards = [[doc currentPage] artboards]; 24 | 25 | // Remove any previous existing 'Artboard labels' group 26 | allLayers = [[doc currentPage] layers]; 27 | for(var i=0; i< [allLayers count]; i++){ 28 | var layer = [allLayers objectAtIndex:i]; 29 | if ([layer name] == groupName) { 30 | [layer removeFromParent]; 31 | } 32 | } 33 | 34 | // Query resolution for appropriate font size and spacings, ask if slice should be drawn 35 | var choice = createSelect( 36 | 'What resolution are you working at?', 37 | options, 38 | settings.getSetting(kSettingsKeys.selectedOptionIndex), 39 | settings.getSetting(kSettingsKeys.drawSlice)); 40 | 41 | const selectedOptionIndex = choice[1]; 42 | if (selectedOptionIndex > -1) { 43 | settings.updateSetting(kSettingsKeys.selectedOptionIndex, selectedOptionIndex); 44 | } 45 | var scaleFactor = parseFloat(options[selectedOptionIndex]); 46 | log("Resolution: " + scaleFactor + "x"); 47 | 48 | var shouldDrawSlice = choice[2]; 49 | settings.updateSetting(kSettingsKeys.drawSlice, shouldDrawSlice); 50 | log("Should Draw Slice? " + shouldDrawSlice); 51 | 52 | if (choice[0] == NSAlertFirstButtonReturn) { 53 | // Name artboards 54 | 55 | // New group to hold labels 56 | var group = [[MSLayerGroup alloc] init]; 57 | [group setName: groupName] 58 | [[doc currentPage] addLayers:[group]]; 59 | 60 | if (shouldDrawSlice) { 61 | // Get bounds 62 | var contentBounds = context.document.currentPage().contentBounds() 63 | 64 | // Draw slice 65 | var slice = [MSSliceLayer new]; 66 | [slice setName: [doc displayName].split(".sketch")[0]]; 67 | var padding = 100 * scaleFactor; 68 | 69 | [[slice frame] setX: contentBounds.origin.x - padding]; 70 | [[slice frame] setY: contentBounds.origin.y - padding]; 71 | [[slice frame] setWidth: contentBounds.size.width + (padding * 2)]; 72 | [[slice frame] setHeight: contentBounds.size.height + (padding * 2)]; 73 | log(">> Drawing slice" ) 74 | 75 | [group addLayers:[slice]]; 76 | [slice select:true byExpandingSelection:false]; 77 | } 78 | 79 | var labels = []; 80 | const labelLineHeight = 16 * scaleFactor; 81 | const labelFontSize = 14 * scaleFactor; 82 | for(var i=0; i< [artboards count]; i++){ 83 | var artboard = artboards[i]; 84 | var artboardName = [artboard name]; 85 | 86 | // Create label and set properties 87 | var textLayer = [[MSTextLayer alloc] initWithFrame:CGRectMake( 88 | [[artboard frame] x] + (2 * scaleFactor), 89 | [[artboard frame] y] - labelLineHeight - (4 * scaleFactor), 90 | 0, 91 | labelLineHeight 92 | )]; 93 | [textLayer setName: artboardName]; 94 | [textLayer setStringValue: artboardName]; 95 | [textLayer setFontSize: labelFontSize]; 96 | [textLayer setFontPostscriptName: 'SF UI Text']; 97 | [textLayer setLineHeight: labelLineHeight]; 98 | 99 | var color = [MSImmutableColor colorWithRed:188/255 green:188/255 blue:188/255 alpha:1.0]; 100 | [textLayer setTextColor: color]; 101 | 102 | labels.push(textLayer); 103 | } 104 | 105 | [group addLayers:labels]; 106 | 107 | // Select each layer to make group the size of the layers within 108 | groupLayers = [group layers]; 109 | for(var i=0; i< [groupLayers count]; i++){ 110 | var layer = [groupLayers objectAtIndex:i]; 111 | [layer select:true byExtendingSelection:false]; 112 | } 113 | 114 | // Lock group 115 | [group setIsLocked:true]; 116 | [doc showMessage: [groupLayers count] + ' artboard labels created in "Artboard labels" group.']; 117 | } 118 | } 119 | 120 | // 121 | // Helpers 122 | // 123 | 124 | function createSelect(msg, items, selectedItemIndex, drawSlice){ 125 | selectedItemIndex = selectedItemIndex || 0; 126 | 127 | var accessory = [[NSView alloc] initWithFrame:NSMakeRect(0,0,200,62)]; 128 | 129 | var combobox = [[NSComboBox alloc] initWithFrame:NSMakeRect(0,37,200,25)]; 130 | [combobox addItemsWithObjectValues:items]; 131 | [combobox selectItemAtIndex:selectedItemIndex]; 132 | 133 | var checkbox = [[NSButton alloc] initWithFrame:NSMakeRect(0,0,200,25)]; 134 | [checkbox setButtonType:NSSwitchButton]; 135 | [checkbox setTitle:@"Draw Slice"]; 136 | if (drawSlice == true) { 137 | [checkbox setState:NSOnState]; 138 | } else { 139 | [checkbox setState:NSOffState]; 140 | } 141 | 142 | [accessory addSubview:checkbox]; 143 | [accessory addSubview:combobox]; 144 | 145 | var alert = [[NSAlert alloc] init]; 146 | [alert setMessageText:msg]; 147 | [alert addButtonWithTitle:'OK']; 148 | [alert addButtonWithTitle:'Cancel']; 149 | [alert setAccessoryView:accessory]; 150 | 151 | var responseCode = [alert runModal]; 152 | var combosel = [combobox indexOfSelectedItem]; 153 | if (!combosel) combosel = [combobox stringValue]; 154 | var checksel = [checkbox state] == NSOnState; 155 | 156 | return [responseCode, combosel, checksel]; 157 | } 158 | -------------------------------------------------------------------------------- /Name Artboards.sketchplugin/Contents/Sketch/lib/FBSettings.js: -------------------------------------------------------------------------------- 1 | // FBSettings 2 | // Settings class via NSUserDefaults 3 | 4 | // Usage 5 | // 1. Create an FBSettings instance using FBSettings.pluginSettings(pluginKey) 6 | // 2. Refer to it throughout your code for any settings you need within 7 | // via a settingsKey in updateSetting and getSetting 8 | 9 | const FBSettings = function(pluginIdentifier, pluginKey) { 10 | // PUBLIC 11 | // Updates/creates a setting for a settingsKey 12 | this.updateSetting = function(settingsKey, settingsValue) { 13 | var settings = getSettingsDict(); 14 | settings[settingsKey] = settingsValue; 15 | setUserDefault(pluginKey, settings); 16 | } 17 | 18 | // PUBLIC 19 | // Returns a setting for a settingsKey. Returns nil if it doesn't exist 20 | this.getSetting = function(settingsKey) { 21 | const settings = getSettingsDict(); 22 | return settings[settingsKey] ? settings[settingsKey] : nil; 23 | } 24 | 25 | // PRIVATE 26 | // Return a settings dictionary for the plugin. 27 | // Creates it if it doesn't exist. 28 | const getSettingsDict = function() { 29 | var settings = getUserDefault(pluginKey); 30 | if (settings) { 31 | // NSUserDefaults returns an immutable dict = need to copy it manually 32 | var mutableSettings = [[NSMutableDictionary alloc] init]; 33 | for(var key in settings) { 34 | mutableSettings[key] = settings[key]; 35 | } 36 | settings = mutableSettings; 37 | } else { 38 | // Create new settings dict 39 | settings = [[NSMutableDictionary alloc] init]; 40 | } 41 | 42 | return settings; 43 | } 44 | 45 | // PRIVATE 46 | // Returns a user default for the given key 47 | const getUserDefault = function(key) { 48 | const defaults = [NSUserDefaults standardUserDefaults]; 49 | const defaultValue = [defaults objectForKey:pluginIdentifier + '.' + key]; 50 | return defaultValue; 51 | } 52 | 53 | // PRIVATE 54 | // Sets a user default for the given key under the plugin identifier 55 | const setUserDefault = function(key, value) { 56 | const defaults = [NSUserDefaults standardUserDefaults]; 57 | const response = [defaults setObject: value forKey:pluginIdentifier + '.' + key]; 58 | [defaults synchronize]; 59 | return response; 60 | } 61 | } 62 | 63 | FBSettings.pluginSettings = function(pluginIdentifier, pluginKey) { 64 | return new FBSettings(pluginIdentifier, pluginKey); 65 | } -------------------------------------------------------------------------------- /Name Artboards.sketchplugin/Contents/Sketch/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Name Artboards", 3 | "description": "Create text layers for the names of all artboards, and optionally draws a slice around everything for easy export.", 4 | "author": "Julius Tarng", 5 | "homepage": "http://github.com/tarngerine/sketch-name-artboards", 6 | "version": 1.4, 7 | "identifier": "com.tarng.sketch-name-artboards", 8 | "updateURL": "https://github.com/tarngerine/sketch-name-artboards", 9 | "compatibleVersion": 39, 10 | "bundleVersion": 1, 11 | "commands": 12 | [ 13 | { 14 | "name": "Name Artboards", 15 | "identifier": "name-artboards", 16 | "shortcut": "ctrl cmd n", 17 | "script": "Name Artboards.cocoascript" 18 | }, 19 | ], 20 | "menu": 21 | { 22 | "isRoot": true, 23 | "items": 24 | [ 25 | "name-artboards" 26 | ] 27 | } 28 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | To install, "Download Zip" to the right, and double click the .sketchplugin file. 2 | 3 | ### Name Artboards and Draw Slice 4 | Goes through each artboard and creates a text label where the artboard name sits so it is visible when exporting with slices. It also draws a slice around all visible content (toggleable). 5 | ![Dialog prompt](http://cl.ly/image/1v0z3L1l2P2e/Image%202015-01-07%20at%203.43.50%20PM.png) 6 | ![Artboard labels group with slice](http://cl.ly/image/3t1R0i2M030e/Image%202015-01-07%20at%203.44.50%20PM.png) 7 | 8 | If you move / change artboard names, just re-run the plugin and it will replace the old 'Artboard labels' group with a new one! Careful not to have other groups with the same name — it will be erased. 9 | 10 | # Changelog 11 | [View releases](https://github.com/tarngerine/sketch-name-artboards/releases) 12 | --------------------------------------------------------------------------------