├── Send to Channel....sketchplugin ├── Send to Group....sketchplugin ├── Send to Slackbot.sketchplugin ├── Send to User....sketchplugin ├── Update API Token.sketchplugin ├── api.js ├── readme.md └── utilities.js /Send to Channel....sketchplugin: -------------------------------------------------------------------------------- 1 | #import 'utilities.js' 2 | #import 'api.js' 3 | 4 | if (getActiveToken() == false) { 5 | requestAndSaveToken() 6 | } 7 | 8 | var channelNames = getChannelNames() 9 | var channelIDs = getChannelIDs() 10 | 11 | var choice = createSelect('Choose a channel...', channelNames, nil) 12 | 13 | if (choice != -1) { 14 | exportArtboardsAndSendTo(channelIDs[choice]) 15 | } 16 | -------------------------------------------------------------------------------- /Send to Group....sketchplugin: -------------------------------------------------------------------------------- 1 | #import 'utilities.js' 2 | #import 'api.js' 3 | 4 | if (getActiveToken() == false) { 5 | requestAndSaveToken() 6 | } 7 | 8 | var groupNames = getGroupNames() 9 | var groupIDs = getGroupIDs() 10 | var choice = createSelect('Choose a group...', groupNames, nil) 11 | 12 | if (choice != -1) { 13 | exportArtboardsAndSendTo(groupIDs[choice]) 14 | } 15 | -------------------------------------------------------------------------------- /Send to Slackbot.sketchplugin: -------------------------------------------------------------------------------- 1 | #import 'utilities.js' 2 | #import 'api.js' 3 | 4 | if (getActiveToken() == false) { 5 | requestAndSaveToken() 6 | } 7 | 8 | openIMAndSend("USLACKBOT") -------------------------------------------------------------------------------- /Send to User....sketchplugin: -------------------------------------------------------------------------------- 1 | #import 'utilities.js' 2 | #import 'api.js' 3 | 4 | if (getActiveToken() == false) { 5 | requestAndSaveToken() 6 | } 7 | 8 | var userNames = getUserNames() 9 | var userIDs = getUserIDs() 10 | var choice = createSelect('Choose a user...', userNames, nil) 11 | if (choice != -1) { 12 | var userID = userIDs[choice] 13 | openIMAndSend(userID) 14 | } 15 | -------------------------------------------------------------------------------- /Update API Token.sketchplugin: -------------------------------------------------------------------------------- 1 | #import 'utilities.js' 2 | #import 'api.js' 3 | 4 | requestAndSaveToken() 5 | -------------------------------------------------------------------------------- /api.js: -------------------------------------------------------------------------------- 1 | var rootURL = "https://slack.com/api/"; 2 | var tokenPath = NSHomeDirectory() + "/.slackToken" 3 | 4 | function requestAndSaveToken() { 5 | var token = [doc askForUserInput:"What is your API token? (https://api.slack.com/web)" initialValue:""] 6 | if (verifyAuth(token) == true) { 7 | var fileManager = NSFileManager.defaultManager() 8 | fileManager.createFileAtPath_contents_attributes(tokenPath, token, nil) 9 | } else { 10 | [doc showMessage:"Your Slack API token is invalid!"] 11 | } 12 | } 13 | 14 | function verifyAuth(token) { 15 | var response = getJSON(rootURL + "auth.test?token=" + token); 16 | if (response.ok == true) { 17 | [doc showMessage: "Logged in as " + response.user]; 18 | } 19 | return response.ok; 20 | } 21 | 22 | function getActiveToken() { 23 | var fileExists = NSFileManager.defaultManager().fileExistsAtPath(tokenPath); 24 | if (fileExists) { 25 | var token = NSString.stringWithContentsOfFile_encoding_error(tokenPath,NSUTF8StringEncoding,nil) 26 | return token 27 | } else { 28 | return false; 29 | } 30 | } 31 | 32 | function getUserNames() { 33 | var token = getActiveToken(); 34 | var response = getJSON(rootURL + "users.list?token=" + token); 35 | var userNames = []; 36 | for (var i = 0; i < response.members.count(); i++) { 37 | var user = response.members[i] 38 | userNames.push(user.name + " (" + user.real_name + ")") 39 | } 40 | return userNames; 41 | } 42 | 43 | function getUserIDs() { 44 | var token = getActiveToken(); 45 | var response = getJSON(rootURL + "users.list?token=" + token); 46 | var userIDs = []; 47 | for (var i = 0; i < response.members.count(); i++) { 48 | var user = response.members[i] 49 | userIDs.push(user.id) 50 | } 51 | return userIDs; 52 | } 53 | 54 | function openIMAndSend(userID) { 55 | var token = getActiveToken(); 56 | var response = getJSON(rootURL + "im.open?token=" + token + "&user=" + userID); 57 | exportArtboardsAndSendTo(response.channel.id) 58 | } 59 | 60 | function getChannelNames() { 61 | var token = getActiveToken(); 62 | var response = getJSON(rootURL + "channels.list?token=" + token + "&exclude_archived=1"); 63 | var activeMemberships = []; 64 | for (var i = 0; i < response.channels.count(); i++) { 65 | if (response.channels[i].is_member == true) { 66 | var channel = response.channels[i] 67 | activeMemberships.push("#" + channel.name) 68 | } 69 | } 70 | return activeMemberships; 71 | } 72 | 73 | function getChannelIDs() { 74 | var token = getActiveToken(); 75 | var response = getJSON(rootURL + "channels.list?token=" + token + "&exclude_archived=1"); 76 | var activeMemberships = []; 77 | for (var i = 0; i < response.channels.count(); i++) { 78 | if (response.channels[i].is_member == true) { 79 | var channel = response.channels[i] 80 | activeMemberships.push(channel.id) 81 | } 82 | } 83 | return activeMemberships; 84 | } 85 | 86 | function getGroupNames() { 87 | var token = getActiveToken(); 88 | var response = getJSON(rootURL + "groups.list?token=" + token + "&exclude_archived=1"); 89 | var groups = []; 90 | for (var i = 0; i < response.groups.count(); i++) { 91 | var group = response.groups[i]; 92 | groups.push(group.name); 93 | } 94 | return groups; 95 | } 96 | 97 | function getGroupIDs() { 98 | var token = getActiveToken(); 99 | var response = getJSON(rootURL + "groups.list?token=" + token + "&exclude_archived=1"); 100 | var groups = []; 101 | for (var i = 0; i < response.groups.count(); i++) { 102 | var group = response.groups[i]; 103 | groups.push(group.id); 104 | } 105 | return groups; 106 | } 107 | 108 | 109 | function exportArtboardsAndSendTo(recipient) { 110 | var loop = [selection objectEnumerator] 111 | while (item = [loop nextObject]) { 112 | if (item.className() == "MSArtboardGroup") { 113 | var path = NSTemporaryDirectory() + item.name() + ".png" 114 | [doc saveArtboardOrSlice:item toFile: path]; 115 | postFile(path, recipient) 116 | } 117 | } 118 | } 119 | 120 | function postFile(path, recipient) { 121 | var task = NSTask.alloc().init() 122 | task.setLaunchPath("/usr/bin/curl"); 123 | var args = NSArray.arrayWithObjects("-F", "token=" + getActiveToken(), "-F", "file=@" + path, "-F", "channels=" + recipient, "https://slack.com/api/files.upload", nil); 124 | task.setArguments(args); 125 | task.launch(); 126 | } 127 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Send to Slack 2 | 3 | A simple plugin for [Sketch.app](http://bohemiancoding.com/sketch/) to directly share artboards to specific Slack groups, channels, or users. 4 | 5 | ## Installation 6 | 1. [Download Sketch Toolbox](http://sketchtoolbox.com) 7 | 2. Search for Send to Slack, click install. 8 | 3. Grab your API token from https://api.slack.com/web. 9 | 4. Go to Sketch->Plugins->Send to Slack->Update API token and paste in your API token. 10 | 11 | ## Usage 12 | 1. Select any number of artboards. 13 | 2. Go to Sketch->Plugins->Send to Slack and choose whether you want to share to a group or a channel. 14 | 3. Select the appropriate group/channel. 15 | 4. That's it! 16 | 17 | ![Usage](https://cldup.com/qNznqoP5aJ.gif) 18 | 19 | ## Known Issues / What's Next 20 | 1. I'm looking into what else can be shared besides just artboards. If you have any suggestions, open an issue! 21 | 22 | ## Feedback 23 | If you have any feedback of any kind, I'm most easily reachable on Twitter [@shahruz](https://twitter.com/shahruz). 24 | -------------------------------------------------------------------------------- /utilities.js: -------------------------------------------------------------------------------- 1 | function getJSON(url) { 2 | var request = NSURLRequest.requestWithURL(NSURL.URLWithString(url)); 3 | var response = NSURLConnection.sendSynchronousRequest_returningResponse_error(request, null, null); 4 | var responseObject = [NSJSONSerialization JSONObjectWithData: response options: nil error: nil]; 5 | return responseObject; 6 | } 7 | 8 | function createSelect(msg, items, selectedItemIndex){ 9 | selectedItemIndex = selectedItemIndex || 0 10 | 11 | var accessory = [[NSComboBox alloc] initWithFrame:NSMakeRect(0,0,200,25)] 12 | [accessory setCompletes:true] 13 | [accessory addItemsWithObjectValues:items] 14 | [accessory selectItemAtIndex:selectedItemIndex] 15 | 16 | var alert = [[NSAlert alloc] init] 17 | [alert setMessageText:msg] 18 | [alert addButtonWithTitle:'OK'] 19 | [alert addButtonWithTitle:'Cancel'] 20 | [alert setAccessoryView:accessory] 21 | 22 | var responseCode = [alert runModal] 23 | if (responseCode == 1000) { 24 | var sel = [accessory indexOfSelectedItem] 25 | return sel 26 | } else { 27 | return -1 28 | } 29 | } 30 | --------------------------------------------------------------------------------