├── .gitignore ├── README.md ├── assets └── icon.png ├── package-lock.json ├── package.json ├── sketch-tokenizer.sketchplugin └── Contents │ ├── Resources │ └── icon.png │ └── Sketch │ ├── get-base-border-color.js │ ├── get-base-border-color.js.map │ ├── get-base-fill-color.js │ ├── get-base-fill-color.js.map │ ├── get-border-color.js │ ├── get-border-color.js.map │ ├── get-color-variable.js │ ├── get-color-variable.js.map │ ├── get-fill-color.js │ ├── get-fill-color.js.map │ ├── get-token-background-color-input.js │ ├── get-token-background-color-input.js.map │ ├── get-token-border-color-input.js │ ├── get-token-border-color-input.js.map │ ├── import-base-colors-decisions-file.js │ ├── import-base-colors-decisions-file.js.map │ ├── import-base-colors.js │ ├── import-base-colors.js.map │ ├── import-decisions-file.js │ ├── import-decisions-file.js.map │ ├── import-token-backgrounds-decisions-file.js │ ├── import-token-backgrounds-decisions-file.js.map │ ├── import-token-borders-decisions-file.js │ ├── import-token-borders-decisions-file.js.map │ ├── manifest.json │ ├── my-command.js │ └── my-command.js.map └── src ├── border-color.js ├── converters └── colors.js ├── decisions ├── backgrounds.json ├── base-colors.json └── borders.json ├── example.sketch ├── manifest.json ├── menu-identify ├── base-colors │ ├── get-base-border-color.js │ └── get-base-fill-color.js └── tokens │ ├── background │ └── get-token-background-color-input.js │ └── border │ └── get-token-border-color-input.js ├── menu-import ├── import-base-colors-decisions-file.js ├── import-token-backgrounds-decisions-file.js └── import-token-borders-decisions-file.js └── utils.js /.gitignore: -------------------------------------------------------------------------------- 1 | # build artifacts 2 | plugin.sketchplugin 3 | 4 | # npm 5 | node_modules 6 | .npm 7 | npm-debug.log 8 | 9 | # mac 10 | .DS_Store 11 | 12 | # WebStorm 13 | .idea 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sketch-tokenizer 2 | 3 | 4 | 5 | > Maps your hardcoded colors values to actual design tokens and adds a label to your layout. 6 | 7 | If you work with design tokens in your project, one of the issues you might face is receiving layouts and having to inspecting them to find out which design token corresponds to certain HEX value. 8 | 9 | That's time consuming, and would be really good to receive such layouts with some "text labels" indicating which design token applies to certain color. 10 | 11 | This plugin comes to make both Designers and Developers's lives easier: you provide a file with your main colors and their variations, and the plugin will take care of mapping those to design tokens. 12 | 13 | **TLDR;:** Designers hands over screens with the `design tokens` developers should use for certain elements. That means: no more time wasted on inspecting hardcoded values. 14 | 15 | ## Demo 16 | 17 | 18 | 19 | ## Usage 20 | 21 | 1. Provide a JSON file with your project's [decision base colors](https://medium.com/eightshapes-llc/tokens-in-design-systems-25dd82d58421) 22 | 23 | ```json 24 | // variations are based on the color`s lightness channel 25 | // (E.g color(var(--color-green), lightness(25%))) 26 | { 27 | "baseColors": { 28 | "green": { 29 | "default": "#00b39e", 30 | "25": "25%", 31 | "40": "40%", 32 | "85": "85%", 33 | "95": "95%" 34 | }, 35 | "white": { 36 | "default": "#ffffff" 37 | }, 38 | "navy": { 39 | "default": "#213c45", 40 | "30": "30%", 41 | "40": "40%", 42 | "98": "98%" 43 | } 44 | } 45 | } 46 | ``` 47 | 48 | 2. Import this file on `Plugins > Tokenizer > Import base colors file...` 49 | 50 | 51 | 52 | 3. Select an object in the Artboard 53 | 54 | 4. Go to `Plugins > Tokenizer > Get color variable > Fill Color` or `Border Color` 55 | 56 | 5. 🎉 The corresponding design token to that label will be applied to the Artboard 57 | 58 | ## Future updates 59 | 60 | - Implement actual design tokens (not only base colors) 61 | - Tones for text 62 | -------------------------------------------------------------------------------- /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lufego/sketch-tokenizer/7c5bedccaae1467e98063b011c1f15a734c5ab79/assets/icon.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sketch-tokenizer", 3 | "version": "0.1.0", 4 | "engines": { 5 | "sketch": ">=3.0" 6 | }, 7 | "skpm": { 8 | "name": "sketch-tokenizer", 9 | "manifest": "src/manifest.json", 10 | "main": "sketch-tokenizer.sketchplugin", 11 | "assets": [ 12 | "assets/**/*" 13 | ] 14 | }, 15 | "scripts": { 16 | "build": "skpm-build", 17 | "watch": "skpm-build --watch", 18 | "start": "skpm-build --watch --run", 19 | "postinstall": "npm run build && skpm-link" 20 | }, 21 | "devDependencies": { 22 | "@skpm/builder": "^0.5.2" 23 | }, 24 | "author": "lufego ", 25 | "dependencies": { 26 | "fs": "0.0.1-security", 27 | "path": "^0.12.7", 28 | "requirejs": "^2.3.5", 29 | "sketch": "^0.2.0", 30 | "yaml-js": "^0.2.3" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /sketch-tokenizer.sketchplugin/Contents/Resources/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lufego/sketch-tokenizer/7c5bedccaae1467e98063b011c1f15a734c5ab79/sketch-tokenizer.sketchplugin/Contents/Resources/icon.png -------------------------------------------------------------------------------- /sketch-tokenizer.sketchplugin/Contents/Sketch/get-border-color.js: -------------------------------------------------------------------------------- 1 | var that = this; 2 | function __skpm_run (key, context) { 3 | that.context = context; 4 | 5 | var exports = 6 | /******/ (function(modules) { // webpackBootstrap 7 | /******/ // The module cache 8 | /******/ var installedModules = {}; 9 | /******/ 10 | /******/ // The require function 11 | /******/ function __webpack_require__(moduleId) { 12 | /******/ 13 | /******/ // Check if module is in cache 14 | /******/ if(installedModules[moduleId]) { 15 | /******/ return installedModules[moduleId].exports; 16 | /******/ } 17 | /******/ // Create a new module (and put it into the cache) 18 | /******/ var module = installedModules[moduleId] = { 19 | /******/ i: moduleId, 20 | /******/ l: false, 21 | /******/ exports: {} 22 | /******/ }; 23 | /******/ 24 | /******/ // Execute the module function 25 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 26 | /******/ 27 | /******/ // Flag the module as loaded 28 | /******/ module.l = true; 29 | /******/ 30 | /******/ // Return the exports of the module 31 | /******/ return module.exports; 32 | /******/ } 33 | /******/ 34 | /******/ 35 | /******/ // expose the modules object (__webpack_modules__) 36 | /******/ __webpack_require__.m = modules; 37 | /******/ 38 | /******/ // expose the module cache 39 | /******/ __webpack_require__.c = installedModules; 40 | /******/ 41 | /******/ // define getter function for harmony exports 42 | /******/ __webpack_require__.d = function(exports, name, getter) { 43 | /******/ if(!__webpack_require__.o(exports, name)) { 44 | /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); 45 | /******/ } 46 | /******/ }; 47 | /******/ 48 | /******/ // define __esModule on exports 49 | /******/ __webpack_require__.r = function(exports) { 50 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 51 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 52 | /******/ } 53 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 54 | /******/ }; 55 | /******/ 56 | /******/ // create a fake namespace object 57 | /******/ // mode & 1: value is a module id, require it 58 | /******/ // mode & 2: merge all properties of value into the ns 59 | /******/ // mode & 4: return value when already ns object 60 | /******/ // mode & 8|1: behave like require 61 | /******/ __webpack_require__.t = function(value, mode) { 62 | /******/ if(mode & 1) value = __webpack_require__(value); 63 | /******/ if(mode & 8) return value; 64 | /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 65 | /******/ var ns = Object.create(null); 66 | /******/ __webpack_require__.r(ns); 67 | /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 68 | /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 69 | /******/ return ns; 70 | /******/ }; 71 | /******/ 72 | /******/ // getDefaultExport function for compatibility with non-harmony modules 73 | /******/ __webpack_require__.n = function(module) { 74 | /******/ var getter = module && module.__esModule ? 75 | /******/ function getDefault() { return module['default']; } : 76 | /******/ function getModuleExports() { return module; }; 77 | /******/ __webpack_require__.d(getter, 'a', getter); 78 | /******/ return getter; 79 | /******/ }; 80 | /******/ 81 | /******/ // Object.prototype.hasOwnProperty.call 82 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 83 | /******/ 84 | /******/ // __webpack_public_path__ 85 | /******/ __webpack_require__.p = ""; 86 | /******/ 87 | /******/ 88 | /******/ // Load entry module and return exports 89 | /******/ return __webpack_require__(__webpack_require__.s = "./src/get-border-color.js"); 90 | /******/ }) 91 | /************************************************************************/ 92 | /******/ ({ 93 | 94 | /***/ "./src/get-border-color.js": 95 | /*!*********************************!*\ 96 | !*** ./src/get-border-color.js ***! 97 | \*********************************/ 98 | /*! exports provided: default */ 99 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 100 | 101 | "use strict"; 102 | __webpack_require__.r(__webpack_exports__); 103 | var Utils = __webpack_require__(/*! ./utils.js */ "./src/utils.js"); // My plugin (command shift s) 104 | 105 | 106 | /* harmony default export */ __webpack_exports__["default"] = (function (context) { 107 | var selection = context.selection; 108 | context.document.showMessage('Plugin 🏃'); 109 | 110 | if (selection.length == 0) { 111 | return context.document.showMessage('🗝🌈: Please select an object'); 112 | } // if its a text 113 | 114 | 115 | if (selection[0] instanceof MSTextLayer) { 116 | return context.document.showMessage('❌: Please use `Tokenizer > Get Tone` for texts'); 117 | } 118 | 119 | var colorMapping = Utils.getBaseColorsVariablesMapping(); 120 | var currentSelectedColor = Utils.getBorderHexColor(selection).toString().toUpperCase(); 121 | var color = colorMapping["#" + currentSelectedColor]; 122 | 123 | var callback = function callback() { 124 | return getBorderColorVariable(selection, color); 125 | }; // checks if color belongs to UI Kit, if not returns an error 126 | 127 | 128 | Utils.colorChecker(color, callback); 129 | }); 130 | 131 | function getBorderColorVariable(selection, text) { 132 | // gets the position of selection 133 | var x = selection[0].frame().x(); 134 | var selectedElementWidth = selection[0].frame().width(); 135 | var midY = selection[0].frame().midY(); 136 | var position = { 137 | x: x, 138 | y: midY - 30, 139 | width: selectedElementWidth 140 | }; 141 | Utils.insertTokenText(position, 'Token', 'Border color: ', text, true); 142 | } 143 | 144 | /***/ }), 145 | 146 | /***/ "./src/utils.js": 147 | /*!**********************!*\ 148 | !*** ./src/utils.js ***! 149 | \**********************/ 150 | /*! exports provided: insertTokenText, createQuoteLine, createTextLayer, getTokenVariable, getFillHexColor, getBorderHexColor, getRGBColor, getHexValueFromColorVariable, colorChecker, getBaseColorsVariablesMapping */ 151 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 152 | 153 | "use strict"; 154 | __webpack_require__.r(__webpack_exports__); 155 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "insertTokenText", function() { return insertTokenText; }); 156 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createQuoteLine", function() { return createQuoteLine; }); 157 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createTextLayer", function() { return createTextLayer; }); 158 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getTokenVariable", function() { return getTokenVariable; }); 159 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getFillHexColor", function() { return getFillHexColor; }); 160 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getBorderHexColor", function() { return getBorderHexColor; }); 161 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getRGBColor", function() { return getRGBColor; }); 162 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getHexValueFromColorVariable", function() { return getHexValueFromColorVariable; }); 163 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "colorChecker", function() { return colorChecker; }); 164 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getBaseColorsVariablesMapping", function() { return getBaseColorsVariablesMapping; }); 165 | var quoteColor = { 166 | r: 1, 167 | g: 0.369, 168 | b: 0.941, 169 | a: 1 170 | }; // UI Creators 171 | 172 | function insertTokenText(_ref, layerName, title, text) { 173 | var x = _ref.x, 174 | y = _ref.y, 175 | width = _ref.width; 176 | var isBorder = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false; 177 | var textWithToken = createTextLayer(layerName, title + text); // pass the position to the text layer to be inserted 178 | 179 | textWithToken.frame().x = x + width + 100; 180 | textWithToken.frame().midY = y; // pass the position to quote line 181 | 182 | createQuoteLine(x, y, width, isBorder); // add the layer to the artboar 183 | 184 | context.document.currentPage().addLayers([textWithToken]); 185 | } 186 | function createQuoteLine(x, y, elementWidth, isBorder) { 187 | // if its a border, we want the quote line to touch it, otherwise touch fill 188 | var touchOffset = isBorder ? 0 : 5; // if its a border, we want the quote line to start from the same point as fill quoted line 189 | 190 | var startPointOffset = isBorder ? 30 : 0; 191 | var path = NSBezierPath.bezierPath(); 192 | path.moveToPoint(NSMakePoint(x + elementWidth - touchOffset, y + startPointOffset)); 193 | path.lineToPoint(NSMakePoint(x + elementWidth + 90, y)); 194 | var shape = MSShapeGroup.shapeWithBezierPath(MSPath.pathWithBezierPath(path)); 195 | var border = shape.style().addStylePartOfType(1); 196 | border.color = MSColor.colorWithRGBADictionary(quoteColor); 197 | border.thickness = 1; 198 | context.document.currentPage().addLayers([shape]); 199 | } 200 | function createTextLayer(name, stringValue) { 201 | var textLayer = MSTextLayer.new(); 202 | textLayer.stringValue = stringValue; 203 | textLayer.name = name; 204 | textLayer.setTextColor(MSColor.colorWithRGBADictionary(quoteColor)); 205 | return textLayer; 206 | } // Token getters 207 | 208 | function getTokenVariable(colorsMap, wholeObject, property, component, hexColor) { 209 | if (!colorsMap) { 210 | return context.document.showMessage('✋🏻❌: Please load a decisions base colors file before continuing'); 211 | } 212 | 213 | if (!wholeObject) { 214 | return context.document.showMessage("\u270B\uD83C\uDFFB\u274C: Please load a decisions token file for ".concat(property, " before continuing")); 215 | } 216 | 217 | var prefix = '--token'; // if property has `-`, splits it 218 | 219 | var hasDash = /-/; 220 | var propertyPrefix = hasDash.test(property) ? property.split('-') : property; // gets the color from selected element 221 | 222 | var selectedColor = colorsMap[hexColor].replace('--color-', ''); 223 | var states; 224 | var propertyName; 225 | 226 | if (propertyPrefix instanceof Array) { 227 | states = wholeObject['token'][propertyPrefix[0]][propertyPrefix[1]][component]; 228 | propertyName = "".concat(propertyPrefix[0], "-").concat(propertyPrefix[1]); 229 | } else { 230 | states = wholeObject['token'][propertyPrefix][component]; 231 | propertyName = propertyPrefix; 232 | } 233 | 234 | var selectedState = Object.keys(states).find(function (state) { 235 | return states[state] == selectedColor; 236 | }); 237 | return "".concat(prefix, "-").concat(propertyName, "-").concat(component, "-").concat(selectedState); 238 | } // Base color getters 239 | 240 | function getFillHexColor(selection) { 241 | var layer = context.selection[0]; 242 | var selectedColor = getRGBColor('fill', layer); 243 | var colorHex = selectedColor.immutableModelObject().hexValue().toString(); 244 | return colorHex; 245 | } 246 | function getBorderHexColor(selection) { 247 | var layer = context.selection[0]; 248 | var selectedColor = getRGBColor('border', layer); 249 | var colorHex = selectedColor.immutableModelObject().hexValue().toString(); 250 | return colorHex; 251 | } 252 | function getRGBColor(type, layer) { 253 | var color; 254 | 255 | if (type === 'fill') { 256 | if (layer instanceof MSTextLayer) { 257 | color = layer.textColor(); 258 | } else { 259 | color = layer.style().fills().firstObject().color(); 260 | } 261 | } else { 262 | color = layer.style().borders().firstObject().color(); 263 | } 264 | 265 | return color; 266 | } 267 | function getHexValueFromColorVariable(colorVar, baseColorsVariablesMap) { 268 | var colorVarWithPrefix = "--color-".concat(colorVar); 269 | return Object.keys(baseColorsVariablesMap).find(function (hexVal) { 270 | if (baseColorsVariablesMap[hexVal] == colorVarWithPrefix) return hexVal; 271 | }); 272 | } // Checkers 273 | 274 | function colorChecker(color, callback) { 275 | if (typeof color === 'undefined') { 276 | return context.document.showMessage('🎨🚫: Non UI Kit color. Please make sure to use a valid color'); 277 | } else { 278 | return callback(); 279 | } 280 | } // General scripts 281 | 282 | function getBaseColorsVariablesMapping() { 283 | // Gets the json data stored in global state 284 | var threadDictionary = NSThread.mainThread().threadDictionary(); 285 | var importedBaseColors = threadDictionary.importedBaseColors; 286 | if (!importedBaseColors) return context.document.showMessage('🗃👎🏻 No file imported. Please import your base colors file in `Import base colors file...`'); 287 | var colorNames = {}; // gets default color variables 288 | 289 | Object.keys(importedBaseColors).map(function (colorGroupName) { 290 | // console.log('colorGroupName', colorGroupName) 291 | var colorGroup = importedBaseColors[colorGroupName]; 292 | var colorDefaultName = colorGroup.default; 293 | colorNames[colorDefaultName.toString().toUpperCase()] = '--color-' + colorGroupName; // console.log('colorGroup.default', colorGroup.default); 294 | 295 | Object.keys(colorGroup).forEach(function (variation) { 296 | // filters out default values 297 | if (variation !== 'default') { 298 | var variationName = colorGroup[variation]; 299 | var variationNameWithoutPercetageSign = variationName.toString().replace('%', ''); // console.log('colorGroup.default', colorGroup.default) 300 | 301 | colorNames[transformColorLightness(colorGroup.default, variationNameWithoutPercetageSign).toUpperCase()] = '--color-' + colorGroupName + '-' + variation; 302 | } 303 | }); 304 | }); 305 | return colorNames; 306 | } // Color converters 307 | 308 | function transformColorLightness(hex, lightness) { 309 | var hslColor = hexToHsl(hex, lightness); 310 | var hexColor = hslToHex(hslColor); 311 | console.log('hexColor', hexColor); 312 | return hexColor; 313 | } 314 | 315 | function hexToHsl(hex, lightness) { 316 | var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 317 | var r = parseInt(result[1], 16); 318 | var g = parseInt(result[2], 16); 319 | var b = parseInt(result[3], 16); 320 | r /= 255, g /= 255, b /= 255; 321 | var max = Math.max(r, g, b), 322 | min = Math.min(r, g, b); 323 | var h, 324 | s, 325 | l = (max + min) / 2; 326 | 327 | if (max == min) { 328 | h = s = 0; // achromatic 329 | } else { 330 | var d = max - min; 331 | s = l > 0.5 ? d / (2 - max - min) : d / (max + min); 332 | 333 | switch (max) { 334 | case r: 335 | h = (g - b) / d + (g < b ? 6 : 0); 336 | break; 337 | 338 | case g: 339 | h = (b - r) / d + 2; 340 | break; 341 | 342 | case b: 343 | h = (r - g) / d + 4; 344 | break; 345 | } 346 | 347 | h /= 6; 348 | } 349 | 350 | h = Math.round(360 * h); 351 | s = s * 100; 352 | s = Math.round(s); 353 | l = l * 100; 354 | l = lightness ? lightness : Math.round(l); 355 | return [h, s, l]; 356 | } 357 | 358 | function hslToHex(hsl) { 359 | var rgbColor = hslToRgb(hsl[0], hsl[1], hsl[2]); 360 | var r = rgbColor[0]; 361 | var g = rgbColor[1]; 362 | var b = rgbColor[2]; // console.log('rgb', r, g, b) 363 | 364 | return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); 365 | } 366 | 367 | function hslToRgb(h, s, l) { 368 | var m1, m2, hue; 369 | s = s / 100; 370 | l = l / 100; 371 | var r, g, b; 372 | if (s == 0) r = g = b = l * 255;else { 373 | m2 = l < 0.5 ? l * (1 + s) : l + s - l * s; 374 | m1 = 2 * l - m2; 375 | hue = h / 360; 376 | r = hue2rgb(m1, m2, hue + 1 / 3); 377 | g = hue2rgb(m1, m2, hue); 378 | b = hue2rgb(m1, m2, hue - 1 / 3); 379 | } 380 | 381 | function multiplyBy255(num) { 382 | return num * 255; 383 | } 384 | 385 | if (r < 1 || g < 1 || b < 1) { 386 | r = multiplyBy255(r); 387 | g = multiplyBy255(g); 388 | b = multiplyBy255(b); 389 | } 390 | 391 | console.log('rgb', Math.round(r), Math.round(g), Math.round(b)); 392 | return [Math.round(r), Math.round(g), Math.round(b)]; 393 | } 394 | 395 | function hue2rgb(m1, m2, hue) { 396 | if (hue < 0) hue += 1; 397 | if (hue > 1) hue -= 1; 398 | if (hue < 1 / 6) return m1 + (m2 - m1) * 6 * hue; 399 | if (hue < 1 / 2) return m2; 400 | if (hue < 2 / 3) return m1 + (m2 - m1) * (2 / 3 - hue) * 6; 401 | return m1; 402 | } 403 | 404 | /***/ }) 405 | 406 | /******/ }); 407 | if (key === 'default' && typeof exports === 'function') { 408 | exports(context); 409 | } else { 410 | exports[key](context); 411 | } 412 | } 413 | that['onRun'] = __skpm_run.bind(this, 'default') 414 | 415 | //# sourceMappingURL=get-border-color.js.map -------------------------------------------------------------------------------- /sketch-tokenizer.sketchplugin/Contents/Sketch/get-border-color.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack://exports/webpack/bootstrap","webpack://exports/./src/get-border-color.js","webpack://exports/./src/utils.js"],"names":["Utils","require","context","selection","document","showMessage","length","MSTextLayer","colorMapping","getBaseColorsVariablesMapping","currentSelectedColor","getBorderHexColor","toString","toUpperCase","color","callback","getBorderColorVariable","colorChecker","text","x","frame","selectedElementWidth","width","midY","position","y","insertTokenText","quoteColor","r","g","b","a","layerName","title","isBorder","textWithToken","createTextLayer","createQuoteLine","currentPage","addLayers","elementWidth","touchOffset","startPointOffset","path","NSBezierPath","bezierPath","moveToPoint","NSMakePoint","lineToPoint","shape","MSShapeGroup","shapeWithBezierPath","MSPath","pathWithBezierPath","border","style","addStylePartOfType","MSColor","colorWithRGBADictionary","thickness","name","stringValue","textLayer","new","setTextColor","getTokenVariable","colorsMap","wholeObject","property","component","hexColor","prefix","hasDash","propertyPrefix","test","split","selectedColor","replace","states","propertyName","Array","selectedState","Object","keys","find","state","getFillHexColor","layer","getRGBColor","colorHex","immutableModelObject","hexValue","type","textColor","fills","firstObject","borders","getHexValueFromColorVariable","colorVar","baseColorsVariablesMap","colorVarWithPrefix","hexVal","threadDictionary","NSThread","mainThread","importedBaseColors","colorNames","map","colorGroup","colorGroupName","colorDefaultName","default","forEach","variation","variationName","variationNameWithoutPercetageSign","transformColorLightness","hex","lightness","hslColor","hexToHsl","hslToHex","console","log","result","exec","parseInt","max","Math","min","h","s","l","d","round","hsl","rgbColor","hslToRgb","slice","m1","m2","hue","hue2rgb","multiplyBy255","num"],"mappings":"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","file":"get-border-color.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = \"./src/get-border-color.js\");\n","const Utils = require('./utils.js')\n\n// My plugin (command shift s)\nexport default function(context) {\n var selection = context.selection;\n context.document.showMessage('Plugin 🏃');\n\n if (selection.length == 0) {\n return context.document.showMessage('🗝🌈: Please select an object');\n }\n // if its a text\n if (selection[0] instanceof MSTextLayer) {\n return context.document.showMessage('❌: Please use `Tokenizer > Get Tone` for texts');\n }\n \n const colorMapping = Utils.getBaseColorsVariablesMapping()\n const currentSelectedColor = Utils.getBorderHexColor(selection).toString().toUpperCase();\n \n \n const color = colorMapping[\"#\" + currentSelectedColor];\n \n const callback = () => getBorderColorVariable(selection, color);\n\n // checks if color belongs to UI Kit, if not returns an error\n Utils.colorChecker(color, callback)\n}\n\n\n\n\nfunction getBorderColorVariable(selection, text) {\n // gets the position of selection\n var x = selection[0].frame().x();\n var selectedElementWidth = selection[0].frame().width();\n var midY =selection[0].frame().midY();\n\n const position = {\n x, y: midY - 30, width: selectedElementWidth\n }\n Utils.insertTokenText(position, 'Token', 'Border color: ', text, true)\n}\n","const quoteColor = { r: 1, g: 0.369, b: 0.941, a: 1 };\n\n// UI Creators\n\nexport function insertTokenText(\n { x, y, width },\n layerName,\n title,\n text,\n isBorder = false\n) {\n const textWithToken = createTextLayer(layerName, title + text);\n // pass the position to the text layer to be inserted\n textWithToken.frame().x = x + width + 100;\n textWithToken.frame().midY = y;\n\n // pass the position to quote line\n createQuoteLine(x, y, width, isBorder);\n\n // add the layer to the artboar\n context.document.currentPage().addLayers([textWithToken]);\n}\n\nexport function createQuoteLine(x, y, elementWidth, isBorder) {\n // if its a border, we want the quote line to touch it, otherwise touch fill\n const touchOffset = isBorder ? 0 : 5;\n\n // if its a border, we want the quote line to start from the same point as fill quoted line\n const startPointOffset = isBorder ? 30 : 0;\n var path = NSBezierPath.bezierPath();\n path.moveToPoint(\n NSMakePoint(x + elementWidth - touchOffset, y + startPointOffset)\n );\n path.lineToPoint(NSMakePoint(x + elementWidth + 90, y));\n\n var shape = MSShapeGroup.shapeWithBezierPath(MSPath.pathWithBezierPath(path));\n var border = shape.style().addStylePartOfType(1);\n border.color = MSColor.colorWithRGBADictionary(quoteColor);\n border.thickness = 1;\n\n context.document.currentPage().addLayers([shape]);\n}\n\nexport function createTextLayer(name, stringValue) {\n var textLayer = MSTextLayer.new();\n textLayer.stringValue = stringValue;\n textLayer.name = name;\n textLayer.setTextColor(MSColor.colorWithRGBADictionary(quoteColor));\n return textLayer;\n}\n\n// Token getters\n\nexport function getTokenVariable(\n colorsMap,\n wholeObject,\n property,\n component,\n hexColor\n) {\n if (!colorsMap) {\n return context.document.showMessage(\n '✋🏻❌: Please load a decisions base colors file before continuing'\n );\n }\n\n if (!wholeObject) {\n return context.document.showMessage(\n `✋🏻❌: Please load a decisions token file for ${property} before continuing`\n );\n }\n\n const prefix = '--token';\n\n // if property has `-`, splits it\n const hasDash = /-/;\n const propertyPrefix = hasDash.test(property)\n ? property.split('-')\n : property;\n\n // gets the color from selected element\n const selectedColor = colorsMap[hexColor].replace('--color-', '');\n\n let states;\n let propertyName;\n if (propertyPrefix instanceof Array) {\n states =\n wholeObject['token'][propertyPrefix[0]][propertyPrefix[1]][component];\n propertyName = `${propertyPrefix[0]}-${propertyPrefix[1]}`;\n } else {\n states = wholeObject['token'][propertyPrefix][component];\n propertyName = propertyPrefix;\n }\n\n const selectedState = Object.keys(states).find(\n state => states[state] == selectedColor\n );\n\n return `${prefix}-${propertyName}-${component}-${selectedState}`;\n}\n\n// Base color getters\n\nexport function getFillHexColor(selection) {\n var layer = context.selection[0];\n var selectedColor = getRGBColor('fill', layer);\n var colorHex = selectedColor\n .immutableModelObject()\n .hexValue()\n .toString();\n return colorHex;\n}\n\nexport function getBorderHexColor(selection) {\n var layer = context.selection[0];\n var selectedColor = getRGBColor('border', layer);\n var colorHex = selectedColor\n .immutableModelObject()\n .hexValue()\n .toString();\n return colorHex;\n}\n\nexport function getRGBColor(type, layer) {\n var color;\n\n if (type === 'fill') {\n if (layer instanceof MSTextLayer) {\n color = layer.textColor();\n } else {\n color = layer\n .style()\n .fills()\n .firstObject()\n .color();\n }\n } else {\n color = layer\n .style()\n .borders()\n .firstObject()\n .color();\n }\n\n return color;\n}\n\nexport function getHexValueFromColorVariable(colorVar, baseColorsVariablesMap) {\n const colorVarWithPrefix = `--color-${colorVar}`;\n return Object.keys(baseColorsVariablesMap).find(hexVal => {\n if (baseColorsVariablesMap[hexVal] == colorVarWithPrefix) return hexVal;\n });\n}\n\n// Checkers\n\nexport function colorChecker(color, callback) {\n if (typeof color === 'undefined') {\n return context.document.showMessage(\n '🎨🚫: Non UI Kit color. Please make sure to use a valid color'\n );\n } else {\n return callback();\n }\n}\n\n// General scripts\n\nexport function getBaseColorsVariablesMapping() {\n // Gets the json data stored in global state\n let threadDictionary = NSThread.mainThread().threadDictionary();\n let importedBaseColors = threadDictionary.importedBaseColors;\n if (!importedBaseColors)\n return context.document.showMessage(\n '🗃👎🏻 No file imported. Please import your base colors file in `Import base colors file...`'\n );\n\n const colorNames = {};\n // gets default color variables\n Object.keys(importedBaseColors).map(colorGroupName => {\n // console.log('colorGroupName', colorGroupName)\n const colorGroup = importedBaseColors[colorGroupName];\n const colorDefaultName = colorGroup.default;\n colorNames[colorDefaultName.toString().toUpperCase()] =\n '--color-' + colorGroupName;\n\n // console.log('colorGroup.default', colorGroup.default);\n\n Object.keys(colorGroup).forEach(variation => {\n // filters out default values\n if (variation !== 'default') {\n const variationName = colorGroup[variation];\n const variationNameWithoutPercetageSign = variationName\n .toString()\n .replace('%', '');\n // console.log('colorGroup.default', colorGroup.default)\n colorNames[\n transformColorLightness(\n colorGroup.default,\n variationNameWithoutPercetageSign\n ).toUpperCase()\n ] =\n '--color-' + colorGroupName + '-' + variation;\n }\n });\n });\n return colorNames;\n}\n\n// Color converters\n\nfunction transformColorLightness(hex, lightness) {\n const hslColor = hexToHsl(hex, lightness);\n const hexColor = hslToHex(hslColor);\n console.log('hexColor', hexColor);\n return hexColor;\n}\n\nfunction hexToHsl(hex, lightness) {\n var result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\n\n var r = parseInt(result[1], 16);\n var g = parseInt(result[2], 16);\n var b = parseInt(result[3], 16);\n\n (r /= 255), (g /= 255), (b /= 255);\n var max = Math.max(r, g, b),\n min = Math.min(r, g, b);\n var h,\n s,\n l = (max + min) / 2;\n\n if (max == min) {\n h = s = 0; // achromatic\n } else {\n var d = max - min;\n s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n switch (max) {\n case r:\n h = (g - b) / d + (g < b ? 6 : 0);\n break;\n case g:\n h = (b - r) / d + 2;\n break;\n case b:\n h = (r - g) / d + 4;\n break;\n }\n h /= 6;\n }\n\n h = Math.round(360 * h);\n s = s * 100;\n s = Math.round(s);\n l = l * 100;\n l = lightness ? lightness : Math.round(l);\n\n return [h, s, l];\n}\n\nfunction hslToHex(hsl) {\n const rgbColor = hslToRgb(hsl[0], hsl[1], hsl[2]);\n const r = rgbColor[0];\n const g = rgbColor[1];\n const b = rgbColor[2];\n\n // console.log('rgb', r, g, b)\n\n return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);\n}\n\nfunction hslToRgb(h, s, l) {\n var m1, m2, hue;\n s = s / 100;\n l = l / 100;\n var r, g, b;\n\n if (s == 0) r = g = b = l * 255;\n else {\n m2 = l < 0.5 ? l * (1 + s) : l + s - l * s;\n m1 = 2 * l - m2;\n hue = h / 360;\n\n r = hue2rgb(m1, m2, hue + 1 / 3);\n g = hue2rgb(m1, m2, hue);\n b = hue2rgb(m1, m2, hue - 1 / 3);\n }\n\n function multiplyBy255(num) {\n return num * 255;\n }\n\n if (r < 1 || g < 1 || b < 1) {\n r = multiplyBy255(r);\n g = multiplyBy255(g);\n b = multiplyBy255(b);\n }\n\n console.log('rgb', Math.round(r), Math.round(g), Math.round(b));\n\n return [Math.round(r), Math.round(g), Math.round(b)];\n}\n\nfunction hue2rgb(m1, m2, hue) {\n if (hue < 0) hue += 1;\n if (hue > 1) hue -= 1;\n if (hue < 1 / 6) return m1 + (m2 - m1) * 6 * hue;\n if (hue < 1 / 2) return m2;\n if (hue < 2 / 3) return m1 + (m2 - m1) * (2 / 3 - hue) * 6;\n return m1;\n}\n"],"sourceRoot":""} -------------------------------------------------------------------------------- /sketch-tokenizer.sketchplugin/Contents/Sketch/get-color-variable.js: -------------------------------------------------------------------------------- 1 | var that = this; 2 | function __skpm_run (key, context) { 3 | that.context = context; 4 | 5 | var exports = 6 | /******/ (function(modules) { // webpackBootstrap 7 | /******/ // The module cache 8 | /******/ var installedModules = {}; 9 | /******/ 10 | /******/ // The require function 11 | /******/ function __webpack_require__(moduleId) { 12 | /******/ 13 | /******/ // Check if module is in cache 14 | /******/ if(installedModules[moduleId]) { 15 | /******/ return installedModules[moduleId].exports; 16 | /******/ } 17 | /******/ // Create a new module (and put it into the cache) 18 | /******/ var module = installedModules[moduleId] = { 19 | /******/ i: moduleId, 20 | /******/ l: false, 21 | /******/ exports: {} 22 | /******/ }; 23 | /******/ 24 | /******/ // Execute the module function 25 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 26 | /******/ 27 | /******/ // Flag the module as loaded 28 | /******/ module.l = true; 29 | /******/ 30 | /******/ // Return the exports of the module 31 | /******/ return module.exports; 32 | /******/ } 33 | /******/ 34 | /******/ 35 | /******/ // expose the modules object (__webpack_modules__) 36 | /******/ __webpack_require__.m = modules; 37 | /******/ 38 | /******/ // expose the module cache 39 | /******/ __webpack_require__.c = installedModules; 40 | /******/ 41 | /******/ // define getter function for harmony exports 42 | /******/ __webpack_require__.d = function(exports, name, getter) { 43 | /******/ if(!__webpack_require__.o(exports, name)) { 44 | /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); 45 | /******/ } 46 | /******/ }; 47 | /******/ 48 | /******/ // define __esModule on exports 49 | /******/ __webpack_require__.r = function(exports) { 50 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 51 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 52 | /******/ } 53 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 54 | /******/ }; 55 | /******/ 56 | /******/ // create a fake namespace object 57 | /******/ // mode & 1: value is a module id, require it 58 | /******/ // mode & 2: merge all properties of value into the ns 59 | /******/ // mode & 4: return value when already ns object 60 | /******/ // mode & 8|1: behave like require 61 | /******/ __webpack_require__.t = function(value, mode) { 62 | /******/ if(mode & 1) value = __webpack_require__(value); 63 | /******/ if(mode & 8) return value; 64 | /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 65 | /******/ var ns = Object.create(null); 66 | /******/ __webpack_require__.r(ns); 67 | /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 68 | /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 69 | /******/ return ns; 70 | /******/ }; 71 | /******/ 72 | /******/ // getDefaultExport function for compatibility with non-harmony modules 73 | /******/ __webpack_require__.n = function(module) { 74 | /******/ var getter = module && module.__esModule ? 75 | /******/ function getDefault() { return module['default']; } : 76 | /******/ function getModuleExports() { return module; }; 77 | /******/ __webpack_require__.d(getter, 'a', getter); 78 | /******/ return getter; 79 | /******/ }; 80 | /******/ 81 | /******/ // Object.prototype.hasOwnProperty.call 82 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 83 | /******/ 84 | /******/ // __webpack_public_path__ 85 | /******/ __webpack_require__.p = ""; 86 | /******/ 87 | /******/ 88 | /******/ // Load entry module and return exports 89 | /******/ return __webpack_require__(__webpack_require__.s = "./src/get-color-variable.js"); 90 | /******/ }) 91 | /************************************************************************/ 92 | /******/ ({ 93 | 94 | /***/ "./src/get-color-variable.js": 95 | /*!***********************************!*\ 96 | !*** ./src/get-color-variable.js ***! 97 | \***********************************/ 98 | /*! exports provided: default */ 99 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 100 | 101 | "use strict"; 102 | __webpack_require__.r(__webpack_exports__); 103 | // My plugin (command shift s) 104 | var colorVariables = { 105 | baseColors: { 106 | green: { 107 | default: "#14B39D", 108 | 25: "#0B8171", 109 | 40: "#19CCB3", 110 | 85: "#B4FFF6", 111 | 95: "#E6FFFC" 112 | }, 113 | white: { 114 | default: "#FFFFFF" 115 | }, 116 | navy: { 117 | default: "#1D3D45", 118 | 30: "#2E5768", 119 | 40: "#407A8B", 120 | 95: "#EEF4F6", 121 | 98: "#F9FBFB" 122 | }, 123 | blue: { 124 | default: "#0090E0", 125 | 95: "#B2E3FF", 126 | 98: "#E5F6FF" 127 | }, 128 | gray: { 129 | default: "#CCCCCC", 130 | 60: "#999999", 131 | 90: "#E6E6E6", 132 | 95: "#F2F2F2" 133 | }, 134 | orange: { 135 | default: "#F1690E", 136 | 95: "#FEF0E7" 137 | }, 138 | red: { 139 | default: "#E50051", 140 | 95: "#FFE5EE" 141 | }, 142 | purple: { 143 | default: "#B26DFF" 144 | }, 145 | black: { 146 | default: "#181818" 147 | } 148 | } 149 | }; 150 | var quoteColor = { 151 | r: 1, 152 | g: 0.369, 153 | b: 0.941, 154 | a: 1 155 | }; 156 | /* harmony default export */ __webpack_exports__["default"] = (function (context) { 157 | var selection = context.selection; 158 | context.document.showMessage('Plugin 🏃'); 159 | 160 | if (selection.length == 0) { 161 | return context.document.showMessage('🗝🌈: Please select an object'); 162 | } 163 | 164 | var colorMapping = getColorVariablesMapping(colorVariables); 165 | var currentSelectedColor = getFillHexColor(selection).toString().toUpperCase(); // if its a text 166 | // if (selection[0] instanceof MSTextLayer) { 167 | // const lay = createTextLayer('tone', 'tone: ' + 'NEGATIVE'); 168 | // // gets the position of selection 169 | // var midX=context.selection[0].frame().midX(); 170 | // var midY=context.selection[0].frame().midY(); 171 | // 172 | // // pass the position to the text layer to be inserter 173 | // lay.frame().midX = midX; 174 | // lay.frame().midY = midY; 175 | // return context.document.currentPage().addLayers([lay]); 176 | // } 177 | 178 | var text = colorMapping["#" + currentSelectedColor]; // if its a shape 179 | 180 | getFillColorVariable(selection, text); 181 | }); 182 | 183 | function insertTokenText(_ref, layerName, title, text) { 184 | var x = _ref.x, 185 | y = _ref.y, 186 | width = _ref.width; 187 | var textWithToken = createTextLayer(layerName, title + text); // pass the position to the text layer to be inserted 188 | 189 | textWithToken.frame().x = x + width + 100; 190 | textWithToken.frame().midY = y; // pass the position to quote line 191 | 192 | createQuoteLine(x, y, width); // add the layer to the artboar 193 | 194 | context.document.currentPage().addLayers([textWithToken]); 195 | } 196 | 197 | function getFillColorVariable(selection, text) { 198 | // gets the position of selection 199 | var x = selection[0].frame().x(); 200 | var selectedElementWidth = selection[0].frame().width(); 201 | var midY = selection[0].frame().midY(); 202 | var position = { 203 | x: x, 204 | y: midY, 205 | width: selectedElementWidth 206 | }; 207 | insertTokenText(position, 'Token', 'Fill color: ', text); 208 | } 209 | 210 | function createQuoteLine(x, y, elementWidth) { 211 | var path = NSBezierPath.bezierPath(); 212 | path.moveToPoint(NSMakePoint(x + elementWidth - 5, y)); 213 | path.lineToPoint(NSMakePoint(x + elementWidth + 90, y)); 214 | var shape = MSShapeGroup.shapeWithBezierPath(MSPath.pathWithBezierPath(path)); 215 | var border = shape.style().addStylePartOfType(1); 216 | border.color = MSColor.colorWithRGBADictionary(quoteColor); 217 | border.thickness = 1; 218 | context.document.currentPage().addLayers([shape]); 219 | } 220 | 221 | function getFillHexColor(selection) { 222 | var layer = context.selection[0]; 223 | var selectedColor = getFillRGBColor("fill", layer); 224 | var colorHex = selectedColor.immutableModelObject().hexValue().toString(); 225 | return colorHex; 226 | } 227 | 228 | function getFillRGBColor(type, layer) { 229 | var color; 230 | 231 | if (type === "fill") { 232 | if (layer instanceof MSTextLayer) { 233 | color = layer.textColor(); 234 | } else { 235 | color = layer.style().fills().firstObject().color(); 236 | } 237 | } else { 238 | color = layer.style().borders().firstObject().color(); 239 | } 240 | 241 | return color; 242 | } // Hex to Color - helper function 243 | 244 | 245 | var hexToColor = function hexToColor(hex, alpha) { 246 | var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex), 247 | red = parseInt(result[1], 16) / 255, 248 | green = parseInt(result[2], 16) / 255, 249 | blue = parseInt(result[3], 16) / 255, 250 | alpha = typeof alpha !== 'undefined' ? alpha : 1; 251 | return NSColor.colorWithCalibratedRed_green_blue_alpha(red, green, blue, alpha); 252 | }; 253 | 254 | function createTextLayer(name, stringValue) { 255 | var textLayer = MSTextLayer.new(); 256 | textLayer.stringValue = stringValue; 257 | textLayer.name = name; 258 | textLayer.setTextColor(MSColor.colorWithRGBADictionary(quoteColor)); 259 | return textLayer; 260 | } 261 | 262 | function getColorVariablesMapping(variables) { 263 | var obj = variables.baseColors; 264 | var colorNames = {}; // gets default color variables 265 | 266 | Object.keys(obj).map(function (colorGroupName) { 267 | var colorGroup = obj[colorGroupName]; 268 | colorNames[colorGroup.default] = '--color-' + colorGroupName; 269 | Object.keys(colorGroup).forEach(function (variation) { 270 | // filters out default values 271 | if (variation !== 'default') { 272 | colorNames[colorGroup[variation]] = '--color-' + colorGroupName + '-' + variation; 273 | } 274 | }); 275 | }); 276 | return colorNames; 277 | } 278 | 279 | /***/ }) 280 | 281 | /******/ }); 282 | if (key === 'default' && typeof exports === 'function') { 283 | exports(context); 284 | } else { 285 | exports[key](context); 286 | } 287 | } 288 | that['onRun'] = __skpm_run.bind(this, 'default') 289 | 290 | //# sourceMappingURL=get-color-variable.js.map -------------------------------------------------------------------------------- /sketch-tokenizer.sketchplugin/Contents/Sketch/get-color-variable.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack://exports/webpack/bootstrap","webpack://exports/./src/get-color-variable.js"],"names":["colorVariables","baseColors","green","default","white","navy","blue","gray","orange","red","purple","black","quoteColor","r","g","b","a","context","selection","document","showMessage","length","colorMapping","getColorVariablesMapping","currentSelectedColor","getFillHexColor","toString","toUpperCase","text","getFillColorVariable","insertTokenText","layerName","title","x","y","width","textWithToken","createTextLayer","frame","midY","createQuoteLine","currentPage","addLayers","selectedElementWidth","position","elementWidth","path","NSBezierPath","bezierPath","moveToPoint","NSMakePoint","lineToPoint","shape","MSShapeGroup","shapeWithBezierPath","MSPath","pathWithBezierPath","border","style","addStylePartOfType","color","MSColor","colorWithRGBADictionary","thickness","layer","selectedColor","getFillRGBColor","colorHex","immutableModelObject","hexValue","type","MSTextLayer","textColor","fills","firstObject","borders","hexToColor","hex","alpha","result","exec","parseInt","NSColor","colorWithCalibratedRed_green_blue_alpha","name","stringValue","textLayer","new","setTextColor","variables","obj","colorNames","Object","keys","map","colorGroup","colorGroupName","forEach","variation"],"mappings":"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","file":"get-color-variable.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = \"./src/get-color-variable.js\");\n","// My plugin (command shift s)\nconst colorVariables = {\n baseColors: {\n green: {\n default: \"#14B39D\",\n 25: \"#0B8171\",\n 40: \"#19CCB3\",\n 85: \"#B4FFF6\",\n 95: \"#E6FFFC\",\n },\n white: {\n default: \"#FFFFFF\"\n },\n navy: {\n default: \"#1D3D45\",\n 30: \"#2E5768\",\n 40: \"#407A8B\",\n 95: \"#EEF4F6\",\n 98 : \"#F9FBFB\"\n },\n blue: {\n default: \"#0090E0\",\n 95: \"#B2E3FF\",\n 98: \"#E5F6FF\"\n },\n gray: {\n default: \"#CCCCCC\",\n 60: \"#999999\",\n 90: \"#E6E6E6\",\n 95: \"#F2F2F2\"\n },\n orange: {\n default: \"#F1690E\",\n 95: \"#FEF0E7\"\n },\n red: {\n default: \"#E50051\",\n 95: \"#FFE5EE\"\n },\n purple: {\n default: \"#B26DFF\",\n },\n black: {\n default: \"#181818\",\n }\n }\n}\n\nconst quoteColor = {r: 1, g: 0.369, b: 0.941, a: 1}\n\nexport default function(context) {\n var selection = context.selection;\n context.document.showMessage('Plugin 🏃');\n\n if (selection.length == 0) {\n return context.document.showMessage('🗝🌈: Please select an object');\n }\n \n const colorMapping = getColorVariablesMapping(colorVariables)\n const currentSelectedColor = getFillHexColor(selection).toString().toUpperCase();\n \n // if its a text\n // if (selection[0] instanceof MSTextLayer) {\n // const lay = createTextLayer('tone', 'tone: ' + 'NEGATIVE');\n // // gets the position of selection\n // var midX=context.selection[0].frame().midX();\n // var midY=context.selection[0].frame().midY();\n // \n // // pass the position to the text layer to be inserter\n // lay.frame().midX = midX;\n // lay.frame().midY = midY;\n // return context.document.currentPage().addLayers([lay]);\n // }\n const text = colorMapping[\"#\" + currentSelectedColor];\n // if its a shape\n getFillColorVariable(selection, text)\n}\n\nfunction insertTokenText({x, y, width}, layerName, title, text) {\n const textWithToken = createTextLayer(layerName, title + text);\n // pass the position to the text layer to be inserted\n textWithToken.frame().x = x + width + 100;\n textWithToken.frame().midY = y;\n \n // pass the position to quote line\n createQuoteLine(x, y, width);\n\n // add the layer to the artboar\n context.document.currentPage().addLayers([textWithToken]);\n}\n\n\nfunction getFillColorVariable(selection, text) {\n // gets the position of selection\n var x = selection[0].frame().x();\n var selectedElementWidth = selection[0].frame().width();\n var midY =selection[0].frame().midY();\n\n const position = {\n x, y: midY, width: selectedElementWidth\n }\n insertTokenText(position, 'Token', 'Fill color: ', text)\n}\n\nfunction createQuoteLine(x, y, elementWidth) {\n var path = NSBezierPath.bezierPath();\n path.moveToPoint(NSMakePoint(x + elementWidth - 5, y));\n path.lineToPoint(NSMakePoint(x + elementWidth + 90, y));\n\n var shape = MSShapeGroup.shapeWithBezierPath(MSPath.pathWithBezierPath(path));\n var border = shape.style().addStylePartOfType(1);\n border.color = MSColor.colorWithRGBADictionary(quoteColor);\n border.thickness = 1;\n\n context.document.currentPage().addLayers([shape]);\n}\n\nfunction getFillHexColor(selection) {\n var layer = context.selection[0]\n var selectedColor = getFillRGBColor(\"fill\", layer)\n var colorHex = selectedColor.immutableModelObject().hexValue().toString()\n return colorHex\n}\n\nfunction getFillRGBColor (type, layer) {\n var color\n\n if (type === \"fill\") {\n if (layer instanceof MSTextLayer) {\n color = layer.textColor()\n } else {\n color = layer.style().fills().firstObject().color()\n }\n } else {\n color = layer.style().borders().firstObject().color()\n }\n\n return color\n}\n\n// Hex to Color - helper function\nvar hexToColor = function(hex, alpha) {\n var result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex),\n red = parseInt(result[1], 16) / 255,\n green = parseInt(result[2], 16) / 255,\n blue = parseInt(result[3], 16) / 255,\n alpha = (typeof alpha !== 'undefined') ? alpha : 1;\n return NSColor.colorWithCalibratedRed_green_blue_alpha(red, green, blue, alpha)\n}\n\n\nfunction createTextLayer(name, stringValue) {\n var textLayer = MSTextLayer.new();\n textLayer.stringValue = stringValue\n textLayer.name = name\n textLayer.setTextColor(MSColor.colorWithRGBADictionary(quoteColor))\n return textLayer;\n}\n\nfunction getColorVariablesMapping(variables) {\n const obj = variables.baseColors\n const colorNames = {}\n // gets default color variables\n Object.keys(obj).map(colorGroupName => {\n const colorGroup = obj[colorGroupName]\n\n colorNames[colorGroup.default] = '--color-' + colorGroupName;\n\n Object.keys(colorGroup).forEach(variation => {\n // filters out default values\n if (variation !== 'default') {\n colorNames[colorGroup[variation]] = '--color-' + colorGroupName + '-' + variation;\n }\n })\n })\n\n return colorNames\n}\n"],"sourceRoot":""} -------------------------------------------------------------------------------- /sketch-tokenizer.sketchplugin/Contents/Sketch/get-fill-color.js: -------------------------------------------------------------------------------- 1 | var that = this; 2 | function __skpm_run (key, context) { 3 | that.context = context; 4 | 5 | var exports = 6 | /******/ (function(modules) { // webpackBootstrap 7 | /******/ // The module cache 8 | /******/ var installedModules = {}; 9 | /******/ 10 | /******/ // The require function 11 | /******/ function __webpack_require__(moduleId) { 12 | /******/ 13 | /******/ // Check if module is in cache 14 | /******/ if(installedModules[moduleId]) { 15 | /******/ return installedModules[moduleId].exports; 16 | /******/ } 17 | /******/ // Create a new module (and put it into the cache) 18 | /******/ var module = installedModules[moduleId] = { 19 | /******/ i: moduleId, 20 | /******/ l: false, 21 | /******/ exports: {} 22 | /******/ }; 23 | /******/ 24 | /******/ // Execute the module function 25 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 26 | /******/ 27 | /******/ // Flag the module as loaded 28 | /******/ module.l = true; 29 | /******/ 30 | /******/ // Return the exports of the module 31 | /******/ return module.exports; 32 | /******/ } 33 | /******/ 34 | /******/ 35 | /******/ // expose the modules object (__webpack_modules__) 36 | /******/ __webpack_require__.m = modules; 37 | /******/ 38 | /******/ // expose the module cache 39 | /******/ __webpack_require__.c = installedModules; 40 | /******/ 41 | /******/ // define getter function for harmony exports 42 | /******/ __webpack_require__.d = function(exports, name, getter) { 43 | /******/ if(!__webpack_require__.o(exports, name)) { 44 | /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); 45 | /******/ } 46 | /******/ }; 47 | /******/ 48 | /******/ // define __esModule on exports 49 | /******/ __webpack_require__.r = function(exports) { 50 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 51 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 52 | /******/ } 53 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 54 | /******/ }; 55 | /******/ 56 | /******/ // create a fake namespace object 57 | /******/ // mode & 1: value is a module id, require it 58 | /******/ // mode & 2: merge all properties of value into the ns 59 | /******/ // mode & 4: return value when already ns object 60 | /******/ // mode & 8|1: behave like require 61 | /******/ __webpack_require__.t = function(value, mode) { 62 | /******/ if(mode & 1) value = __webpack_require__(value); 63 | /******/ if(mode & 8) return value; 64 | /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 65 | /******/ var ns = Object.create(null); 66 | /******/ __webpack_require__.r(ns); 67 | /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 68 | /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 69 | /******/ return ns; 70 | /******/ }; 71 | /******/ 72 | /******/ // getDefaultExport function for compatibility with non-harmony modules 73 | /******/ __webpack_require__.n = function(module) { 74 | /******/ var getter = module && module.__esModule ? 75 | /******/ function getDefault() { return module['default']; } : 76 | /******/ function getModuleExports() { return module; }; 77 | /******/ __webpack_require__.d(getter, 'a', getter); 78 | /******/ return getter; 79 | /******/ }; 80 | /******/ 81 | /******/ // Object.prototype.hasOwnProperty.call 82 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 83 | /******/ 84 | /******/ // __webpack_public_path__ 85 | /******/ __webpack_require__.p = ""; 86 | /******/ 87 | /******/ 88 | /******/ // Load entry module and return exports 89 | /******/ return __webpack_require__(__webpack_require__.s = "./src/get-fill-color.js"); 90 | /******/ }) 91 | /************************************************************************/ 92 | /******/ ({ 93 | 94 | /***/ "./src/get-fill-color.js": 95 | /*!*******************************!*\ 96 | !*** ./src/get-fill-color.js ***! 97 | \*******************************/ 98 | /*! exports provided: default */ 99 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 100 | 101 | "use strict"; 102 | __webpack_require__.r(__webpack_exports__); 103 | var Utils = __webpack_require__(/*! ./utils.js */ "./src/utils.js"); // My plugin (command shift s) 104 | 105 | 106 | /* harmony default export */ __webpack_exports__["default"] = (function (context) { 107 | var selection = context.selection; 108 | context.document.showMessage('Plugin 🏃'); 109 | 110 | if (selection.length == 0) { 111 | return context.document.showMessage('🗝🌈: Please select an object'); 112 | } // if its a text 113 | 114 | 115 | if (selection[0] instanceof MSTextLayer) { 116 | return context.document.showMessage('❌: Please use `Tokenizer > Get Tone` for texts'); 117 | } 118 | 119 | var colorMapping = Utils.getBaseColorsVariablesMapping(); 120 | console.log('colorMapping', colorMapping); 121 | var currentSelectedColor = Utils.getFillHexColor(selection).toString().toUpperCase(); 122 | var color = colorMapping['#' + currentSelectedColor]; 123 | 124 | var callback = function callback() { 125 | return getFillColorVariable(selection, color); 126 | }; // checks if color belongs to UI Kit, if not returns an error 127 | 128 | 129 | Utils.colorChecker(color, callback); 130 | }); 131 | 132 | function getFillColorVariable(selection, text) { 133 | // gets the position of selection 134 | var x = selection[0].frame().x(); 135 | var selectedElementWidth = selection[0].frame().width(); 136 | var midY = selection[0].frame().midY(); 137 | var position = { 138 | x: x, 139 | y: midY, 140 | width: selectedElementWidth 141 | }; 142 | Utils.insertTokenText(position, 'Token', 'Fill color: ', text); 143 | } 144 | 145 | /***/ }), 146 | 147 | /***/ "./src/utils.js": 148 | /*!**********************!*\ 149 | !*** ./src/utils.js ***! 150 | \**********************/ 151 | /*! exports provided: insertTokenText, createQuoteLine, createTextLayer, getTokenVariable, getFillHexColor, getBorderHexColor, getRGBColor, getHexValueFromColorVariable, colorChecker, getBaseColorsVariablesMapping */ 152 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 153 | 154 | "use strict"; 155 | __webpack_require__.r(__webpack_exports__); 156 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "insertTokenText", function() { return insertTokenText; }); 157 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createQuoteLine", function() { return createQuoteLine; }); 158 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createTextLayer", function() { return createTextLayer; }); 159 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getTokenVariable", function() { return getTokenVariable; }); 160 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getFillHexColor", function() { return getFillHexColor; }); 161 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getBorderHexColor", function() { return getBorderHexColor; }); 162 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getRGBColor", function() { return getRGBColor; }); 163 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getHexValueFromColorVariable", function() { return getHexValueFromColorVariable; }); 164 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "colorChecker", function() { return colorChecker; }); 165 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getBaseColorsVariablesMapping", function() { return getBaseColorsVariablesMapping; }); 166 | var quoteColor = { 167 | r: 1, 168 | g: 0.369, 169 | b: 0.941, 170 | a: 1 171 | }; // UI Creators 172 | 173 | function insertTokenText(_ref, layerName, title, text) { 174 | var x = _ref.x, 175 | y = _ref.y, 176 | width = _ref.width; 177 | var isBorder = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false; 178 | var textWithToken = createTextLayer(layerName, title + text); // pass the position to the text layer to be inserted 179 | 180 | textWithToken.frame().x = x + width + 100; 181 | textWithToken.frame().midY = y; // pass the position to quote line 182 | 183 | createQuoteLine(x, y, width, isBorder); // add the layer to the artboar 184 | 185 | context.document.currentPage().addLayers([textWithToken]); 186 | } 187 | function createQuoteLine(x, y, elementWidth, isBorder) { 188 | // if its a border, we want the quote line to touch it, otherwise touch fill 189 | var touchOffset = isBorder ? 0 : 5; // if its a border, we want the quote line to start from the same point as fill quoted line 190 | 191 | var startPointOffset = isBorder ? 30 : 0; 192 | var path = NSBezierPath.bezierPath(); 193 | path.moveToPoint(NSMakePoint(x + elementWidth - touchOffset, y + startPointOffset)); 194 | path.lineToPoint(NSMakePoint(x + elementWidth + 90, y)); 195 | var shape = MSShapeGroup.shapeWithBezierPath(MSPath.pathWithBezierPath(path)); 196 | var border = shape.style().addStylePartOfType(1); 197 | border.color = MSColor.colorWithRGBADictionary(quoteColor); 198 | border.thickness = 1; 199 | context.document.currentPage().addLayers([shape]); 200 | } 201 | function createTextLayer(name, stringValue) { 202 | var textLayer = MSTextLayer.new(); 203 | textLayer.stringValue = stringValue; 204 | textLayer.name = name; 205 | textLayer.setTextColor(MSColor.colorWithRGBADictionary(quoteColor)); 206 | return textLayer; 207 | } // Token getters 208 | 209 | function getTokenVariable(colorsMap, wholeObject, property, component, hexColor) { 210 | if (!colorsMap) { 211 | return context.document.showMessage('✋🏻❌: Please load a decisions base colors file before continuing'); 212 | } 213 | 214 | if (!wholeObject) { 215 | return context.document.showMessage("\u270B\uD83C\uDFFB\u274C: Please load a decisions token file for ".concat(property, " before continuing")); 216 | } 217 | 218 | var prefix = '--token'; // if property has `-`, splits it 219 | 220 | var hasDash = /-/; 221 | var propertyPrefix = hasDash.test(property) ? property.split('-') : property; // gets the color from selected element 222 | 223 | var selectedColor = colorsMap[hexColor].replace('--color-', ''); 224 | var states; 225 | var propertyName; 226 | 227 | if (propertyPrefix instanceof Array) { 228 | states = wholeObject['token'][propertyPrefix[0]][propertyPrefix[1]][component]; 229 | propertyName = "".concat(propertyPrefix[0], "-").concat(propertyPrefix[1]); 230 | } else { 231 | states = wholeObject['token'][propertyPrefix][component]; 232 | propertyName = propertyPrefix; 233 | } 234 | 235 | var selectedState = Object.keys(states).find(function (state) { 236 | return states[state] == selectedColor; 237 | }); 238 | return "".concat(prefix, "-").concat(propertyName, "-").concat(component, "-").concat(selectedState); 239 | } // Base color getters 240 | 241 | function getFillHexColor(selection) { 242 | var layer = context.selection[0]; 243 | var selectedColor = getRGBColor('fill', layer); 244 | var colorHex = selectedColor.immutableModelObject().hexValue().toString(); 245 | return colorHex; 246 | } 247 | function getBorderHexColor(selection) { 248 | var layer = context.selection[0]; 249 | var selectedColor = getRGBColor('border', layer); 250 | var colorHex = selectedColor.immutableModelObject().hexValue().toString(); 251 | return colorHex; 252 | } 253 | function getRGBColor(type, layer) { 254 | var color; 255 | 256 | if (type === 'fill') { 257 | if (layer instanceof MSTextLayer) { 258 | color = layer.textColor(); 259 | } else { 260 | color = layer.style().fills().firstObject().color(); 261 | } 262 | } else { 263 | color = layer.style().borders().firstObject().color(); 264 | } 265 | 266 | return color; 267 | } 268 | function getHexValueFromColorVariable(colorVar, baseColorsVariablesMap) { 269 | var colorVarWithPrefix = "--color-".concat(colorVar); 270 | return Object.keys(baseColorsVariablesMap).find(function (hexVal) { 271 | if (baseColorsVariablesMap[hexVal] == colorVarWithPrefix) return hexVal; 272 | }); 273 | } // Checkers 274 | 275 | function colorChecker(color, callback) { 276 | if (typeof color === 'undefined') { 277 | return context.document.showMessage('🎨🚫: Non UI Kit color. Please make sure to use a valid color'); 278 | } else { 279 | return callback(); 280 | } 281 | } // General scripts 282 | 283 | function getBaseColorsVariablesMapping() { 284 | // Gets the json data stored in global state 285 | var threadDictionary = NSThread.mainThread().threadDictionary(); 286 | var importedBaseColors = threadDictionary.importedBaseColors; 287 | if (!importedBaseColors) return context.document.showMessage('🗃👎🏻 No file imported. Please import your base colors file in `Import base colors file...`'); 288 | var colorNames = {}; // gets default color variables 289 | 290 | Object.keys(importedBaseColors).map(function (colorGroupName) { 291 | // console.log('colorGroupName', colorGroupName) 292 | var colorGroup = importedBaseColors[colorGroupName]; 293 | var colorDefaultName = colorGroup.default; 294 | colorNames[colorDefaultName.toString().toUpperCase()] = '--color-' + colorGroupName; // console.log('colorGroup.default', colorGroup.default); 295 | 296 | Object.keys(colorGroup).forEach(function (variation) { 297 | // filters out default values 298 | if (variation !== 'default') { 299 | var variationName = colorGroup[variation]; 300 | var variationNameWithoutPercetageSign = variationName.toString().replace('%', ''); // console.log('colorGroup.default', colorGroup.default) 301 | 302 | colorNames[transformColorLightness(colorGroup.default, variationNameWithoutPercetageSign).toUpperCase()] = '--color-' + colorGroupName + '-' + variation; 303 | } 304 | }); 305 | }); 306 | return colorNames; 307 | } // Color converters 308 | 309 | function transformColorLightness(hex, lightness) { 310 | var hslColor = hexToHsl(hex, lightness); 311 | var hexColor = hslToHex(hslColor); 312 | console.log('hexColor', hexColor); 313 | return hexColor; 314 | } 315 | 316 | function hexToHsl(hex, lightness) { 317 | var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 318 | var r = parseInt(result[1], 16); 319 | var g = parseInt(result[2], 16); 320 | var b = parseInt(result[3], 16); 321 | r /= 255, g /= 255, b /= 255; 322 | var max = Math.max(r, g, b), 323 | min = Math.min(r, g, b); 324 | var h, 325 | s, 326 | l = (max + min) / 2; 327 | 328 | if (max == min) { 329 | h = s = 0; // achromatic 330 | } else { 331 | var d = max - min; 332 | s = l > 0.5 ? d / (2 - max - min) : d / (max + min); 333 | 334 | switch (max) { 335 | case r: 336 | h = (g - b) / d + (g < b ? 6 : 0); 337 | break; 338 | 339 | case g: 340 | h = (b - r) / d + 2; 341 | break; 342 | 343 | case b: 344 | h = (r - g) / d + 4; 345 | break; 346 | } 347 | 348 | h /= 6; 349 | } 350 | 351 | h = Math.round(360 * h); 352 | s = s * 100; 353 | s = Math.round(s); 354 | l = l * 100; 355 | l = lightness ? lightness : Math.round(l); 356 | return [h, s, l]; 357 | } 358 | 359 | function hslToHex(hsl) { 360 | var rgbColor = hslToRgb(hsl[0], hsl[1], hsl[2]); 361 | var r = rgbColor[0]; 362 | var g = rgbColor[1]; 363 | var b = rgbColor[2]; // console.log('rgb', r, g, b) 364 | 365 | return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); 366 | } 367 | 368 | function hslToRgb(h, s, l) { 369 | var m1, m2, hue; 370 | s = s / 100; 371 | l = l / 100; 372 | var r, g, b; 373 | if (s == 0) r = g = b = l * 255;else { 374 | m2 = l < 0.5 ? l * (1 + s) : l + s - l * s; 375 | m1 = 2 * l - m2; 376 | hue = h / 360; 377 | r = hue2rgb(m1, m2, hue + 1 / 3); 378 | g = hue2rgb(m1, m2, hue); 379 | b = hue2rgb(m1, m2, hue - 1 / 3); 380 | } 381 | 382 | function multiplyBy255(num) { 383 | return num * 255; 384 | } 385 | 386 | if (r < 1 || g < 1 || b < 1) { 387 | r = multiplyBy255(r); 388 | g = multiplyBy255(g); 389 | b = multiplyBy255(b); 390 | } 391 | 392 | console.log('rgb', Math.round(r), Math.round(g), Math.round(b)); 393 | return [Math.round(r), Math.round(g), Math.round(b)]; 394 | } 395 | 396 | function hue2rgb(m1, m2, hue) { 397 | if (hue < 0) hue += 1; 398 | if (hue > 1) hue -= 1; 399 | if (hue < 1 / 6) return m1 + (m2 - m1) * 6 * hue; 400 | if (hue < 1 / 2) return m2; 401 | if (hue < 2 / 3) return m1 + (m2 - m1) * (2 / 3 - hue) * 6; 402 | return m1; 403 | } 404 | 405 | /***/ }) 406 | 407 | /******/ }); 408 | if (key === 'default' && typeof exports === 'function') { 409 | exports(context); 410 | } else { 411 | exports[key](context); 412 | } 413 | } 414 | that['onRun'] = __skpm_run.bind(this, 'default') 415 | 416 | //# sourceMappingURL=get-fill-color.js.map -------------------------------------------------------------------------------- /sketch-tokenizer.sketchplugin/Contents/Sketch/get-fill-color.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack://exports/webpack/bootstrap","webpack://exports/./src/get-fill-color.js","webpack://exports/./src/utils.js"],"names":["Utils","require","context","selection","document","showMessage","length","MSTextLayer","colorMapping","getBaseColorsVariablesMapping","console","log","currentSelectedColor","getFillHexColor","toString","toUpperCase","color","callback","getFillColorVariable","colorChecker","text","x","frame","selectedElementWidth","width","midY","position","y","insertTokenText","quoteColor","r","g","b","a","layerName","title","isBorder","textWithToken","createTextLayer","createQuoteLine","currentPage","addLayers","elementWidth","touchOffset","startPointOffset","path","NSBezierPath","bezierPath","moveToPoint","NSMakePoint","lineToPoint","shape","MSShapeGroup","shapeWithBezierPath","MSPath","pathWithBezierPath","border","style","addStylePartOfType","MSColor","colorWithRGBADictionary","thickness","name","stringValue","textLayer","new","setTextColor","getTokenVariable","colorsMap","wholeObject","property","component","hexColor","prefix","hasDash","propertyPrefix","test","split","selectedColor","replace","states","propertyName","Array","selectedState","Object","keys","find","state","layer","getRGBColor","colorHex","immutableModelObject","hexValue","getBorderHexColor","type","textColor","fills","firstObject","borders","getHexValueFromColorVariable","colorVar","baseColorsVariablesMap","colorVarWithPrefix","hexVal","threadDictionary","NSThread","mainThread","importedBaseColors","colorNames","map","colorGroup","colorGroupName","colorDefaultName","default","forEach","variation","variationName","variationNameWithoutPercetageSign","transformColorLightness","hex","lightness","hslColor","hexToHsl","hslToHex","result","exec","parseInt","max","Math","min","h","s","l","d","round","hsl","rgbColor","hslToRgb","slice","m1","m2","hue","hue2rgb","multiplyBy255","num"],"mappings":"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","file":"get-fill-color.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = \"./src/get-fill-color.js\");\n","const Utils = require('./utils.js');\n\n// My plugin (command shift s)\nexport default function(context) {\n var selection = context.selection;\n context.document.showMessage('Plugin 🏃');\n\n if (selection.length == 0) {\n return context.document.showMessage('🗝🌈: Please select an object');\n }\n // if its a text\n if (selection[0] instanceof MSTextLayer) {\n return context.document.showMessage(\n '❌: Please use `Tokenizer > Get Tone` for texts'\n );\n }\n\n const colorMapping = Utils.getBaseColorsVariablesMapping();\n console.log('colorMapping', colorMapping);\n const currentSelectedColor = Utils.getFillHexColor(selection)\n .toString()\n .toUpperCase();\n\n const color = colorMapping['#' + currentSelectedColor];\n\n const callback = () => getFillColorVariable(selection, color);\n\n // checks if color belongs to UI Kit, if not returns an error\n Utils.colorChecker(color, callback);\n}\n\nfunction getFillColorVariable(selection, text) {\n // gets the position of selection\n var x = selection[0].frame().x();\n var selectedElementWidth = selection[0].frame().width();\n var midY = selection[0].frame().midY();\n\n const position = {\n x,\n y: midY,\n width: selectedElementWidth\n };\n Utils.insertTokenText(position, 'Token', 'Fill color: ', text);\n}\n","const quoteColor = { r: 1, g: 0.369, b: 0.941, a: 1 };\n\n// UI Creators\n\nexport function insertTokenText(\n { x, y, width },\n layerName,\n title,\n text,\n isBorder = false\n) {\n const textWithToken = createTextLayer(layerName, title + text);\n // pass the position to the text layer to be inserted\n textWithToken.frame().x = x + width + 100;\n textWithToken.frame().midY = y;\n\n // pass the position to quote line\n createQuoteLine(x, y, width, isBorder);\n\n // add the layer to the artboar\n context.document.currentPage().addLayers([textWithToken]);\n}\n\nexport function createQuoteLine(x, y, elementWidth, isBorder) {\n // if its a border, we want the quote line to touch it, otherwise touch fill\n const touchOffset = isBorder ? 0 : 5;\n\n // if its a border, we want the quote line to start from the same point as fill quoted line\n const startPointOffset = isBorder ? 30 : 0;\n var path = NSBezierPath.bezierPath();\n path.moveToPoint(\n NSMakePoint(x + elementWidth - touchOffset, y + startPointOffset)\n );\n path.lineToPoint(NSMakePoint(x + elementWidth + 90, y));\n\n var shape = MSShapeGroup.shapeWithBezierPath(MSPath.pathWithBezierPath(path));\n var border = shape.style().addStylePartOfType(1);\n border.color = MSColor.colorWithRGBADictionary(quoteColor);\n border.thickness = 1;\n\n context.document.currentPage().addLayers([shape]);\n}\n\nexport function createTextLayer(name, stringValue) {\n var textLayer = MSTextLayer.new();\n textLayer.stringValue = stringValue;\n textLayer.name = name;\n textLayer.setTextColor(MSColor.colorWithRGBADictionary(quoteColor));\n return textLayer;\n}\n\n// Token getters\n\nexport function getTokenVariable(\n colorsMap,\n wholeObject,\n property,\n component,\n hexColor\n) {\n if (!colorsMap) {\n return context.document.showMessage(\n '✋🏻❌: Please load a decisions base colors file before continuing'\n );\n }\n\n if (!wholeObject) {\n return context.document.showMessage(\n `✋🏻❌: Please load a decisions token file for ${property} before continuing`\n );\n }\n\n const prefix = '--token';\n\n // if property has `-`, splits it\n const hasDash = /-/;\n const propertyPrefix = hasDash.test(property)\n ? property.split('-')\n : property;\n\n // gets the color from selected element\n const selectedColor = colorsMap[hexColor].replace('--color-', '');\n\n let states;\n let propertyName;\n if (propertyPrefix instanceof Array) {\n states =\n wholeObject['token'][propertyPrefix[0]][propertyPrefix[1]][component];\n propertyName = `${propertyPrefix[0]}-${propertyPrefix[1]}`;\n } else {\n states = wholeObject['token'][propertyPrefix][component];\n propertyName = propertyPrefix;\n }\n\n const selectedState = Object.keys(states).find(\n state => states[state] == selectedColor\n );\n\n return `${prefix}-${propertyName}-${component}-${selectedState}`;\n}\n\n// Base color getters\n\nexport function getFillHexColor(selection) {\n var layer = context.selection[0];\n var selectedColor = getRGBColor('fill', layer);\n var colorHex = selectedColor\n .immutableModelObject()\n .hexValue()\n .toString();\n return colorHex;\n}\n\nexport function getBorderHexColor(selection) {\n var layer = context.selection[0];\n var selectedColor = getRGBColor('border', layer);\n var colorHex = selectedColor\n .immutableModelObject()\n .hexValue()\n .toString();\n return colorHex;\n}\n\nexport function getRGBColor(type, layer) {\n var color;\n\n if (type === 'fill') {\n if (layer instanceof MSTextLayer) {\n color = layer.textColor();\n } else {\n color = layer\n .style()\n .fills()\n .firstObject()\n .color();\n }\n } else {\n color = layer\n .style()\n .borders()\n .firstObject()\n .color();\n }\n\n return color;\n}\n\nexport function getHexValueFromColorVariable(colorVar, baseColorsVariablesMap) {\n const colorVarWithPrefix = `--color-${colorVar}`;\n return Object.keys(baseColorsVariablesMap).find(hexVal => {\n if (baseColorsVariablesMap[hexVal] == colorVarWithPrefix) return hexVal;\n });\n}\n\n// Checkers\n\nexport function colorChecker(color, callback) {\n if (typeof color === 'undefined') {\n return context.document.showMessage(\n '🎨🚫: Non UI Kit color. Please make sure to use a valid color'\n );\n } else {\n return callback();\n }\n}\n\n// General scripts\n\nexport function getBaseColorsVariablesMapping() {\n // Gets the json data stored in global state\n let threadDictionary = NSThread.mainThread().threadDictionary();\n let importedBaseColors = threadDictionary.importedBaseColors;\n if (!importedBaseColors)\n return context.document.showMessage(\n '🗃👎🏻 No file imported. Please import your base colors file in `Import base colors file...`'\n );\n\n const colorNames = {};\n // gets default color variables\n Object.keys(importedBaseColors).map(colorGroupName => {\n // console.log('colorGroupName', colorGroupName)\n const colorGroup = importedBaseColors[colorGroupName];\n const colorDefaultName = colorGroup.default;\n colorNames[colorDefaultName.toString().toUpperCase()] =\n '--color-' + colorGroupName;\n\n // console.log('colorGroup.default', colorGroup.default);\n\n Object.keys(colorGroup).forEach(variation => {\n // filters out default values\n if (variation !== 'default') {\n const variationName = colorGroup[variation];\n const variationNameWithoutPercetageSign = variationName\n .toString()\n .replace('%', '');\n // console.log('colorGroup.default', colorGroup.default)\n colorNames[\n transformColorLightness(\n colorGroup.default,\n variationNameWithoutPercetageSign\n ).toUpperCase()\n ] =\n '--color-' + colorGroupName + '-' + variation;\n }\n });\n });\n return colorNames;\n}\n\n// Color converters\n\nfunction transformColorLightness(hex, lightness) {\n const hslColor = hexToHsl(hex, lightness);\n const hexColor = hslToHex(hslColor);\n console.log('hexColor', hexColor);\n return hexColor;\n}\n\nfunction hexToHsl(hex, lightness) {\n var result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\n\n var r = parseInt(result[1], 16);\n var g = parseInt(result[2], 16);\n var b = parseInt(result[3], 16);\n\n (r /= 255), (g /= 255), (b /= 255);\n var max = Math.max(r, g, b),\n min = Math.min(r, g, b);\n var h,\n s,\n l = (max + min) / 2;\n\n if (max == min) {\n h = s = 0; // achromatic\n } else {\n var d = max - min;\n s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n switch (max) {\n case r:\n h = (g - b) / d + (g < b ? 6 : 0);\n break;\n case g:\n h = (b - r) / d + 2;\n break;\n case b:\n h = (r - g) / d + 4;\n break;\n }\n h /= 6;\n }\n\n h = Math.round(360 * h);\n s = s * 100;\n s = Math.round(s);\n l = l * 100;\n l = lightness ? lightness : Math.round(l);\n\n return [h, s, l];\n}\n\nfunction hslToHex(hsl) {\n const rgbColor = hslToRgb(hsl[0], hsl[1], hsl[2]);\n const r = rgbColor[0];\n const g = rgbColor[1];\n const b = rgbColor[2];\n\n // console.log('rgb', r, g, b)\n\n return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);\n}\n\nfunction hslToRgb(h, s, l) {\n var m1, m2, hue;\n s = s / 100;\n l = l / 100;\n var r, g, b;\n\n if (s == 0) r = g = b = l * 255;\n else {\n m2 = l < 0.5 ? l * (1 + s) : l + s - l * s;\n m1 = 2 * l - m2;\n hue = h / 360;\n\n r = hue2rgb(m1, m2, hue + 1 / 3);\n g = hue2rgb(m1, m2, hue);\n b = hue2rgb(m1, m2, hue - 1 / 3);\n }\n\n function multiplyBy255(num) {\n return num * 255;\n }\n\n if (r < 1 || g < 1 || b < 1) {\n r = multiplyBy255(r);\n g = multiplyBy255(g);\n b = multiplyBy255(b);\n }\n\n console.log('rgb', Math.round(r), Math.round(g), Math.round(b));\n\n return [Math.round(r), Math.round(g), Math.round(b)];\n}\n\nfunction hue2rgb(m1, m2, hue) {\n if (hue < 0) hue += 1;\n if (hue > 1) hue -= 1;\n if (hue < 1 / 6) return m1 + (m2 - m1) * 6 * hue;\n if (hue < 1 / 2) return m2;\n if (hue < 2 / 3) return m1 + (m2 - m1) * (2 / 3 - hue) * 6;\n return m1;\n}\n"],"sourceRoot":""} -------------------------------------------------------------------------------- /sketch-tokenizer.sketchplugin/Contents/Sketch/import-base-colors-decisions-file.js: -------------------------------------------------------------------------------- 1 | var that = this; 2 | function __skpm_run (key, context) { 3 | that.context = context; 4 | 5 | var exports = 6 | /******/ (function(modules) { // webpackBootstrap 7 | /******/ // The module cache 8 | /******/ var installedModules = {}; 9 | /******/ 10 | /******/ // The require function 11 | /******/ function __webpack_require__(moduleId) { 12 | /******/ 13 | /******/ // Check if module is in cache 14 | /******/ if(installedModules[moduleId]) { 15 | /******/ return installedModules[moduleId].exports; 16 | /******/ } 17 | /******/ // Create a new module (and put it into the cache) 18 | /******/ var module = installedModules[moduleId] = { 19 | /******/ i: moduleId, 20 | /******/ l: false, 21 | /******/ exports: {} 22 | /******/ }; 23 | /******/ 24 | /******/ // Execute the module function 25 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 26 | /******/ 27 | /******/ // Flag the module as loaded 28 | /******/ module.l = true; 29 | /******/ 30 | /******/ // Return the exports of the module 31 | /******/ return module.exports; 32 | /******/ } 33 | /******/ 34 | /******/ 35 | /******/ // expose the modules object (__webpack_modules__) 36 | /******/ __webpack_require__.m = modules; 37 | /******/ 38 | /******/ // expose the module cache 39 | /******/ __webpack_require__.c = installedModules; 40 | /******/ 41 | /******/ // define getter function for harmony exports 42 | /******/ __webpack_require__.d = function(exports, name, getter) { 43 | /******/ if(!__webpack_require__.o(exports, name)) { 44 | /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); 45 | /******/ } 46 | /******/ }; 47 | /******/ 48 | /******/ // define __esModule on exports 49 | /******/ __webpack_require__.r = function(exports) { 50 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 51 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 52 | /******/ } 53 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 54 | /******/ }; 55 | /******/ 56 | /******/ // create a fake namespace object 57 | /******/ // mode & 1: value is a module id, require it 58 | /******/ // mode & 2: merge all properties of value into the ns 59 | /******/ // mode & 4: return value when already ns object 60 | /******/ // mode & 8|1: behave like require 61 | /******/ __webpack_require__.t = function(value, mode) { 62 | /******/ if(mode & 1) value = __webpack_require__(value); 63 | /******/ if(mode & 8) return value; 64 | /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 65 | /******/ var ns = Object.create(null); 66 | /******/ __webpack_require__.r(ns); 67 | /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 68 | /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 69 | /******/ return ns; 70 | /******/ }; 71 | /******/ 72 | /******/ // getDefaultExport function for compatibility with non-harmony modules 73 | /******/ __webpack_require__.n = function(module) { 74 | /******/ var getter = module && module.__esModule ? 75 | /******/ function getDefault() { return module['default']; } : 76 | /******/ function getModuleExports() { return module; }; 77 | /******/ __webpack_require__.d(getter, 'a', getter); 78 | /******/ return getter; 79 | /******/ }; 80 | /******/ 81 | /******/ // Object.prototype.hasOwnProperty.call 82 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 83 | /******/ 84 | /******/ // __webpack_public_path__ 85 | /******/ __webpack_require__.p = ""; 86 | /******/ 87 | /******/ 88 | /******/ // Load entry module and return exports 89 | /******/ return __webpack_require__(__webpack_require__.s = "./src/menu-import/import-base-colors-decisions-file.js"); 90 | /******/ }) 91 | /************************************************************************/ 92 | /******/ ({ 93 | 94 | /***/ "./src/converters/colors.js": 95 | /*!**********************************!*\ 96 | !*** ./src/converters/colors.js ***! 97 | \**********************************/ 98 | /*! exports provided: transformColorLightness */ 99 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 100 | 101 | "use strict"; 102 | __webpack_require__.r(__webpack_exports__); 103 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "transformColorLightness", function() { return transformColorLightness; }); 104 | function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } 105 | 106 | function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } 107 | 108 | function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } 109 | 110 | function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } 111 | 112 | // Color converters 113 | function transformColorLightness(hex, lightness) { 114 | /* A bit of crazyness happening here; 115 | But this is the workflow from hsl_picker plugin to 116 | generate colors in sketch, so the same scheme is below */ 117 | // HEXtoRGB => RgbToHsl => change light => HSLtoRGB => RGBtoHSL => HSLtoHEX 118 | var colorRgb = HEXtoRGB(hex); 119 | var colorHsl = RGBtoHSL(colorRgb, lightness); 120 | var colorRgbTransformed = HSLtoRGB(colorHsl); 121 | var colorHslTransformed = RGBtoHSL(colorRgbTransformed); 122 | var colorHex = HSLtoHEX(colorHslTransformed); 123 | return colorHex; 124 | } 125 | 126 | function HEXtoRGB(hex) { 127 | var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 128 | return result ? [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)] : null; 129 | } 130 | 131 | function RGBtoHSL(_ref, lightness) { 132 | var _ref2 = _slicedToArray(_ref, 3), 133 | r = _ref2[0], 134 | g = _ref2[1], 135 | b = _ref2[2]; 136 | 137 | r /= 255, g /= 255, b /= 255; 138 | var max = Math.max(r, g, b), 139 | min = Math.min(r, g, b); 140 | var h, 141 | s, 142 | l = (max + min) / 2; 143 | 144 | if (max == min) { 145 | h = s = 0; // achromatic 146 | } else { 147 | var d = max - min; 148 | s = l > 0.5 ? d / (2 - max - min) : d / (max + min); 149 | 150 | switch (max) { 151 | case r: 152 | h = (g - b) / d + (g < b ? 6 : 0); 153 | break; 154 | 155 | case g: 156 | h = (b - r) / d + 2; 157 | break; 158 | 159 | case b: 160 | h = (r - g) / d + 4; 161 | break; 162 | } 163 | 164 | h /= 6; 165 | } 166 | 167 | return [Math.round(h * 360), Math.round(s * 100), lightness ? parseInt(lightness) : Math.round(l * 100)]; 168 | } 169 | 170 | function HSLtoHEX(hsl) { 171 | var rgbColor = HSLtoRGB([hsl[0], hsl[1], hsl[2]]); 172 | var r = rgbColor[0]; 173 | var g = rgbColor[1]; 174 | var b = rgbColor[2]; // console.log('rgb', r, g, b) 175 | 176 | return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); 177 | } 178 | 179 | function HSLtoRGB(_ref3) { 180 | var _ref4 = _slicedToArray(_ref3, 3), 181 | h = _ref4[0], 182 | s = _ref4[1], 183 | l = _ref4[2]; 184 | 185 | var m1, m2, hue; 186 | s = s / 100; 187 | l = l / 100; 188 | var r, g, b; 189 | if (s == 0) r = g = b = l * 255;else { 190 | m2 = l < 0.5 ? l * (1 + s) : l + s - l * s; 191 | m1 = 2 * l - m2; 192 | hue = h / 360; 193 | r = hue2rgb(m1, m2, hue + 1 / 3); 194 | g = hue2rgb(m1, m2, hue); 195 | b = hue2rgb(m1, m2, hue - 1 / 3); 196 | } 197 | 198 | function multiplyBy255(num) { 199 | return num * 255; 200 | } 201 | 202 | if (r < 1 || g < 1 || b < 1) { 203 | r = multiplyBy255(r); 204 | g = multiplyBy255(g); 205 | b = multiplyBy255(b); 206 | } // console.log('rgb', Math.round(r), Math.round(g), Math.round(b)); 207 | 208 | 209 | return [Math.round(r), Math.round(g), Math.round(b)]; 210 | } // Used inside HSLtoRGB function 211 | 212 | 213 | function hue2rgb(m1, m2, hue) { 214 | if (hue < 0) hue += 1; 215 | if (hue > 1) hue -= 1; 216 | if (hue < 1 / 6) return m1 + (m2 - m1) * 6 * hue; 217 | if (hue < 1 / 2) return m2; 218 | if (hue < 2 / 3) return m1 + (m2 - m1) * (2 / 3 - hue) * 6; 219 | return m1; 220 | } 221 | 222 | /***/ }), 223 | 224 | /***/ "./src/menu-import/import-base-colors-decisions-file.js": 225 | /*!**************************************************************!*\ 226 | !*** ./src/menu-import/import-base-colors-decisions-file.js ***! 227 | \**************************************************************/ 228 | /*! exports provided: default */ 229 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 230 | 231 | "use strict"; 232 | __webpack_require__.r(__webpack_exports__); 233 | var importFile = __webpack_require__(/*! ./../utils.js */ "./src/utils.js").importFile; 234 | 235 | /* harmony default export */ __webpack_exports__["default"] = (function (context) { 236 | var fileName = 'Base colors'; // the value global state will hold 237 | 238 | var objName = 'baseColors'; 239 | importFile(fileName, objName); 240 | context.document.showMessage("\uD83D\uDCE9\uD83C\uDF89: File for ".concat(fileName, " imported! Ready to use!")); 241 | }); 242 | 243 | /***/ }), 244 | 245 | /***/ "./src/utils.js": 246 | /*!**********************!*\ 247 | !*** ./src/utils.js ***! 248 | \**********************/ 249 | /*! exports provided: insertTokenText, insertIntoGroup, createQuoteLine, createTextLayer, getTokenVariable, getFillHexColor, getBorderHexColor, getRGBColor, getHexValueFromColorVariable, colorChecker, getBaseColorsVariablesMapping, importFile */ 250 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 251 | 252 | "use strict"; 253 | __webpack_require__.r(__webpack_exports__); 254 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "insertTokenText", function() { return insertTokenText; }); 255 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "insertIntoGroup", function() { return insertIntoGroup; }); 256 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createQuoteLine", function() { return createQuoteLine; }); 257 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createTextLayer", function() { return createTextLayer; }); 258 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getTokenVariable", function() { return getTokenVariable; }); 259 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getFillHexColor", function() { return getFillHexColor; }); 260 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getBorderHexColor", function() { return getBorderHexColor; }); 261 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getRGBColor", function() { return getRGBColor; }); 262 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getHexValueFromColorVariable", function() { return getHexValueFromColorVariable; }); 263 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "colorChecker", function() { return colorChecker; }); 264 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getBaseColorsVariablesMapping", function() { return getBaseColorsVariablesMapping; }); 265 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "importFile", function() { return importFile; }); 266 | function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; } 267 | 268 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } 269 | 270 | var ColorConverter = __webpack_require__(/*! ./converters/colors.js */ "./src/converters/colors.js"); 271 | 272 | var quoteColor = { 273 | r: 1, 274 | g: 0.369, 275 | b: 0.941, 276 | a: 1 277 | }; 278 | var lineHeight = 14; 279 | var lineWidth = 85; // UI Creators 280 | 281 | function insertTokenText(position, layerGroupName, title, text) { 282 | var isBorder = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false; 283 | var capitalizedTitle = title[0].toUpperCase() + title.slice(1); 284 | var textWithToken = createTextLayer("".concat(capitalizedTitle, ": ").concat(text)); 285 | var quoteLine = createQuoteLine(position, isBorder); // var bounds = MSLayerGroup.groupBoundsForContainer( 286 | // MSLayerArray.arrayWithLayers([quoteLine, textWithToken]) 287 | // ); 288 | 289 | insertIntoGroup(layerGroupName, title, { 290 | text: textWithToken, 291 | line: quoteLine 292 | }, position, isBorder); 293 | } 294 | function insertIntoGroup(layerGroupName, property, layers, position, isBorder) { 295 | var groupLayer = MSLayerGroup.new(); // to simulate the heigt/width 296 | 297 | var bounds = MSLayerGroup.groupBoundsForContainer(MSLayerArray.arrayWithLayers([layers.line, layers.text])); // if its a border, we want the quote line to touch it, otherwise touch fill 298 | 299 | var touchOffset = isBorder ? 0 : 5; // if its a border TOKEN, we want the quote line to start from the same point as fill quoted line 300 | 301 | var startingPointOffset = isBorder ? lineHeight : 0; // spacing between line and text 302 | 303 | var spacing = 4; // moves the text a bit further from object 304 | 305 | layers.text.frame().x = lineWidth + spacing; 306 | 307 | if (isBorder) { 308 | layers.text.frame().y = -lineHeight; 309 | } 310 | 311 | groupLayer.name = "Token ".concat(property, " for ").concat(layerGroupName); 312 | groupLayer.layers = [layers.line, layers.text]; 313 | groupLayer.resizeToFitChildrenWithOption(1); 314 | groupLayer.frame().x = position.x + position.width - touchOffset; 315 | groupLayer.frame().y = position.y + position.midY - bounds.size.height / 2 - startingPointOffset; 316 | var currentParentGroup = context.document.currentPage().currentArtboard() || context.document.currentPage(); 317 | currentParentGroup.addLayers([groupLayer]); 318 | } 319 | function createQuoteLine(position, isBorder) { 320 | var lineHeightMidY = lineHeight / 2; // if its a border TOKEN, we want the quote line to start from the same point as fill quoted line 321 | 322 | var startingPointOffset = isBorder ? 15 : 0; 323 | var path = NSBezierPath.bezierPath(); 324 | path.moveToPoint(NSMakePoint(lineWidth, lineHeightMidY - startingPointOffset)); 325 | path.lineToPoint(NSMakePoint(0, lineHeightMidY)); 326 | var shape = MSShapeGroup.shapeWithBezierPath(MSPath.pathWithBezierPath(path)); 327 | var border = shape.style().addStylePartOfType(1); 328 | border.color = MSColor.colorWithRGBADictionary(quoteColor); 329 | border.thickness = 1; 330 | return shape; 331 | } 332 | function createTextLayer(stringValue) { 333 | var textLayer = MSTextLayer.new(); 334 | textLayer.stringValue = stringValue; 335 | textLayer.name = 'Text'; 336 | textLayer.setTextColor(MSColor.colorWithRGBADictionary(quoteColor)); 337 | return textLayer; 338 | } // Token getters 339 | 340 | function getTokenVariable(property, component, hexColor) { 341 | var baseColorsMap = getBaseColorsVariablesMapping(); 342 | var prefix = '--token'; // if property has `-`, splits it 343 | 344 | var hasDash = /-/; 345 | var propertyPrefix = hasDash.test(property) ? property.split('-') : property; 346 | var states; 347 | var decisionsFile; 348 | var propertyName; // if the propery is passed with dash (E.g border-color) 349 | 350 | if (propertyPrefix instanceof Array) { 351 | decisionsFile = getDecisionsJson(propertyPrefix[0]); 352 | 353 | if (!decisionsFile) { 354 | return context.document.showMessage("\u270B\uD83C\uDFFB\u274C: Please load a decisions token file for ".concat(property, " before continuing")); 355 | } 356 | 357 | states = decisionsFile[propertyPrefix[1]][component]; 358 | propertyName = "".concat(propertyPrefix[0], "-").concat(propertyPrefix[1]); 359 | } else { 360 | decisionsFile = getDecisionsJson(propertyPrefix); 361 | 362 | if (!decisionsFile) { 363 | return context.document.showMessage("\u270B\uD83C\uDFFB\u274C: Please load a decisions token file for ".concat(property, " before continuing")); 364 | } 365 | 366 | states = decisionsFile[propertyPrefix][component]; 367 | propertyName = propertyPrefix; 368 | } 369 | 370 | if (!baseColorsMap) { 371 | return context.document.showMessage('✋🏻❌: Please load a decisions base colors file before continuing'); 372 | } // gets the color from selected element 373 | 374 | 375 | var selectedColor = baseColorsMap[hexColor].replace('--color-', ''); 376 | var selectedState = Object.keys(states).find(function (state) { 377 | return states[state] == selectedColor; 378 | }); 379 | 380 | if (!selectedState) { 381 | return context.document.showMessage('🎨🚫: Non-recognized token color. Please make sure to use a valid color for this token'); 382 | } 383 | 384 | return "".concat(prefix, "-").concat(propertyName, "-").concat(component, "-").concat(selectedState); 385 | } // Base color getters 386 | 387 | function getFillHexColor(selection) { 388 | var layer = context.selection[0]; 389 | var selectedColor = getRGBColor('fill', layer); 390 | var colorHex = selectedColor.immutableModelObject().hexValue().toString(); 391 | return colorHex; 392 | } 393 | 394 | function getDecisionsJson(object) { 395 | // Gets the json data stored in global state 396 | var threadDictionary = NSThread.mainThread().threadDictionary(); 397 | var decisions = threadDictionary[object]; 398 | return decisions; 399 | } 400 | 401 | function getBorderHexColor(selection) { 402 | var layer = context.selection[0]; 403 | var selectedColor = getRGBColor('border', layer); 404 | var colorHex = selectedColor.immutableModelObject().hexValue().toString(); 405 | return colorHex; 406 | } 407 | function getRGBColor(type, layer) { 408 | var color; 409 | 410 | if (type === 'fill') { 411 | if (layer instanceof MSTextLayer) { 412 | color = layer.textColor(); 413 | } else { 414 | color = layer.style().fills().firstObject().color(); 415 | } 416 | } else { 417 | color = layer.style().borders().firstObject().color(); 418 | } 419 | 420 | return color; 421 | } 422 | function getHexValueFromColorVariable(colorVar, baseColorsVariablesMap) { 423 | var colorVarWithPrefix = "--color-".concat(colorVar); 424 | return Object.keys(baseColorsVariablesMap).find(function (hexVal) { 425 | if (baseColorsVariablesMap[hexVal] == colorVarWithPrefix) return hexVal; 426 | }); 427 | } // Checkers 428 | 429 | function colorChecker(color, callback) { 430 | if (typeof color === 'undefined') { 431 | return context.document.showMessage('🎨🚫: Non UI Kit color. Please make sure to use a valid color'); 432 | } else { 433 | return callback(); 434 | } 435 | } // General scripts 436 | 437 | function getBaseColorsVariablesMapping() { 438 | // Gets the json data stored in global state 439 | var importedBaseColors = getDecisionsJson('baseColors'); 440 | if (!importedBaseColors) return context.document.showMessage('🗃👎🏻 No file imported. Please import your base colors file in `Import base colors file...`'); 441 | var colorNames = {}; // gets default color variables 442 | 443 | Object.keys(importedBaseColors).map(function (colorGroupName) { 444 | var colorGroup = importedBaseColors[colorGroupName]; 445 | var colorDefaultName = colorGroup.default; 446 | colorNames[colorDefaultName.toString().toUpperCase()] = '--color-' + colorGroupName; 447 | Object.keys(colorGroup).forEach(function (variation) { 448 | // filters out default values 449 | if (variation !== 'default') { 450 | var variationName = colorGroup[variation]; 451 | var variationNameWithoutPercetageSign = variationName.toString().replace('%', ''); 452 | colorNames[ColorConverter.transformColorLightness(colorGroup.default, variationNameWithoutPercetageSign).toUpperCase()] = '--color-' + colorGroupName + '-' + variation; 453 | } 454 | }); 455 | }); 456 | return colorNames; 457 | } // importers 458 | 459 | function importFile(fileName, objName) { 460 | //ask for JSON file path, passing the last location if available 461 | var dataPath = askForJSON('lastJSONPath', fileName); 462 | if (!dataPath) return; //load json data 463 | 464 | var jsonData = loadJSONData(dataPath); 465 | if (!jsonData) return; //get root dir used when populating local images 466 | 467 | var jsonDir = NSString.stringWithString(dataPath).stringByDeletingLastPathComponent(); 468 | var threadDictionary = NSThread.mainThread().threadDictionary(); 469 | threadDictionary[objName] = _objectSpread({}, jsonData); 470 | } 471 | 472 | function askForJSON(path, fileName) { 473 | //create panel 474 | var panel = NSOpenPanel.openPanel(); //set panel properties 475 | 476 | panel.setTitle('Select JSON'); 477 | panel.setMessage("Please select the JSON file for ".concat(fileName)); 478 | panel.setPrompt('Select'); 479 | panel.setCanCreateDirectories(false); 480 | panel.setCanChooseFiles(true); 481 | panel.setCanChooseDirectories(false); 482 | panel.setAllowsMultipleSelection(false); 483 | panel.setShowsHiddenFiles(false); 484 | panel.setExtensionHidden(false); //set initial panel path 485 | 486 | if (path) { 487 | panel.setDirectoryURL(NSURL.fileURLWithPath(path)); 488 | } else { 489 | panel.setDirectoryURL(NSURL.fileURLWithPath('/Users/' + NSUserName())); 490 | } //show panel 491 | 492 | 493 | var pressedButton = panel.runModal(); 494 | 495 | if (pressedButton == NSOKButton) { 496 | return panel.URL().path(); 497 | } 498 | } 499 | 500 | function loadJSONData(path) { 501 | //load contents 502 | var contents = readFileAsText(path); //get data from JSON 503 | 504 | var data; 505 | 506 | try { 507 | data = JSON.parse(contents); 508 | } catch (e) { 509 | context.document.showMessage("There was an error parsing data. Please make sure it's valid."); 510 | return; 511 | } 512 | 513 | return data; 514 | } 515 | 516 | function readFileAsText(path) { 517 | return NSString.stringWithContentsOfFile_encoding_error(path, NSUTF8StringEncoding, false); 518 | } 519 | 520 | /***/ }) 521 | 522 | /******/ }); 523 | if (key === 'default' && typeof exports === 'function') { 524 | exports(context); 525 | } else { 526 | exports[key](context); 527 | } 528 | } 529 | that['onRun'] = __skpm_run.bind(this, 'default') 530 | 531 | //# sourceMappingURL=import-base-colors-decisions-file.js.map -------------------------------------------------------------------------------- /sketch-tokenizer.sketchplugin/Contents/Sketch/import-base-colors.js: -------------------------------------------------------------------------------- 1 | var that = this; 2 | function __skpm_run (key, context) { 3 | that.context = context; 4 | 5 | var exports = 6 | /******/ (function(modules) { // webpackBootstrap 7 | /******/ // The module cache 8 | /******/ var installedModules = {}; 9 | /******/ 10 | /******/ // The require function 11 | /******/ function __webpack_require__(moduleId) { 12 | /******/ 13 | /******/ // Check if module is in cache 14 | /******/ if(installedModules[moduleId]) { 15 | /******/ return installedModules[moduleId].exports; 16 | /******/ } 17 | /******/ // Create a new module (and put it into the cache) 18 | /******/ var module = installedModules[moduleId] = { 19 | /******/ i: moduleId, 20 | /******/ l: false, 21 | /******/ exports: {} 22 | /******/ }; 23 | /******/ 24 | /******/ // Execute the module function 25 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 26 | /******/ 27 | /******/ // Flag the module as loaded 28 | /******/ module.l = true; 29 | /******/ 30 | /******/ // Return the exports of the module 31 | /******/ return module.exports; 32 | /******/ } 33 | /******/ 34 | /******/ 35 | /******/ // expose the modules object (__webpack_modules__) 36 | /******/ __webpack_require__.m = modules; 37 | /******/ 38 | /******/ // expose the module cache 39 | /******/ __webpack_require__.c = installedModules; 40 | /******/ 41 | /******/ // define getter function for harmony exports 42 | /******/ __webpack_require__.d = function(exports, name, getter) { 43 | /******/ if(!__webpack_require__.o(exports, name)) { 44 | /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); 45 | /******/ } 46 | /******/ }; 47 | /******/ 48 | /******/ // define __esModule on exports 49 | /******/ __webpack_require__.r = function(exports) { 50 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 51 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 52 | /******/ } 53 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 54 | /******/ }; 55 | /******/ 56 | /******/ // create a fake namespace object 57 | /******/ // mode & 1: value is a module id, require it 58 | /******/ // mode & 2: merge all properties of value into the ns 59 | /******/ // mode & 4: return value when already ns object 60 | /******/ // mode & 8|1: behave like require 61 | /******/ __webpack_require__.t = function(value, mode) { 62 | /******/ if(mode & 1) value = __webpack_require__(value); 63 | /******/ if(mode & 8) return value; 64 | /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 65 | /******/ var ns = Object.create(null); 66 | /******/ __webpack_require__.r(ns); 67 | /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 68 | /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 69 | /******/ return ns; 70 | /******/ }; 71 | /******/ 72 | /******/ // getDefaultExport function for compatibility with non-harmony modules 73 | /******/ __webpack_require__.n = function(module) { 74 | /******/ var getter = module && module.__esModule ? 75 | /******/ function getDefault() { return module['default']; } : 76 | /******/ function getModuleExports() { return module; }; 77 | /******/ __webpack_require__.d(getter, 'a', getter); 78 | /******/ return getter; 79 | /******/ }; 80 | /******/ 81 | /******/ // Object.prototype.hasOwnProperty.call 82 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 83 | /******/ 84 | /******/ // __webpack_public_path__ 85 | /******/ __webpack_require__.p = ""; 86 | /******/ 87 | /******/ 88 | /******/ // Load entry module and return exports 89 | /******/ return __webpack_require__(__webpack_require__.s = "./src/import-base-colors.js"); 90 | /******/ }) 91 | /************************************************************************/ 92 | /******/ ({ 93 | 94 | /***/ "./src/import-base-colors.js": 95 | /*!***********************************!*\ 96 | !*** ./src/import-base-colors.js ***! 97 | \***********************************/ 98 | /*! exports provided: default, askForJSON, loadJSONData, readFileAsText */ 99 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 100 | 101 | "use strict"; 102 | __webpack_require__.r(__webpack_exports__); 103 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "askForJSON", function() { return askForJSON; }); 104 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "loadJSONData", function() { return loadJSONData; }); 105 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "readFileAsText", function() { return readFileAsText; }); 106 | function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; } 107 | 108 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } 109 | 110 | var baseColors; 111 | /* harmony default export */ __webpack_exports__["default"] = (function (context) { 112 | var selection = context.selection; 113 | context.document.showMessage('Plugin 🏃'); //ask for JSON file path, passing the last location if available 114 | 115 | var dataPath = askForJSON('lastJSONPath'); // console.log('dataPath', dataPath) 116 | 117 | if (!dataPath) return; //load json data 118 | 119 | var jsonData = loadJSONData(dataPath); 120 | if (!jsonData) return; //get root dir used when populating local images 121 | 122 | var jsonDir = NSString.stringWithString(dataPath).stringByDeletingLastPathComponent(); // console.log('jsonData', jsonData) 123 | 124 | var threadDictionary = NSThread.mainThread().threadDictionary(); 125 | threadDictionary.importedBaseColors = _objectSpread({}, jsonData.baseColors); 126 | context.document.showMessage('📩🎉: File imported! Ready to use!'); 127 | }); 128 | function askForJSON(path) { 129 | //create panel 130 | var panel = NSOpenPanel.openPanel(); //set panel properties 131 | 132 | panel.setTitle("Select JSON"); 133 | panel.setMessage("Please select the JSON file you'd like to use."); 134 | panel.setPrompt("Select"); 135 | panel.setCanCreateDirectories(false); 136 | panel.setCanChooseFiles(true); 137 | panel.setCanChooseDirectories(false); 138 | panel.setAllowsMultipleSelection(false); 139 | panel.setShowsHiddenFiles(false); 140 | panel.setExtensionHidden(false); //set initial panel path 141 | 142 | if (path) { 143 | panel.setDirectoryURL(NSURL.fileURLWithPath(path)); 144 | } else { 145 | panel.setDirectoryURL(NSURL.fileURLWithPath('/Users/' + NSUserName())); 146 | } //show panel 147 | 148 | 149 | var pressedButton = panel.runModal(); 150 | 151 | if (pressedButton == NSOKButton) { 152 | return panel.URL().path(); 153 | } 154 | } 155 | function loadJSONData(path) { 156 | //load contents 157 | var contents = readFileAsText(path); //get data from JSON 158 | 159 | var data; 160 | 161 | try { 162 | data = JSON.parse(contents); 163 | } catch (e) { 164 | context.document.showMessage("There was an error parsing data. Please make sure it's valid."); 165 | return; 166 | } 167 | 168 | return data; 169 | } 170 | function readFileAsText(path) { 171 | return NSString.stringWithContentsOfFile_encoding_error(path, NSUTF8StringEncoding, false); 172 | } 173 | 174 | /***/ }) 175 | 176 | /******/ }); 177 | if (key === 'default' && typeof exports === 'function') { 178 | exports(context); 179 | } else { 180 | exports[key](context); 181 | } 182 | } 183 | that['onRun'] = __skpm_run.bind(this, 'default') 184 | 185 | //# sourceMappingURL=import-base-colors.js.map -------------------------------------------------------------------------------- /sketch-tokenizer.sketchplugin/Contents/Sketch/import-base-colors.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack://exports/webpack/bootstrap","webpack://exports/./src/import-base-colors.js"],"names":["baseColors","context","selection","document","showMessage","dataPath","askForJSON","jsonData","loadJSONData","jsonDir","NSString","stringWithString","stringByDeletingLastPathComponent","threadDictionary","NSThread","mainThread","importedBaseColors","path","panel","NSOpenPanel","openPanel","setTitle","setMessage","setPrompt","setCanCreateDirectories","setCanChooseFiles","setCanChooseDirectories","setAllowsMultipleSelection","setShowsHiddenFiles","setExtensionHidden","setDirectoryURL","NSURL","fileURLWithPath","NSUserName","pressedButton","runModal","NSOKButton","URL","contents","readFileAsText","data","JSON","parse","e","stringWithContentsOfFile_encoding_error","NSUTF8StringEncoding"],"mappings":"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","file":"import-base-colors.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = \"./src/import-base-colors.js\");\n","let baseColors;\nexport default function(context) {\n var selection = context.selection;\n context.document.showMessage('Plugin 🏃');\n\n //ask for JSON file path, passing the last location if available\n let dataPath = askForJSON('lastJSONPath')\n // console.log('dataPath', dataPath)\n if (!dataPath) return\n\n //load json data\n let jsonData = loadJSONData(dataPath)\n if (!jsonData) return\n\n //get root dir used when populating local images\n let jsonDir = NSString.stringWithString(dataPath).stringByDeletingLastPathComponent()\n\n // console.log('jsonData', jsonData)\n\n let threadDictionary = NSThread.mainThread().threadDictionary();\n threadDictionary.importedBaseColors = {...jsonData.baseColors};\n\n context.document.showMessage('📩🎉: File imported! Ready to use!')\n}\n\nexport function askForJSON(path) {\n //create panel\n let panel = NSOpenPanel.openPanel()\n\n //set panel properties\n panel.setTitle(\"Select JSON\")\n panel.setMessage(\"Please select the JSON file you'd like to use.\")\n panel.setPrompt(\"Select\")\n panel.setCanCreateDirectories(false)\n panel.setCanChooseFiles(true)\n panel.setCanChooseDirectories(false)\n panel.setAllowsMultipleSelection(false)\n panel.setShowsHiddenFiles(false)\n panel.setExtensionHidden(false)\n\n //set initial panel path\n if (path) {\n panel.setDirectoryURL(NSURL.fileURLWithPath(path))\n }\n else {\n panel.setDirectoryURL(NSURL.fileURLWithPath('/Users/' + NSUserName()))\n }\n\n //show panel\n let pressedButton = panel.runModal()\n if (pressedButton == NSOKButton) {\n return panel.URL().path()\n }\n}\n\nexport function loadJSONData(path) {\n\n //load contents\n let contents = readFileAsText(path)\n\n //get data from JSON\n let data\n try {\n data = JSON.parse(contents)\n }\n catch (e) {\n context.document.showMessage(\"There was an error parsing data. Please make sure it's valid.\")\n return\n }\n\n return data\n}\n\nexport function readFileAsText(path) {\n return NSString.stringWithContentsOfFile_encoding_error(path, NSUTF8StringEncoding, false)\n}\n"],"sourceRoot":""} -------------------------------------------------------------------------------- /sketch-tokenizer.sketchplugin/Contents/Sketch/import-decisions-file.js: -------------------------------------------------------------------------------- 1 | var that = this; 2 | function __skpm_run (key, context) { 3 | that.context = context; 4 | 5 | var exports = 6 | /******/ (function(modules) { // webpackBootstrap 7 | /******/ // The module cache 8 | /******/ var installedModules = {}; 9 | /******/ 10 | /******/ // The require function 11 | /******/ function __webpack_require__(moduleId) { 12 | /******/ 13 | /******/ // Check if module is in cache 14 | /******/ if(installedModules[moduleId]) { 15 | /******/ return installedModules[moduleId].exports; 16 | /******/ } 17 | /******/ // Create a new module (and put it into the cache) 18 | /******/ var module = installedModules[moduleId] = { 19 | /******/ i: moduleId, 20 | /******/ l: false, 21 | /******/ exports: {} 22 | /******/ }; 23 | /******/ 24 | /******/ // Execute the module function 25 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 26 | /******/ 27 | /******/ // Flag the module as loaded 28 | /******/ module.l = true; 29 | /******/ 30 | /******/ // Return the exports of the module 31 | /******/ return module.exports; 32 | /******/ } 33 | /******/ 34 | /******/ 35 | /******/ // expose the modules object (__webpack_modules__) 36 | /******/ __webpack_require__.m = modules; 37 | /******/ 38 | /******/ // expose the module cache 39 | /******/ __webpack_require__.c = installedModules; 40 | /******/ 41 | /******/ // define getter function for harmony exports 42 | /******/ __webpack_require__.d = function(exports, name, getter) { 43 | /******/ if(!__webpack_require__.o(exports, name)) { 44 | /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); 45 | /******/ } 46 | /******/ }; 47 | /******/ 48 | /******/ // define __esModule on exports 49 | /******/ __webpack_require__.r = function(exports) { 50 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 51 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 52 | /******/ } 53 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 54 | /******/ }; 55 | /******/ 56 | /******/ // create a fake namespace object 57 | /******/ // mode & 1: value is a module id, require it 58 | /******/ // mode & 2: merge all properties of value into the ns 59 | /******/ // mode & 4: return value when already ns object 60 | /******/ // mode & 8|1: behave like require 61 | /******/ __webpack_require__.t = function(value, mode) { 62 | /******/ if(mode & 1) value = __webpack_require__(value); 63 | /******/ if(mode & 8) return value; 64 | /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 65 | /******/ var ns = Object.create(null); 66 | /******/ __webpack_require__.r(ns); 67 | /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 68 | /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 69 | /******/ return ns; 70 | /******/ }; 71 | /******/ 72 | /******/ // getDefaultExport function for compatibility with non-harmony modules 73 | /******/ __webpack_require__.n = function(module) { 74 | /******/ var getter = module && module.__esModule ? 75 | /******/ function getDefault() { return module['default']; } : 76 | /******/ function getModuleExports() { return module; }; 77 | /******/ __webpack_require__.d(getter, 'a', getter); 78 | /******/ return getter; 79 | /******/ }; 80 | /******/ 81 | /******/ // Object.prototype.hasOwnProperty.call 82 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 83 | /******/ 84 | /******/ // __webpack_public_path__ 85 | /******/ __webpack_require__.p = ""; 86 | /******/ 87 | /******/ 88 | /******/ // Load entry module and return exports 89 | /******/ return __webpack_require__(__webpack_require__.s = "./src/import-decisions-file.js"); 90 | /******/ }) 91 | /************************************************************************/ 92 | /******/ ({ 93 | 94 | /***/ "./src/import-decisions-file.js": 95 | /*!**************************************!*\ 96 | !*** ./src/import-decisions-file.js ***! 97 | \**************************************/ 98 | /*! exports provided: default, askForJSON, loadJSONData, readFileAsText */ 99 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 100 | 101 | "use strict"; 102 | __webpack_require__.r(__webpack_exports__); 103 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "askForJSON", function() { return askForJSON; }); 104 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "loadJSONData", function() { return loadJSONData; }); 105 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "readFileAsText", function() { return readFileAsText; }); 106 | function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; } 107 | 108 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } 109 | 110 | var baseColors; 111 | /* harmony default export */ __webpack_exports__["default"] = (function (context) { 112 | var selection = context.selection; 113 | context.document.showMessage('Plugin 🏃'); //ask for JSON file path, passing the last location if available 114 | 115 | var dataPath = askForJSON('lastJSONPath'); // console.log('dataPath', dataPath) 116 | 117 | if (!dataPath) return; //load json data 118 | 119 | var jsonData = loadJSONData(dataPath); 120 | if (!jsonData) return; //get root dir used when populating local images 121 | 122 | var jsonDir = NSString.stringWithString(dataPath).stringByDeletingLastPathComponent(); // console.log('jsonData', jsonData) 123 | 124 | var threadDictionary = NSThread.mainThread().threadDictionary(); 125 | threadDictionary.importedBaseColors = _objectSpread({}, jsonData.baseColors); 126 | context.document.showMessage('📩🎉: File imported! Ready to use!'); 127 | }); 128 | function askForJSON(path) { 129 | //create panel 130 | var panel = NSOpenPanel.openPanel(); //set panel properties 131 | 132 | panel.setTitle('Select JSON'); 133 | panel.setMessage("Please select the JSON file you'd like to use."); 134 | panel.setPrompt('Select'); 135 | panel.setCanCreateDirectories(false); 136 | panel.setCanChooseFiles(true); 137 | panel.setCanChooseDirectories(false); 138 | panel.setAllowsMultipleSelection(false); 139 | panel.setShowsHiddenFiles(false); 140 | panel.setExtensionHidden(false); //set initial panel path 141 | 142 | if (path) { 143 | panel.setDirectoryURL(NSURL.fileURLWithPath(path)); 144 | } else { 145 | panel.setDirectoryURL(NSURL.fileURLWithPath('/Users/' + NSUserName())); 146 | } //show panel 147 | 148 | 149 | var pressedButton = panel.runModal(); 150 | 151 | if (pressedButton == NSOKButton) { 152 | return panel.URL().path(); 153 | } 154 | } 155 | function loadJSONData(path) { 156 | //load contents 157 | var contents = readFileAsText(path); //get data from JSON 158 | 159 | var data; 160 | 161 | try { 162 | data = JSON.parse(contents); 163 | } catch (e) { 164 | context.document.showMessage("There was an error parsing data. Please make sure it's valid."); 165 | return; 166 | } 167 | 168 | return data; 169 | } 170 | function readFileAsText(path) { 171 | return NSString.stringWithContentsOfFile_encoding_error(path, NSUTF8StringEncoding, false); 172 | } 173 | 174 | /***/ }) 175 | 176 | /******/ }); 177 | if (key === 'default' && typeof exports === 'function') { 178 | exports(context); 179 | } else { 180 | exports[key](context); 181 | } 182 | } 183 | that['onRun'] = __skpm_run.bind(this, 'default') 184 | 185 | //# sourceMappingURL=import-decisions-file.js.map -------------------------------------------------------------------------------- /sketch-tokenizer.sketchplugin/Contents/Sketch/import-decisions-file.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack://exports/webpack/bootstrap","webpack://exports/./src/import-decisions-file.js"],"names":["baseColors","context","selection","document","showMessage","dataPath","askForJSON","jsonData","loadJSONData","jsonDir","NSString","stringWithString","stringByDeletingLastPathComponent","threadDictionary","NSThread","mainThread","importedBaseColors","path","panel","NSOpenPanel","openPanel","setTitle","setMessage","setPrompt","setCanCreateDirectories","setCanChooseFiles","setCanChooseDirectories","setAllowsMultipleSelection","setShowsHiddenFiles","setExtensionHidden","setDirectoryURL","NSURL","fileURLWithPath","NSUserName","pressedButton","runModal","NSOKButton","URL","contents","readFileAsText","data","JSON","parse","e","stringWithContentsOfFile_encoding_error","NSUTF8StringEncoding"],"mappings":"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","file":"import-decisions-file.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = \"./src/import-decisions-file.js\");\n","let baseColors;\nexport default function(context) {\n var selection = context.selection;\n context.document.showMessage('Plugin 🏃');\n\n //ask for JSON file path, passing the last location if available\n let dataPath = askForJSON('lastJSONPath');\n // console.log('dataPath', dataPath)\n if (!dataPath) return;\n\n //load json data\n let jsonData = loadJSONData(dataPath);\n if (!jsonData) return;\n\n //get root dir used when populating local images\n let jsonDir = NSString.stringWithString(\n dataPath\n ).stringByDeletingLastPathComponent();\n\n // console.log('jsonData', jsonData)\n\n let threadDictionary = NSThread.mainThread().threadDictionary();\n threadDictionary.importedBaseColors = { ...jsonData.baseColors };\n\n context.document.showMessage('📩🎉: File imported! Ready to use!');\n}\n\nexport function askForJSON(path) {\n //create panel\n let panel = NSOpenPanel.openPanel();\n\n //set panel properties\n panel.setTitle('Select JSON');\n panel.setMessage(\"Please select the JSON file you'd like to use.\");\n panel.setPrompt('Select');\n panel.setCanCreateDirectories(false);\n panel.setCanChooseFiles(true);\n panel.setCanChooseDirectories(false);\n panel.setAllowsMultipleSelection(false);\n panel.setShowsHiddenFiles(false);\n panel.setExtensionHidden(false);\n\n //set initial panel path\n if (path) {\n panel.setDirectoryURL(NSURL.fileURLWithPath(path));\n } else {\n panel.setDirectoryURL(NSURL.fileURLWithPath('/Users/' + NSUserName()));\n }\n\n //show panel\n let pressedButton = panel.runModal();\n if (pressedButton == NSOKButton) {\n return panel.URL().path();\n }\n}\n\nexport function loadJSONData(path) {\n //load contents\n let contents = readFileAsText(path);\n\n //get data from JSON\n let data;\n try {\n data = JSON.parse(contents);\n } catch (e) {\n context.document.showMessage(\n \"There was an error parsing data. Please make sure it's valid.\"\n );\n return;\n }\n\n return data;\n}\n\nexport function readFileAsText(path) {\n return NSString.stringWithContentsOfFile_encoding_error(\n path,\n NSUTF8StringEncoding,\n false\n );\n}\n"],"sourceRoot":""} -------------------------------------------------------------------------------- /sketch-tokenizer.sketchplugin/Contents/Sketch/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "compatibleVersion": 3, 3 | "bundleVersion": 1, 4 | "icon": "icon.png", 5 | "commands": [ 6 | { 7 | "name": "Fill color", 8 | "identifier": "base-fill-color", 9 | "shortcut": "ctrl shift w", 10 | "script": "get-base-fill-color.js" 11 | }, 12 | { 13 | "name": "Border color", 14 | "identifier": "base-border-color", 15 | "shortcut": "ctrl shift b", 16 | "script": "get-base-border-color.js" 17 | }, 18 | { 19 | "name": "Input", 20 | "identifier": "token-border-color-input", 21 | "script": "get-token-border-color-input.js" 22 | }, 23 | { 24 | "name": "Input", 25 | "identifier": "token-background-color-input", 26 | "script": "get-token-background-color-input.js" 27 | }, 28 | { 29 | "name": "Import base colors decisions file...", 30 | "identifier": "import-base-colors-decisions-file", 31 | "shortcut": "ctrl shift i", 32 | "script": "import-base-colors-decisions-file.js" 33 | }, 34 | { 35 | "name": "Import borders decisions file...", 36 | "identifier": "import-token-borders-decisions-file", 37 | "script": "import-token-borders-decisions-file.js" 38 | }, 39 | { 40 | "name": "Import backgrounds decisions file...", 41 | "identifier": "import-token-backgrounds-decisions-file", 42 | "script": "import-token-backgrounds-decisions-file.js" 43 | } 44 | ], 45 | "menu": { 46 | "title": "Tokenizer", 47 | "items": [ 48 | { 49 | "title": "Load data", 50 | "items": [ 51 | "import-base-colors-decisions-file", 52 | "import-token-borders-decisions-file", 53 | "import-token-backgrounds-decisions-file" 54 | ] 55 | }, 56 | { 57 | "title": "Identify", 58 | "items": [ 59 | { 60 | "title": "Base color", 61 | "items": [ 62 | "base-fill-color", 63 | "base-border-color" 64 | ] 65 | }, 66 | { 67 | "title": "Token", 68 | "items": [ 69 | { 70 | "title": "Border color", 71 | "items": [ 72 | "token-border-color-input" 73 | ] 74 | }, 75 | { 76 | "title": "Background color", 77 | "items": [ 78 | "token-background-color-input" 79 | ] 80 | } 81 | ] 82 | } 83 | ] 84 | } 85 | ] 86 | }, 87 | "version": "0.1.0", 88 | "name": "sketch-tokenizer", 89 | "disableCocoaScriptPreprocessor": true, 90 | "appcast": "https://raw.githubusercontent.com//master/.appcast.xml", 91 | "author": "lufego", 92 | "authorEmail": "luis.gomes@commercetools.de" 93 | } -------------------------------------------------------------------------------- /sketch-tokenizer.sketchplugin/Contents/Sketch/my-command.js: -------------------------------------------------------------------------------- 1 | var that = this; 2 | function __skpm_run (key, context) { 3 | that.context = context; 4 | 5 | var exports = 6 | /******/ (function(modules) { // webpackBootstrap 7 | /******/ // The module cache 8 | /******/ var installedModules = {}; 9 | /******/ 10 | /******/ // The require function 11 | /******/ function __webpack_require__(moduleId) { 12 | /******/ 13 | /******/ // Check if module is in cache 14 | /******/ if(installedModules[moduleId]) { 15 | /******/ return installedModules[moduleId].exports; 16 | /******/ } 17 | /******/ // Create a new module (and put it into the cache) 18 | /******/ var module = installedModules[moduleId] = { 19 | /******/ i: moduleId, 20 | /******/ l: false, 21 | /******/ exports: {} 22 | /******/ }; 23 | /******/ 24 | /******/ // Execute the module function 25 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 26 | /******/ 27 | /******/ // Flag the module as loaded 28 | /******/ module.l = true; 29 | /******/ 30 | /******/ // Return the exports of the module 31 | /******/ return module.exports; 32 | /******/ } 33 | /******/ 34 | /******/ 35 | /******/ // expose the modules object (__webpack_modules__) 36 | /******/ __webpack_require__.m = modules; 37 | /******/ 38 | /******/ // expose the module cache 39 | /******/ __webpack_require__.c = installedModules; 40 | /******/ 41 | /******/ // define getter function for harmony exports 42 | /******/ __webpack_require__.d = function(exports, name, getter) { 43 | /******/ if(!__webpack_require__.o(exports, name)) { 44 | /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); 45 | /******/ } 46 | /******/ }; 47 | /******/ 48 | /******/ // define __esModule on exports 49 | /******/ __webpack_require__.r = function(exports) { 50 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 51 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 52 | /******/ } 53 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 54 | /******/ }; 55 | /******/ 56 | /******/ // create a fake namespace object 57 | /******/ // mode & 1: value is a module id, require it 58 | /******/ // mode & 2: merge all properties of value into the ns 59 | /******/ // mode & 4: return value when already ns object 60 | /******/ // mode & 8|1: behave like require 61 | /******/ __webpack_require__.t = function(value, mode) { 62 | /******/ if(mode & 1) value = __webpack_require__(value); 63 | /******/ if(mode & 8) return value; 64 | /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 65 | /******/ var ns = Object.create(null); 66 | /******/ __webpack_require__.r(ns); 67 | /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 68 | /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 69 | /******/ return ns; 70 | /******/ }; 71 | /******/ 72 | /******/ // getDefaultExport function for compatibility with non-harmony modules 73 | /******/ __webpack_require__.n = function(module) { 74 | /******/ var getter = module && module.__esModule ? 75 | /******/ function getDefault() { return module['default']; } : 76 | /******/ function getModuleExports() { return module; }; 77 | /******/ __webpack_require__.d(getter, 'a', getter); 78 | /******/ return getter; 79 | /******/ }; 80 | /******/ 81 | /******/ // Object.prototype.hasOwnProperty.call 82 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 83 | /******/ 84 | /******/ // __webpack_public_path__ 85 | /******/ __webpack_require__.p = ""; 86 | /******/ 87 | /******/ 88 | /******/ // Load entry module and return exports 89 | /******/ return __webpack_require__(__webpack_require__.s = "./src/my-command.js"); 90 | /******/ }) 91 | /************************************************************************/ 92 | /******/ ({ 93 | 94 | /***/ "./src/my-command.js": 95 | /*!***************************!*\ 96 | !*** ./src/my-command.js ***! 97 | \***************************/ 98 | /*! exports provided: default */ 99 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 100 | 101 | "use strict"; 102 | __webpack_require__.r(__webpack_exports__); 103 | // My plugin (command shift s) 104 | var colorVariables = { 105 | baseColors: { 106 | green: { 107 | default: "#14B39D", 108 | 25: "#0B8171", 109 | 40: "#19CCB3", 110 | 85: "#B4FFF6", 111 | 95: "#E6FFFC" 112 | }, 113 | white: { 114 | default: "#FFFFFF" 115 | }, 116 | navy: { 117 | default: "#1D3D45", 118 | 30: "#2E5768", 119 | 40: "#407A8B", 120 | 95: "#EEF4F6", 121 | 98: "#F9FBFB" 122 | }, 123 | blue: { 124 | default: "#0090E0", 125 | 95: "#B2E3FF", 126 | 98: "#E5F6FF" 127 | }, 128 | gray: { 129 | default: "#CCCCCC", 130 | 60: "#999999", 131 | 90: "#E6E6E6", 132 | 95: "#F2F2F2" 133 | }, 134 | orange: { 135 | default: "#F1690E", 136 | 95: "#FEF0E7" 137 | }, 138 | red: { 139 | default: "#E50051", 140 | 95: "#FFE5EE" 141 | }, 142 | purple: { 143 | default: "#B26DFF" 144 | }, 145 | black: { 146 | default: "#181818" 147 | } 148 | } 149 | }; 150 | /* harmony default export */ __webpack_exports__["default"] = (function (context) { 151 | var selection = context.selection; 152 | context.document.showMessage('Plugin 🏃'); 153 | 154 | if (selection.length == 0) { 155 | return context.document.showMessage('🗝🌈: Please select a layer'); 156 | } 157 | 158 | if (selection[0] instanceof MSTextLayer) { 159 | var _lay = createTextLayer('tone', 'tone: ' + 'NEGATIVE'); // gets the position of selection 160 | 161 | 162 | var midX = context.selection[0].frame().midX(); 163 | var midY = context.selection[0].frame().midY(); // pass the position to the text layer to be inserter 164 | 165 | _lay.frame().midX = midX; 166 | _lay.frame().midY = midY; 167 | return context.document.currentPage().addLayers([_lay]); 168 | } 169 | 170 | var colorMapping = getColorVariablesMapping(colorVariables); 171 | var currentSelectedColor = getFillHexColor(selection).toString().toUpperCase(); 172 | var lay = createTextLayer('design', 'color: ' + colorMapping["#" + currentSelectedColor]); // gets the position of selection 173 | 174 | var midX = context.selection[0].frame().midX(); 175 | var midY = context.selection[0].frame().midY(); // pass the position to the text layer to be inserter 176 | 177 | lay.frame().midX = midX; 178 | lay.frame().midY = midY; // add the layer to the artboar 179 | 180 | context.document.currentPage().addLayers([lay]); 181 | }); 182 | 183 | function getFillHexColor(selection) { 184 | var layer = context.selection[0]; 185 | var selectedColor = getFillRGBColor("fill", layer); 186 | var colorHex = selectedColor.immutableModelObject().hexValue().toString(); 187 | return colorHex; 188 | } 189 | 190 | function getFillRGBColor(type, layer) { 191 | var color; 192 | 193 | if (type === "fill") { 194 | if (layer instanceof MSTextLayer) { 195 | color = layer.textColor(); 196 | } else { 197 | color = layer.style().fills().firstObject().color(); 198 | } 199 | } else { 200 | color = layer.style().borders().firstObject().color(); 201 | } 202 | 203 | return color; 204 | } // Hex to Color - helper function 205 | 206 | 207 | var hexToColor = function hexToColor(hex, alpha) { 208 | var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex), 209 | red = parseInt(result[1], 16) / 255, 210 | green = parseInt(result[2], 16) / 255, 211 | blue = parseInt(result[3], 16) / 255, 212 | alpha = typeof alpha !== 'undefined' ? alpha : 1; 213 | return NSColor.colorWithCalibratedRed_green_blue_alpha(red, green, blue, alpha); 214 | }; 215 | 216 | function createTextLayer(name, stringValue) { 217 | var textLayer = MSTextLayer.new(); 218 | textLayer.stringValue = stringValue; 219 | textLayer.name = name; 220 | textLayer.setTextColor = hexToColor("CCCCCC"); 221 | return textLayer; 222 | } 223 | 224 | function getColorVariablesMapping(variables) { 225 | var obj = variables.baseColors; 226 | var colorNames = {}; // gets default color variables 227 | 228 | Object.keys(obj).map(function (colorGroupName) { 229 | var colorGroup = obj[colorGroupName]; 230 | colorNames[colorGroup.default] = '--color-' + colorGroupName; 231 | Object.keys(colorGroup).forEach(function (variation) { 232 | // filters out default values 233 | if (variation !== 'default') { 234 | colorNames[colorGroup[variation]] = '--color-' + colorGroupName + '-' + variation; 235 | } 236 | }); 237 | }); 238 | return colorNames; 239 | } 240 | 241 | /***/ }) 242 | 243 | /******/ }); 244 | if (key === 'default' && typeof exports === 'function') { 245 | exports(context); 246 | } else { 247 | exports[key](context); 248 | } 249 | } 250 | that['onRun'] = __skpm_run.bind(this, 'default') 251 | 252 | //# sourceMappingURL=my-command.js.map -------------------------------------------------------------------------------- /sketch-tokenizer.sketchplugin/Contents/Sketch/my-command.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack://exports/webpack/bootstrap","webpack://exports/./src/my-command.js"],"names":["colorVariables","baseColors","green","default","white","navy","blue","gray","orange","red","purple","black","context","selection","document","showMessage","length","MSTextLayer","lay","createTextLayer","midX","frame","midY","currentPage","addLayers","colorMapping","getColorVariablesMapping","currentSelectedColor","getFillHexColor","toString","toUpperCase","layer","selectedColor","getFillRGBColor","colorHex","immutableModelObject","hexValue","type","color","textColor","style","fills","firstObject","borders","hexToColor","hex","alpha","result","exec","parseInt","NSColor","colorWithCalibratedRed_green_blue_alpha","name","stringValue","textLayer","new","setTextColor","variables","obj","colorNames","Object","keys","map","colorGroup","colorGroupName","forEach","variation"],"mappings":"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","file":"my-command.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = \"./src/my-command.js\");\n","// My plugin (command shift s)\nconst colorVariables = {\n baseColors: {\n green: {\n default: \"#14B39D\",\n 25: \"#0B8171\",\n 40: \"#19CCB3\",\n 85: \"#B4FFF6\",\n 95: \"#E6FFFC\",\n },\n white: {\n default: \"#FFFFFF\"\n },\n navy: {\n default: \"#1D3D45\",\n 30: \"#2E5768\",\n 40: \"#407A8B\",\n 95: \"#EEF4F6\",\n 98 : \"#F9FBFB\"\n },\n blue: {\n default: \"#0090E0\",\n 95: \"#B2E3FF\",\n 98: \"#E5F6FF\"\n },\n gray: {\n default: \"#CCCCCC\",\n 60: \"#999999\",\n 90: \"#E6E6E6\",\n 95: \"#F2F2F2\"\n },\n orange: {\n default: \"#F1690E\",\n 95: \"#FEF0E7\"\n },\n red: {\n default: \"#E50051\",\n 95: \"#FFE5EE\"\n },\n purple: {\n default: \"#B26DFF\",\n },\n black: {\n default: \"#181818\",\n }\n }\n}\n\nexport default function(context) {\n var selection = context.selection;\n context.document.showMessage('Plugin 🏃');\n\n if (selection.length == 0) {\n return context.document.showMessage('🗝🌈: Please select a layer');\n }\n\n if (selection[0] instanceof MSTextLayer) {\n const lay = createTextLayer('tone', 'tone: ' + 'NEGATIVE');\n // gets the position of selection\n var midX=context.selection[0].frame().midX();\n var midY=context.selection[0].frame().midY();\n\n // pass the position to the text layer to be inserter\n lay.frame().midX = midX;\n lay.frame().midY = midY;\n return context.document.currentPage().addLayers([lay]);\n }\n\n const colorMapping = getColorVariablesMapping(colorVariables)\n const currentSelectedColor = getFillHexColor(selection).toString().toUpperCase();\n\n\n const lay = createTextLayer('design', 'color: ' + colorMapping[\"#\" + currentSelectedColor]);\n\n // gets the position of selection\n var midX=context.selection[0].frame().midX();\n var midY=context.selection[0].frame().midY();\n\n // pass the position to the text layer to be inserter\n lay.frame().midX = midX;\n lay.frame().midY = midY;\n\n // add the layer to the artboar\n context.document.currentPage().addLayers([lay]);\n}\n\nfunction getFillHexColor(selection) {\n var layer = context.selection[0]\n var selectedColor = getFillRGBColor(\"fill\", layer)\n var colorHex = selectedColor.immutableModelObject().hexValue().toString()\n return colorHex\n}\n\nfunction getFillRGBColor (type, layer) {\n var color\n\n if (type === \"fill\") {\n if (layer instanceof MSTextLayer) {\n color = layer.textColor()\n } else {\n color = layer.style().fills().firstObject().color()\n }\n } else {\n color = layer.style().borders().firstObject().color()\n }\n\n return color\n}\n\n// Hex to Color - helper function\nvar hexToColor = function(hex, alpha) {\n var result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex),\n red = parseInt(result[1], 16) / 255,\n green = parseInt(result[2], 16) / 255,\n blue = parseInt(result[3], 16) / 255,\n alpha = (typeof alpha !== 'undefined') ? alpha : 1;\n return NSColor.colorWithCalibratedRed_green_blue_alpha(red, green, blue, alpha)\n}\n\n\nfunction createTextLayer(name, stringValue) {\n var textLayer = MSTextLayer.new();\n textLayer.stringValue = stringValue\n textLayer.name = name\n textLayer.setTextColor = hexToColor(\"CCCCCC\")\n return textLayer;\n}\n\nfunction getColorVariablesMapping(variables) {\n const obj = variables.baseColors\n const colorNames = {}\n // gets default color variables\n Object.keys(obj).map(colorGroupName => {\n const colorGroup = obj[colorGroupName]\n\n colorNames[colorGroup.default] = '--color-' + colorGroupName;\n\n Object.keys(colorGroup).forEach(variation => {\n // filters out default values\n if (variation !== 'default') {\n colorNames[colorGroup[variation]] = '--color-' + colorGroupName + '-' + variation;\n }\n })\n })\n\n return colorNames\n}\n"],"sourceRoot":""} -------------------------------------------------------------------------------- /src/border-color.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lufego/sketch-tokenizer/7c5bedccaae1467e98063b011c1f15a734c5ab79/src/border-color.js -------------------------------------------------------------------------------- /src/converters/colors.js: -------------------------------------------------------------------------------- 1 | // Color converters 2 | 3 | export function transformColorLightness(hex, lightness) { 4 | /* A bit of crazyness happening here; 5 | But this is the workflow from hsl_picker plugin to 6 | generate colors in sketch, so the same scheme is below */ 7 | // HEXtoRGB => RgbToHsl => change light => HSLtoRGB => RGBtoHSL => HSLtoHEX 8 | 9 | const colorRgb = HEXtoRGB(hex); 10 | const colorHsl = RGBtoHSL(colorRgb, lightness); 11 | const colorRgbTransformed = HSLtoRGB(colorHsl); 12 | const colorHslTransformed = RGBtoHSL(colorRgbTransformed); 13 | const colorHex = HSLtoHEX(colorHslTransformed); 14 | return colorHex; 15 | } 16 | 17 | function HEXtoRGB(hex) { 18 | var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 19 | return result 20 | ? [ 21 | parseInt(result[1], 16), 22 | parseInt(result[2], 16), 23 | parseInt(result[3], 16) 24 | ] 25 | : null; 26 | } 27 | 28 | function RGBtoHSL([r, g, b], lightness) { 29 | (r /= 255), (g /= 255), (b /= 255); 30 | var max = Math.max(r, g, b), 31 | min = Math.min(r, g, b); 32 | var h, 33 | s, 34 | l = (max + min) / 2; 35 | if (max == min) { 36 | h = s = 0; // achromatic 37 | } else { 38 | var d = max - min; 39 | s = l > 0.5 ? d / (2 - max - min) : d / (max + min); 40 | switch (max) { 41 | case r: 42 | h = (g - b) / d + (g < b ? 6 : 0); 43 | break; 44 | case g: 45 | h = (b - r) / d + 2; 46 | break; 47 | case b: 48 | h = (r - g) / d + 4; 49 | break; 50 | } 51 | h /= 6; 52 | } 53 | return [ 54 | Math.round(h * 360), 55 | Math.round(s * 100), 56 | lightness ? parseInt(lightness) : Math.round(l * 100) 57 | ]; 58 | } 59 | 60 | function HSLtoHEX(hsl) { 61 | const rgbColor = HSLtoRGB([hsl[0], hsl[1], hsl[2]]); 62 | const r = rgbColor[0]; 63 | const g = rgbColor[1]; 64 | const b = rgbColor[2]; 65 | 66 | // console.log('rgb', r, g, b) 67 | 68 | return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); 69 | } 70 | 71 | function HSLtoRGB([h, s, l]) { 72 | var m1, m2, hue; 73 | s = s / 100; 74 | l = l / 100; 75 | var r, g, b; 76 | 77 | if (s == 0) r = g = b = l * 255; 78 | else { 79 | m2 = l < 0.5 ? l * (1 + s) : l + s - l * s; 80 | m1 = 2 * l - m2; 81 | hue = h / 360; 82 | 83 | r = hue2rgb(m1, m2, hue + 1 / 3); 84 | g = hue2rgb(m1, m2, hue); 85 | b = hue2rgb(m1, m2, hue - 1 / 3); 86 | } 87 | 88 | function multiplyBy255(num) { 89 | return num * 255; 90 | } 91 | 92 | if (r < 1 || g < 1 || b < 1) { 93 | r = multiplyBy255(r); 94 | g = multiplyBy255(g); 95 | b = multiplyBy255(b); 96 | } 97 | 98 | // console.log('rgb', Math.round(r), Math.round(g), Math.round(b)); 99 | 100 | return [Math.round(r), Math.round(g), Math.round(b)]; 101 | } 102 | 103 | // Used inside HSLtoRGB function 104 | function hue2rgb(m1, m2, hue) { 105 | if (hue < 0) hue += 1; 106 | if (hue > 1) hue -= 1; 107 | if (hue < 1 / 6) return m1 + (m2 - m1) * 6 * hue; 108 | if (hue < 1 / 2) return m2; 109 | if (hue < 2 / 3) return m1 + (m2 - m1) * (2 / 3 - hue) * 6; 110 | return m1; 111 | } 112 | -------------------------------------------------------------------------------- /src/decisions/backgrounds.json: -------------------------------------------------------------------------------- 1 | { 2 | "color": { 3 | "input": { 4 | "pristine": "white", 5 | "disabled": "navy-98" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/decisions/base-colors.json: -------------------------------------------------------------------------------- 1 | { 2 | "green": { 3 | "25": "25%", 4 | "40": "40%", 5 | "85": "85%", 6 | "95": "95%", 7 | "default": "#00b39e" 8 | }, 9 | "white": { 10 | "default": "#ffffff" 11 | }, 12 | "navy": { 13 | "30": "30%", 14 | "40": "40%", 15 | "95": "95%", 16 | "98": "98%", 17 | "default": "#213c45" 18 | }, 19 | "blue": { 20 | "95": "95%", 21 | "85": "85%", 22 | "default": "#078cdf" 23 | }, 24 | "gray": { 25 | "60": "60%", 26 | "90": "90%", 27 | "95": "95%", 28 | "default": "#cccccc" 29 | }, 30 | "orange": { 31 | "95": "95%", 32 | "default": "#f16d0e" 33 | }, 34 | "red": { 35 | "95": "95%", 36 | "default": "#e60050" 37 | }, 38 | "purple": { 39 | "default": "#b866ff" 40 | }, 41 | "black": { 42 | "default": "#1a1a1a" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/decisions/borders.json: -------------------------------------------------------------------------------- 1 | { 2 | "color": { 3 | "input": { 4 | "pristine": "gray-60", 5 | "disabled": "gray", 6 | "readonly": "gray", 7 | "focus": "green", 8 | "error": "red", 9 | "warning": "orange" 10 | } 11 | }, 12 | "radius": { 13 | "input": 6 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/example.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lufego/sketch-tokenizer/7c5bedccaae1467e98063b011c1f15a734c5ab79/src/example.sketch -------------------------------------------------------------------------------- /src/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "compatibleVersion": 3, 3 | "bundleVersion": 1, 4 | "icon": "icon.png", 5 | "commands": [ 6 | { 7 | "name": "Fill color", 8 | "identifier": "base-fill-color", 9 | "shortcut": "ctrl shift w", 10 | "script": "./menu-identify/base-colors/get-base-fill-color.js" 11 | }, 12 | { 13 | "name": "Border color", 14 | "identifier": "base-border-color", 15 | "shortcut": "ctrl shift b", 16 | "script": "./menu-identify/base-colors/get-base-border-color.js" 17 | }, 18 | { 19 | "name": "Input", 20 | "identifier": "token-border-color-input", 21 | "script": "./menu-identify/tokens/border/get-token-border-color-input.js" 22 | }, 23 | { 24 | "name": "Input", 25 | "identifier": "token-background-color-input", 26 | "script": 27 | "./menu-identify/tokens/background/get-token-background-color-input.js" 28 | }, 29 | { 30 | "name": "Import base colors decisions file...", 31 | "identifier": "import-base-colors-decisions-file", 32 | "shortcut": "ctrl shift i", 33 | "script": "./menu-import/import-base-colors-decisions-file.js" 34 | }, 35 | { 36 | "name": "Import borders decisions file...", 37 | "identifier": "import-token-borders-decisions-file", 38 | "script": "./menu-import/import-token-borders-decisions-file.js" 39 | }, 40 | { 41 | "name": "Import backgrounds decisions file...", 42 | "identifier": "import-token-backgrounds-decisions-file", 43 | "script": "./menu-import/import-token-backgrounds-decisions-file.js" 44 | } 45 | ], 46 | "menu": { 47 | "title": "Tokenizer", 48 | "items": [ 49 | { 50 | "title": "Load data", 51 | "items": [ 52 | "import-base-colors-decisions-file", 53 | "import-token-borders-decisions-file", 54 | "import-token-backgrounds-decisions-file" 55 | ] 56 | }, 57 | { 58 | "title": "Identify", 59 | "items": [ 60 | { 61 | "title": "Base color", 62 | "items": ["base-fill-color", "base-border-color"] 63 | }, 64 | { 65 | "title": "Token", 66 | "items": [ 67 | { 68 | "title": "Border color", 69 | "items": ["token-border-color-input"] 70 | }, 71 | { 72 | "title": "Background color", 73 | "items": ["token-background-color-input"] 74 | } 75 | ] 76 | } 77 | ] 78 | } 79 | ] 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/menu-identify/base-colors/get-base-border-color.js: -------------------------------------------------------------------------------- 1 | const Utils = require('./../../utils.js'); 2 | 3 | // My plugin (command shift s) 4 | export default function(context) { 5 | var selection = context.selection; 6 | context.document.showMessage('Plugin 🏃'); 7 | 8 | if (selection.length == 0) { 9 | return context.document.showMessage('🗝🌈: Please select an object'); 10 | } 11 | // if its a text 12 | if (selection[0] instanceof MSTextLayer) { 13 | return context.document.showMessage( 14 | '❌: Please use `Tokenizer > Get Tone` for texts' 15 | ); 16 | } 17 | 18 | const colorMapping = Utils.getBaseColorsVariablesMapping(); 19 | const currentSelectedColor = Utils.getBorderHexColor(selection) 20 | .toString() 21 | .toUpperCase(); 22 | 23 | const color = colorMapping['#' + currentSelectedColor]; 24 | 25 | const callback = () => getBorderColorVariable(selection, color); 26 | 27 | // checks if color belongs to UI Kit, if not returns an error 28 | Utils.colorChecker(color, callback); 29 | } 30 | 31 | function getBorderColorVariable(selection, text) { 32 | const position = { 33 | x: selection[0].absoluteRect().rulerX(), 34 | y: selection[0].absoluteRect().rulerY(), 35 | midY: selection[0].absoluteRect().height() / 2, 36 | width: selection[0].absoluteRect().width() 37 | }; 38 | 39 | const layerName = String(selection[0].name()); 40 | 41 | Utils.insertTokenText(position, layerName, 'border color', text, true); 42 | } 43 | -------------------------------------------------------------------------------- /src/menu-identify/base-colors/get-base-fill-color.js: -------------------------------------------------------------------------------- 1 | const Utils = require('./../../utils.js'); 2 | 3 | // My plugin (command shift s) 4 | export default function(context) { 5 | var selection = context.selection; 6 | context.document.showMessage('Plugin 🏃'); 7 | 8 | if (selection.length == 0) { 9 | return context.document.showMessage('🗝🌈: Please select an object'); 10 | } 11 | // if its a text 12 | if (selection[0] instanceof MSTextLayer) { 13 | return context.document.showMessage( 14 | '❌: Please use `Tokenizer > Get Tone` for texts' 15 | ); 16 | } 17 | 18 | const colorMapping = Utils.getBaseColorsVariablesMapping(); 19 | console.log('colorMapping', colorMapping); 20 | const currentSelectedColor = Utils.getFillHexColor(selection) 21 | .toString() 22 | .toUpperCase(); 23 | 24 | const color = colorMapping['#' + currentSelectedColor]; 25 | 26 | const callback = () => getFillColorVariable(selection, color); 27 | 28 | // checks if color belongs to UI Kit, if not returns an error 29 | Utils.colorChecker(color, callback); 30 | } 31 | 32 | function getFillColorVariable(selection, text) { 33 | const position = { 34 | x: selection[0].absoluteRect().rulerX(), 35 | y: selection[0].absoluteRect().rulerY(), 36 | midY: selection[0].absoluteRect().height() / 2, 37 | width: selection[0].absoluteRect().width() 38 | }; 39 | 40 | const layerName = String(selection[0].name()); 41 | 42 | Utils.insertTokenText(position, layerName, 'fill color', text); 43 | } 44 | -------------------------------------------------------------------------------- /src/menu-identify/tokens/background/get-token-background-color-input.js: -------------------------------------------------------------------------------- 1 | const Utils = require('./../../../utils.js'); 2 | 3 | // My plugin (command shift s) 4 | export default function(context) { 5 | var selection = context.selection; 6 | context.document.showMessage('Plugin 🏃'); 7 | 8 | if (selection.length == 0) { 9 | return context.document.showMessage('🗝🌈: Please select an object'); 10 | } 11 | // if its a text 12 | if (selection[0] instanceof MSTextLayer) { 13 | return context.document.showMessage( 14 | '❌: Please use `Tokenizer > Get Tone` for texts' 15 | ); 16 | } 17 | 18 | const colorMapping = Utils.getBaseColorsVariablesMapping(); 19 | // console.log('colorMapping', colorMapping); 20 | const currentSelectedColor = Utils.getFillHexColor(selection) 21 | .toString() 22 | .toUpperCase(); 23 | const color = colorMapping[`#${currentSelectedColor}`]; 24 | 25 | const callback = () => 26 | insertTokenrVariable(selection, `#${currentSelectedColor}`); 27 | 28 | // checks if color belongs to UI Kit, if not returns an error 29 | Utils.colorChecker(color, callback); 30 | } 31 | 32 | function insertTokenrVariable(selection, hexColor) { 33 | const position = { 34 | x: selection[0].absoluteRect().rulerX(), 35 | y: selection[0].absoluteRect().rulerY(), 36 | midY: selection[0].absoluteRect().height() / 2, 37 | width: selection[0].absoluteRect().width() 38 | }; 39 | 40 | const layerName = String(selection[0].name()); 41 | 42 | const tokenText = Utils.getTokenVariable( 43 | 'background-color', 44 | 'input', 45 | hexColor 46 | ); 47 | 48 | Utils.insertTokenText( 49 | position, 50 | layerName, 51 | 'token input background color', 52 | tokenText 53 | ); 54 | } 55 | -------------------------------------------------------------------------------- /src/menu-identify/tokens/border/get-token-border-color-input.js: -------------------------------------------------------------------------------- 1 | const Utils = require('./../../../utils.js'); 2 | 3 | // My plugin (command shift s) 4 | export default function(context) { 5 | var selection = context.selection; 6 | context.document.showMessage('Plugin 🏃'); 7 | 8 | if (selection.length == 0) { 9 | return context.document.showMessage('🗝🌈: Please select an object'); 10 | } 11 | // if its a text 12 | if (selection[0] instanceof MSTextLayer) { 13 | return context.document.showMessage( 14 | '❌: Please use `Tokenizer > Get Tone` for texts' 15 | ); 16 | } 17 | 18 | const colorMapping = Utils.getBaseColorsVariablesMapping(); 19 | // console.log('colorMapping', colorMapping); 20 | const currentSelectedColor = Utils.getBorderHexColor(selection) 21 | .toString() 22 | .toUpperCase(); 23 | const color = colorMapping[`#${currentSelectedColor}`]; 24 | 25 | const callback = () => 26 | insertTokenrVariable(selection, `#${currentSelectedColor}`); 27 | 28 | // checks if color belongs to UI Kit, if not returns an error 29 | Utils.colorChecker(color, callback); 30 | } 31 | 32 | function insertTokenrVariable(selection, hexColor) { 33 | const position = { 34 | x: selection[0].absoluteRect().rulerX(), 35 | y: selection[0].absoluteRect().rulerY(), 36 | midY: selection[0].absoluteRect().height() / 2, 37 | width: selection[0].absoluteRect().width() 38 | }; 39 | 40 | const layerName = String(selection[0].name()); 41 | 42 | const tokenText = Utils.getTokenVariable('border-color', 'input', hexColor); 43 | 44 | Utils.insertTokenText( 45 | position, 46 | layerName, 47 | 'token input border color', 48 | tokenText, 49 | true 50 | ); 51 | } 52 | -------------------------------------------------------------------------------- /src/menu-import/import-base-colors-decisions-file.js: -------------------------------------------------------------------------------- 1 | const importFile = require('./../utils.js').importFile; 2 | 3 | export default function(context) { 4 | const fileName = 'Base colors'; 5 | 6 | // the value global state will hold 7 | const objName = 'baseColors'; 8 | 9 | importFile(fileName, objName); 10 | 11 | context.document.showMessage( 12 | `📩🎉: File for ${fileName} imported! Ready to use!` 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /src/menu-import/import-token-backgrounds-decisions-file.js: -------------------------------------------------------------------------------- 1 | const importFile = require('./../utils.js').importFile; 2 | 3 | export default function(context) { 4 | const fileName = 'Background decisions'; 5 | 6 | // the value global state will hold 7 | const objName = 'background'; 8 | 9 | importFile(fileName, objName); 10 | 11 | context.document.showMessage( 12 | `📩🎉: File for ${fileName} imported! Ready to use!` 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /src/menu-import/import-token-borders-decisions-file.js: -------------------------------------------------------------------------------- 1 | const importFile = require('./../utils.js').importFile; 2 | 3 | export default function(context) { 4 | const fileName = 'Border decisions'; 5 | 6 | // the value global state will hold 7 | const objName = 'border'; 8 | 9 | importFile(fileName, objName); 10 | 11 | context.document.showMessage( 12 | `📩🎉: File for ${fileName} imported! Ready to use!` 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | const ColorConverter = require('./converters/colors.js'); 2 | 3 | const quoteColor = { r: 1, g: 0.369, b: 0.941, a: 1 }; 4 | const lineHeight = 14; 5 | const lineWidth = 85; 6 | 7 | // UI Creators 8 | 9 | export function insertTokenText( 10 | position, 11 | layerGroupName, 12 | title, 13 | text, 14 | isBorder = false 15 | ) { 16 | const capitalizedTitle = title[0].toUpperCase() + title.slice(1); 17 | const textWithToken = createTextLayer(`${capitalizedTitle}: ${text}`); 18 | const quoteLine = createQuoteLine(position, isBorder); 19 | 20 | // var bounds = MSLayerGroup.groupBoundsForContainer( 21 | // MSLayerArray.arrayWithLayers([quoteLine, textWithToken]) 22 | // ); 23 | 24 | insertIntoGroup( 25 | layerGroupName, 26 | title, 27 | { text: textWithToken, line: quoteLine }, 28 | position, 29 | isBorder 30 | ); 31 | } 32 | 33 | export function insertIntoGroup( 34 | layerGroupName, 35 | property, 36 | layers, 37 | position, 38 | isBorder 39 | ) { 40 | var groupLayer = MSLayerGroup.new(); 41 | 42 | // to simulate the heigt/width 43 | var bounds = MSLayerGroup.groupBoundsForContainer( 44 | MSLayerArray.arrayWithLayers([layers.line, layers.text]) 45 | ); 46 | 47 | // if its a border, we want the quote line to touch it, otherwise touch fill 48 | const touchOffset = isBorder ? 0 : 5; 49 | 50 | // if its a border TOKEN, we want the quote line to start from the same point as fill quoted line 51 | const startingPointOffset = isBorder ? lineHeight : 0; 52 | 53 | // spacing between line and text 54 | const spacing = 4; 55 | 56 | // moves the text a bit further from object 57 | layers.text.frame().x = lineWidth + spacing; 58 | if (isBorder) { 59 | layers.text.frame().y = -lineHeight; 60 | } 61 | 62 | groupLayer.name = `Token ${property} for ${layerGroupName}`; 63 | groupLayer.layers = [layers.line, layers.text]; 64 | 65 | groupLayer.resizeToFitChildrenWithOption(1); 66 | groupLayer.frame().x = position.x + position.width - touchOffset; 67 | groupLayer.frame().y = 68 | position.y + position.midY - bounds.size.height / 2 - startingPointOffset; 69 | var currentParentGroup = 70 | context.document.currentPage().currentArtboard() || 71 | context.document.currentPage(); 72 | currentParentGroup.addLayers([groupLayer]); 73 | } 74 | 75 | export function createQuoteLine(position, isBorder) { 76 | const lineHeightMidY = lineHeight / 2; 77 | 78 | // if its a border TOKEN, we want the quote line to start from the same point as fill quoted line 79 | const startingPointOffset = isBorder ? 15 : 0; 80 | var path = NSBezierPath.bezierPath(); 81 | path.moveToPoint( 82 | NSMakePoint(lineWidth, lineHeightMidY - startingPointOffset) 83 | ); 84 | path.lineToPoint(NSMakePoint(0, lineHeightMidY)); 85 | 86 | var shape = MSShapeGroup.shapeWithBezierPath(MSPath.pathWithBezierPath(path)); 87 | var border = shape.style().addStylePartOfType(1); 88 | border.color = MSColor.colorWithRGBADictionary(quoteColor); 89 | border.thickness = 1; 90 | 91 | return shape; 92 | } 93 | 94 | export function createTextLayer(stringValue) { 95 | var textLayer = MSTextLayer.new(); 96 | textLayer.stringValue = stringValue; 97 | textLayer.name = 'Text'; 98 | textLayer.setTextColor(MSColor.colorWithRGBADictionary(quoteColor)); 99 | return textLayer; 100 | } 101 | 102 | // Token getters 103 | 104 | export function getTokenVariable(property, component, hexColor) { 105 | const baseColorsMap = getBaseColorsVariablesMapping(); 106 | const prefix = '--token'; 107 | 108 | // if property has `-`, splits it 109 | const hasDash = /-/; 110 | const propertyPrefix = hasDash.test(property) 111 | ? property.split('-') 112 | : property; 113 | 114 | let states; 115 | let decisionsFile; 116 | let propertyName; 117 | 118 | // if the propery is passed with dash (E.g border-color) 119 | if (propertyPrefix instanceof Array) { 120 | decisionsFile = getDecisionsJson(propertyPrefix[0]); 121 | if (!decisionsFile) { 122 | return context.document.showMessage( 123 | `✋🏻❌: Please load a decisions token file for ${property} before continuing` 124 | ); 125 | } 126 | states = decisionsFile[propertyPrefix[1]][component]; 127 | propertyName = `${propertyPrefix[0]}-${propertyPrefix[1]}`; 128 | } else { 129 | decisionsFile = getDecisionsJson(propertyPrefix); 130 | if (!decisionsFile) { 131 | return context.document.showMessage( 132 | `✋🏻❌: Please load a decisions token file for ${property} before continuing` 133 | ); 134 | } 135 | states = decisionsFile[propertyPrefix][component]; 136 | propertyName = propertyPrefix; 137 | } 138 | 139 | if (!baseColorsMap) { 140 | return context.document.showMessage( 141 | '✋🏻❌: Please load a decisions base colors file before continuing' 142 | ); 143 | } 144 | 145 | // gets the color from selected element 146 | const selectedColor = baseColorsMap[hexColor].replace('--color-', ''); 147 | 148 | const selectedState = Object.keys(states).find( 149 | state => states[state] == selectedColor 150 | ); 151 | 152 | if (!selectedState) { 153 | return context.document.showMessage( 154 | '🎨🚫: Non-recognized token color. Please make sure to use a valid color for this token' 155 | ); 156 | } 157 | 158 | return `${prefix}-${propertyName}-${component}-${selectedState}`; 159 | } 160 | 161 | // Base color getters 162 | 163 | export function getFillHexColor(selection) { 164 | var layer = context.selection[0]; 165 | var selectedColor = getRGBColor('fill', layer); 166 | var colorHex = selectedColor 167 | .immutableModelObject() 168 | .hexValue() 169 | .toString(); 170 | return colorHex; 171 | } 172 | 173 | function getDecisionsJson(object) { 174 | // Gets the json data stored in global state 175 | let threadDictionary = NSThread.mainThread().threadDictionary(); 176 | let decisions = threadDictionary[object]; 177 | return decisions; 178 | } 179 | 180 | export function getBorderHexColor(selection) { 181 | var layer = context.selection[0]; 182 | var selectedColor = getRGBColor('border', layer); 183 | var colorHex = selectedColor 184 | .immutableModelObject() 185 | .hexValue() 186 | .toString(); 187 | return colorHex; 188 | } 189 | 190 | export function getRGBColor(type, layer) { 191 | var color; 192 | 193 | if (type === 'fill') { 194 | if (layer instanceof MSTextLayer) { 195 | color = layer.textColor(); 196 | } else { 197 | color = layer 198 | .style() 199 | .fills() 200 | .firstObject() 201 | .color(); 202 | } 203 | } else { 204 | color = layer 205 | .style() 206 | .borders() 207 | .firstObject() 208 | .color(); 209 | } 210 | 211 | return color; 212 | } 213 | 214 | export function getHexValueFromColorVariable(colorVar, baseColorsVariablesMap) { 215 | const colorVarWithPrefix = `--color-${colorVar}`; 216 | return Object.keys(baseColorsVariablesMap).find(hexVal => { 217 | if (baseColorsVariablesMap[hexVal] == colorVarWithPrefix) return hexVal; 218 | }); 219 | } 220 | 221 | // Checkers 222 | 223 | export function colorChecker(color, callback) { 224 | if (typeof color === 'undefined') { 225 | return context.document.showMessage( 226 | '🎨🚫: Non UI Kit color. Please make sure to use a valid color' 227 | ); 228 | } else { 229 | return callback(); 230 | } 231 | } 232 | 233 | // General scripts 234 | 235 | export function getBaseColorsVariablesMapping() { 236 | // Gets the json data stored in global state 237 | const importedBaseColors = getDecisionsJson('baseColors'); 238 | 239 | if (!importedBaseColors) 240 | return context.document.showMessage( 241 | '🗃👎🏻 No file imported. Please import your base colors file in `Import base colors file...`' 242 | ); 243 | 244 | const colorNames = {}; 245 | // gets default color variables 246 | Object.keys(importedBaseColors).map(colorGroupName => { 247 | const colorGroup = importedBaseColors[colorGroupName]; 248 | const colorDefaultName = colorGroup.default; 249 | colorNames[colorDefaultName.toString().toUpperCase()] = 250 | '--color-' + colorGroupName; 251 | 252 | Object.keys(colorGroup).forEach(variation => { 253 | // filters out default values 254 | if (variation !== 'default') { 255 | const variationName = colorGroup[variation]; 256 | const variationNameWithoutPercetageSign = variationName 257 | .toString() 258 | .replace('%', ''); 259 | colorNames[ 260 | ColorConverter.transformColorLightness( 261 | colorGroup.default, 262 | variationNameWithoutPercetageSign 263 | ).toUpperCase() 264 | ] = 265 | '--color-' + colorGroupName + '-' + variation; 266 | } 267 | }); 268 | }); 269 | return colorNames; 270 | } 271 | 272 | // importers 273 | 274 | export function importFile(fileName, objName) { 275 | //ask for JSON file path, passing the last location if available 276 | let dataPath = askForJSON('lastJSONPath', fileName); 277 | if (!dataPath) return; 278 | 279 | //load json data 280 | let jsonData = loadJSONData(dataPath); 281 | if (!jsonData) return; 282 | 283 | //get root dir used when populating local images 284 | let jsonDir = NSString.stringWithString( 285 | dataPath 286 | ).stringByDeletingLastPathComponent(); 287 | 288 | let threadDictionary = NSThread.mainThread().threadDictionary(); 289 | threadDictionary[objName] = { ...jsonData }; 290 | } 291 | 292 | function askForJSON(path, fileName) { 293 | //create panel 294 | let panel = NSOpenPanel.openPanel(); 295 | 296 | //set panel properties 297 | panel.setTitle('Select JSON'); 298 | panel.setMessage(`Please select the JSON file for ${fileName}`); 299 | panel.setPrompt('Select'); 300 | panel.setCanCreateDirectories(false); 301 | panel.setCanChooseFiles(true); 302 | panel.setCanChooseDirectories(false); 303 | panel.setAllowsMultipleSelection(false); 304 | panel.setShowsHiddenFiles(false); 305 | panel.setExtensionHidden(false); 306 | 307 | //set initial panel path 308 | if (path) { 309 | panel.setDirectoryURL(NSURL.fileURLWithPath(path)); 310 | } else { 311 | panel.setDirectoryURL(NSURL.fileURLWithPath('/Users/' + NSUserName())); 312 | } 313 | 314 | //show panel 315 | let pressedButton = panel.runModal(); 316 | if (pressedButton == NSOKButton) { 317 | return panel.URL().path(); 318 | } 319 | } 320 | 321 | function loadJSONData(path) { 322 | //load contents 323 | let contents = readFileAsText(path); 324 | 325 | //get data from JSON 326 | let data; 327 | try { 328 | data = JSON.parse(contents); 329 | } catch (e) { 330 | context.document.showMessage( 331 | "There was an error parsing data. Please make sure it's valid." 332 | ); 333 | return; 334 | } 335 | 336 | return data; 337 | } 338 | 339 | function readFileAsText(path) { 340 | return NSString.stringWithContentsOfFile_encoding_error( 341 | path, 342 | NSUTF8StringEncoding, 343 | false 344 | ); 345 | } 346 | --------------------------------------------------------------------------------