├── README.md ├── Screens └── ColorPalette.png ├── SharedColorPalette.sketchplugin └── Contents │ └── Sketch │ ├── ExportSharedColorPalette.js │ ├── ImportSharedColorPalette.js │ ├── common.js │ └── manifest.json └── Templates └── Colors.sketch /README.md: -------------------------------------------------------------------------------- 1 | Shared Color Palette for Sketch 2 | ================================== 3 | 4 | Keep your colors in sync across multiple documents by creating a system of JSON import/export. 5 | 6 | [Read about this plugin here](https://medium.com/@marianomike/the-beginners-guide-to-writing-sketch-plugins-part-7-creating-a-shared-color-palette-9c0a1899ee02#.ylmwnj1e9) 7 | 8 | 9 | ## Create a color palette using a Sketch document and Shared Styles: 10 | 11 | ![Color Palette](Screens/ColorPalette.png) 12 | 13 | [Download Sketch Template](https://github.com/marianomike/sketch-sharedcolorpalette/tree/master/Templates) 14 | 15 | 16 | ## From Sketch Color Palette file, export Shared Styles to a JSON file 17 | 18 | *`cmd` + `ctrl` + `shift` +* **`9`** 19 | 20 | 21 | ## In new document, import JSON file 22 | 23 | *`cmd` + `ctrl` + `shift` +* **`8`** 24 | 25 | 26 | 27 | ## Install 28 | 29 | Copy **`SharedColorPalette.sketchplugin`** to **Sketch** plugins folder. 30 | 31 | 32 | ## Author 33 | 34 | Mike Mariano 35 | 36 | Email: mike@uiuxartist.com 37 | 38 | Twitter: https://twitter.com/marianomike 39 | 40 | http://uiuxartist.com 41 | -------------------------------------------------------------------------------- /Screens/ColorPalette.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marianomike/sketch-sharedcolorpalette/88bca135c25c7921117668b327650a87888fc124/Screens/ColorPalette.png -------------------------------------------------------------------------------- /SharedColorPalette.sketchplugin/Contents/Sketch/ExportSharedColorPalette.js: -------------------------------------------------------------------------------- 1 | @import 'common.js' 2 | 3 | var onRun = function(context) { 4 | 5 | var sketch = context.api(); 6 | var doc = sketch.selectedDocument; 7 | 8 | //get the name of the document and remove the file extension if there is one 9 | var documentName = removeFileExtension(doc.sketchObject.displayName()); 10 | 11 | //reference the shared styles 12 | var sharedStyles = doc.sketchObject.documentData().layerStyles(); 13 | 14 | //reference the number of shared styles 15 | var numberOfSharedStyles = Number(sharedStyles.numberOfSharedStyles()); 16 | 17 | //allow json to be written to the folder 18 | var fileTypes = [NSArray arrayWithObjects:@"json", nil]; 19 | 20 | //create select folder window to save the file 21 | var panel = [NSSavePanel savePanel]; 22 | [panel setCanChooseDirectories:true]; 23 | [panel setCanCreateDirectories:true]; 24 | [panel setAllowedFileTypes:fileTypes]; 25 | [panel setNameFieldStringValue:documentName+".json"]; 26 | 27 | //the text on the button in the panel 28 | panel.setPrompt("Save Color Palette"); 29 | 30 | //check if Ok has been clicked 31 | if (panel.runModal()) { 32 | //create an array to hold the palette 33 | var paletteArray = []; 34 | 35 | for (var z = 0; z < numberOfSharedStyles; z++){ 36 | 37 | layerStyle = sharedStyles.objects().objectAtIndex(z); 38 | 39 | //convert variables to Strings for JSON export 40 | var colorName = String(layerStyle.name()); 41 | var colorHex = "#" + layerStyle.value().firstEnabledFill().color().immutableModelObject().hexValue(); 42 | 43 | //push this info into the palette array 44 | paletteArray.push({ 45 | name: colorName, 46 | value: colorHex, 47 | }) 48 | 49 | } 50 | //get the file path 51 | var file_path = panel.URL().path(); 52 | // Create the JSON object from paletteArray 53 | var jsonObj = { "Color Palette": paletteArray }; 54 | // Convert the object to a json string and format it 55 | var file = NSString.stringWithString(JSON.stringify(jsonObj, null, "\t")); 56 | // Save the file 57 | file.writeToFile_atomically_encoding_error(file_path, true, NSUTF8StringEncoding, null); 58 | 59 | var alertMessage = documentName+".json saved to: " + file_path; 60 | alert("Shared Color Palette JSON Exported!", alertMessage); 61 | } 62 | 63 | }; 64 | -------------------------------------------------------------------------------- /SharedColorPalette.sketchplugin/Contents/Sketch/ImportSharedColorPalette.js: -------------------------------------------------------------------------------- 1 | @import 'common.js' 2 | 3 | var onRun = function(context) { 4 | 5 | var sketch = context.api(); 6 | var doc = sketch.selectedDocument; 7 | 8 | var sharedStyles = doc.sketchObject.documentData().layerStyles(); 9 | var numberOfSharedStyles = Number(sharedStyles.numberOfSharedStyles()); 10 | 11 | //create array to hold existing styles for reference later 12 | var existingStyles = []; 13 | 14 | //if there are exisitng styles push them to array 15 | if(numberOfSharedStyles > 0){ 16 | for (var i = 0; i < sharedStyles.numberOfSharedStyles(); i++){ 17 | layerStyle = sharedStyles.objects().objectAtIndex(i); 18 | var styleName = String(layerStyle.name()); 19 | existingStyles.push(styleName); 20 | } 21 | } 22 | 23 | //create panel for user to select file 24 | var open = NSOpenPanel.openPanel(); 25 | var fileTypes = [NSArray arrayWithObjects:@"json",nil]; 26 | 27 | open.setAllowedFileTypes(fileTypes); 28 | open.setCanChooseDirectories(true); 29 | open.setCanChooseFiles(true); 30 | open.setCanCreateDirectories(true); 31 | open.setTitle("Import a Color Palette"); 32 | open.setPrompt("Import Palette"); 33 | open.runModal(); 34 | 35 | //impor the selected file and parse to JSON object 36 | var filePath = open.URLs().firstObject().path(); 37 | var fileContents = NSString.stringWithContentsOfFile(filePath); 38 | var paletteContents = JSON.parse(fileContents); 39 | 40 | //create array to hold JSON object for easy reference 41 | var palette = []; 42 | 43 | for(var x in paletteContents){ 44 | palette.push(paletteContents[x]); 45 | } 46 | 47 | updateSharedStyles(doc, sharedStyles, palette, existingStyles, filePath); 48 | 49 | } 50 | 51 | function updateSharedStyles(doc, sharedStyles, palette, existingStyles, filePath){ 52 | 53 | //create array for Document colors 54 | var documentColors = []; 55 | 56 | for(var i = 0; i < palette.length; i++){ 57 | 58 | for(var z = 0; z < palette[i].length; z++){ 59 | 60 | //get the values we need from the palette array 61 | var colorName = palette[i][z].name; 62 | var colorValue = palette[i][z].value; 63 | var colorExists = false; 64 | 65 | //if there are existing styles, check if they are the same as the ones imported 66 | if(existingStyles.length > 0){ 67 | var colorExists = checkIfExists(colorName, existingStyles); 68 | } 69 | 70 | //clear out the existing document colors 71 | doc.sketchObject.documentData().assets().setColors([]); 72 | 73 | //create a color variable out of the colorValue so we can add it to the color array 74 | var color = colorFromString(colorValue); 75 | documentColors.push(color); 76 | 77 | //set the documents colors with the imported colors 78 | doc.sketchObject.documentData().assets().setColors(documentColors); 79 | 80 | if(colorExists == false){ 81 | 82 | //create a new style with fill and add it to the shared styles list 83 | var style = MSStyle.alloc().init(); 84 | var fill = style.addStylePartOfType(0); 85 | fill.color = colorFromString(colorValue); 86 | sharedStyles.addSharedStyleWithName_firstInstance(colorName,style); 87 | 88 | } else { 89 | 90 | for (var k = 0; k < sharedStyles.numberOfSharedStyles(); k++){ 91 | 92 | var layerStyle = sharedStyles.objects().objectAtIndex(k); 93 | var styleName = String(layerStyle.name()); 94 | 95 | //checks if the name of the imported color is the same as the existing 96 | if(styleName == colorName){ 97 | 98 | var fill = layerStyle.value().fills().firstObject(); 99 | var oldFill = String("#" + fill.color().immutableModelObject().hexValue()); 100 | var styleIndex = k; 101 | 102 | //checks if the existing color value is different than the imported one 103 | if(oldFill != colorValue){ 104 | //change the fill color of the shared style 105 | fill.color = colorFromString(colorValue); 106 | //create a color to be added to the Document colors 107 | var color = colorFromString(colorValue); 108 | //reference the ID of the style to be able to update existing styles later 109 | var styleID = layerStyle.objectID(); 110 | //update all layers using this same ID 111 | updateAllExistingStyles(doc, styleID, sharedStyles, k); 112 | } 113 | } 114 | } 115 | } 116 | //refresh the inspector to show updates 117 | doc.sketchObject.reloadInspector(); 118 | } 119 | } 120 | //alert user import is complete 121 | var alertMessage = filePath+" imported!"; 122 | alert("Shared Color Palette Imported!", alertMessage); 123 | } 124 | 125 | function updateAllExistingStyles(doc, styleID, sharedStyles, index){ 126 | //reference the pages array in the document 127 | var pages = doc.sketchObject.pages(); 128 | 129 | for (var i = 0; i < pages.count(); i++){ 130 | //reference each page 131 | var page = pages[i]; 132 | //reference the artboards array of each page 133 | var artboards = [page artboards]; 134 | 135 | //loop through the artboards of each page 136 | for (var z = 0; z < artboards.count(); z++){ 137 | //reference each artboard of each page 138 | var artboard = artboards[z]; 139 | //reference the layers array of each artboard 140 | var layers = [artboard layers]; 141 | 142 | //loop through the layers array 143 | for(var k = 0; k < layers.count(); k++){ 144 | //reference each layer of each artboard 145 | var layer = layers[k]; 146 | //get the objectID of the shared style 147 | var objectID = layer.style().sharedObjectID(); 148 | //get the existing shared style 149 | var style = sharedStyles.objects().objectAtIndex(index); 150 | 151 | //check if the layer is using the older version of the shared style and refresh it with the new one 152 | if(objectID == styleID){ 153 | layer.setStyle(style.newInstance()); 154 | } 155 | } 156 | } 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /SharedColorPalette.sketchplugin/Contents/Sketch/common.js: -------------------------------------------------------------------------------- 1 | function rgbToHex(r, g, b) { 2 | return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); 3 | } 4 | 5 | function colorFromString(value) { 6 | var immutable = MSImmutableColor.colorWithSVGString_(value); 7 | return MSColor.alloc().initWithImmutableObject_(immutable); 8 | } 9 | 10 | function alert(title, message){ 11 | var app = [NSApplication sharedApplication]; 12 | [app displayDialog:message withTitle:title]; 13 | } 14 | 15 | function checkIfExists(colorName, existingStyles){ 16 | var existsArray = []; 17 | for (var i = 0; i < existingStyles.length; i++){ 18 | if(existingStyles[i] == colorName){ 19 | existsArray.push(colorName); 20 | } 21 | } 22 | 23 | if(existsArray.length > 0){ 24 | return true; 25 | }else{ 26 | return false; 27 | } 28 | } 29 | 30 | function createSelect(msg, items, selectedItemIndex){ 31 | selectedItemIndex = selectedItemIndex || 0 32 | 33 | var accessory = NSComboBox.alloc().initWithFrame(NSMakeRect(0,0,200,25)) 34 | accessory.addItemsWithObjectValues(items) 35 | accessory.selectItemAtIndex(selectedItemIndex) 36 | 37 | var alert = NSAlert.alloc().init() 38 | alert.setMessageText(msg) 39 | alert.addButtonWithTitle('OK') 40 | alert.addButtonWithTitle('Cancel') 41 | alert.setAccessoryView(accessory) 42 | 43 | var responseCode = alert.runModal() 44 | var sel = accessory.indexOfSelectedItem() 45 | 46 | return [responseCode, sel] 47 | } 48 | 49 | function removeFileExtension(layerName){ 50 | if([layerName containsString:@"."]){ 51 | var nameArray = [layerName componentsSeparatedByString:@"."]; 52 | var name = nameArray[0]; 53 | return name; 54 | }else{ 55 | return layerName; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /SharedColorPalette.sketchplugin/Contents/Sketch/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "Shared Color Palette", 3 | "identifier" : "com.marianomike.sharedcolorpalette", 4 | "version" : "1.2", 5 | "description" : "Share Color Palettes between Sketch Files.", 6 | "authorEmail" : "mike@uiuxartist.com", 7 | "author" : "Mike Mariano", 8 | 9 | "commands" : [ 10 | { 11 | "script" : "ExportSharedColorPalette.js", 12 | "handler" : "onRun", 13 | "shortcut" : "command ctrl shift 9", 14 | "name" : "Export Color Palette", 15 | "identifier" : "com.marianomike.sharedcolorpalette.export" 16 | }, 17 | { 18 | "script" : "ImportSharedColorPalette.js", 19 | "handler" : "onRun", 20 | "shortcut" : "command ctrl shift 8", 21 | "name" : "Import Color Palette", 22 | "identifier" : "com.marianomike.sharedcolorpalette.import" 23 | } 24 | ], 25 | } 26 | -------------------------------------------------------------------------------- /Templates/Colors.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marianomike/sketch-sharedcolorpalette/88bca135c25c7921117668b327650a87888fc124/Templates/Colors.sketch --------------------------------------------------------------------------------