├── .gitignore ├── README.md ├── Snap to 8pt Grid.sketchplugin └── Contents │ ├── Resources │ ├── icon-square.png │ ├── icon.png │ ├── screengrab.gif │ ├── snap-fontSize.png │ ├── snap-height.png │ ├── snap-lineHeight.png │ ├── snap-width.png │ ├── snap-x.png │ └── snap-y.png │ └── Sketch │ ├── __snap.js │ ├── __snap.js.map │ └── manifest.json ├── appcast.xml ├── assets ├── icon-square.png ├── icon.png ├── screengrab.gif ├── snap-fontSize.png ├── snap-height.png ├── snap-lineHeight.png ├── snap-width.png ├── snap-x.png └── snap-y.png ├── package-lock.json ├── package.json ├── sketch-assets └── icons.sketch └── src ├── manifest.json └── snap.js /.gitignore: -------------------------------------------------------------------------------- 1 | # build artifacts 2 | snapper.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 | 15 | # sketch 16 | # sketch-assets 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Snap to 8pt Grid 4 | 5 | A Sketch plugin which helps with snapping layer properties to the 8 point grid. 6 | It's also possible to change to other point grids like a 10 point grid. This can be altered via the settings of the plugin menu. 7 | 8 | screengrab 9 | 10 | ## Usage 11 | 1. Select any type of layer (or make a selection) 12 | 2. Choose one of the snapping commands from the menu or use Runner ;) 13 | 3. Boom! Your layer property is snapped to the 8pt grid😎 14 | 15 | ## Layer properties that can be snapped 16 | - X 17 | - Y 18 | - Height 19 | - Width 20 | - Line-height 21 | - Font-size 22 | 23 | ## Installation 24 | 25 | - [Download](../../releases/latest/download/Snap.to.8pt.Grid.sketchplugin.zip) the latest release of the plugin 26 | - Un-zip 27 | - Double-click on snapper.sketchplugin 28 | 29 | ## Development Guide 30 | 31 | _This plugin was created using `skpm`. For a detailed explanation on how things work, checkout the [skpm Readme](https://github.com/skpm/skpm/blob/master/README.md)._ 32 | 33 | ## To Do / Idea's 34 | 35 | - Snapping of paths 36 | - Add keyboard shortcuts 37 | - ~~Change pt/px amount of snapping (for example 10pt grid)~~ 38 | -------------------------------------------------------------------------------- /Snap to 8pt Grid.sketchplugin/Contents/Resources/icon-square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mheesakkers/sketch-plugin-snap-to-8pt-grid/9575329fd4b7bee105b372677797a509fe2f4ef6/Snap to 8pt Grid.sketchplugin/Contents/Resources/icon-square.png -------------------------------------------------------------------------------- /Snap to 8pt Grid.sketchplugin/Contents/Resources/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mheesakkers/sketch-plugin-snap-to-8pt-grid/9575329fd4b7bee105b372677797a509fe2f4ef6/Snap to 8pt Grid.sketchplugin/Contents/Resources/icon.png -------------------------------------------------------------------------------- /Snap to 8pt Grid.sketchplugin/Contents/Resources/screengrab.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mheesakkers/sketch-plugin-snap-to-8pt-grid/9575329fd4b7bee105b372677797a509fe2f4ef6/Snap to 8pt Grid.sketchplugin/Contents/Resources/screengrab.gif -------------------------------------------------------------------------------- /Snap to 8pt Grid.sketchplugin/Contents/Resources/snap-fontSize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mheesakkers/sketch-plugin-snap-to-8pt-grid/9575329fd4b7bee105b372677797a509fe2f4ef6/Snap to 8pt Grid.sketchplugin/Contents/Resources/snap-fontSize.png -------------------------------------------------------------------------------- /Snap to 8pt Grid.sketchplugin/Contents/Resources/snap-height.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mheesakkers/sketch-plugin-snap-to-8pt-grid/9575329fd4b7bee105b372677797a509fe2f4ef6/Snap to 8pt Grid.sketchplugin/Contents/Resources/snap-height.png -------------------------------------------------------------------------------- /Snap to 8pt Grid.sketchplugin/Contents/Resources/snap-lineHeight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mheesakkers/sketch-plugin-snap-to-8pt-grid/9575329fd4b7bee105b372677797a509fe2f4ef6/Snap to 8pt Grid.sketchplugin/Contents/Resources/snap-lineHeight.png -------------------------------------------------------------------------------- /Snap to 8pt Grid.sketchplugin/Contents/Resources/snap-width.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mheesakkers/sketch-plugin-snap-to-8pt-grid/9575329fd4b7bee105b372677797a509fe2f4ef6/Snap to 8pt Grid.sketchplugin/Contents/Resources/snap-width.png -------------------------------------------------------------------------------- /Snap to 8pt Grid.sketchplugin/Contents/Resources/snap-x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mheesakkers/sketch-plugin-snap-to-8pt-grid/9575329fd4b7bee105b372677797a509fe2f4ef6/Snap to 8pt Grid.sketchplugin/Contents/Resources/snap-x.png -------------------------------------------------------------------------------- /Snap to 8pt Grid.sketchplugin/Contents/Resources/snap-y.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mheesakkers/sketch-plugin-snap-to-8pt-grid/9575329fd4b7bee105b372677797a509fe2f4ef6/Snap to 8pt Grid.sketchplugin/Contents/Resources/snap-y.png -------------------------------------------------------------------------------- /Snap to 8pt Grid.sketchplugin/Contents/Sketch/__snap.js: -------------------------------------------------------------------------------- 1 | var globalThis = this; 2 | var global = this; 3 | function __skpm_run (key, context) { 4 | globalThis.context = context; 5 | try { 6 | 7 | var exports = 8 | /******/ (function(modules) { // webpackBootstrap 9 | /******/ // The module cache 10 | /******/ var installedModules = {}; 11 | /******/ 12 | /******/ // The require function 13 | /******/ function __webpack_require__(moduleId) { 14 | /******/ 15 | /******/ // Check if module is in cache 16 | /******/ if(installedModules[moduleId]) { 17 | /******/ return installedModules[moduleId].exports; 18 | /******/ } 19 | /******/ // Create a new module (and put it into the cache) 20 | /******/ var module = installedModules[moduleId] = { 21 | /******/ i: moduleId, 22 | /******/ l: false, 23 | /******/ exports: {} 24 | /******/ }; 25 | /******/ 26 | /******/ // Execute the module function 27 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 28 | /******/ 29 | /******/ // Flag the module as loaded 30 | /******/ module.l = true; 31 | /******/ 32 | /******/ // Return the exports of the module 33 | /******/ return module.exports; 34 | /******/ } 35 | /******/ 36 | /******/ 37 | /******/ // expose the modules object (__webpack_modules__) 38 | /******/ __webpack_require__.m = modules; 39 | /******/ 40 | /******/ // expose the module cache 41 | /******/ __webpack_require__.c = installedModules; 42 | /******/ 43 | /******/ // define getter function for harmony exports 44 | /******/ __webpack_require__.d = function(exports, name, getter) { 45 | /******/ if(!__webpack_require__.o(exports, name)) { 46 | /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); 47 | /******/ } 48 | /******/ }; 49 | /******/ 50 | /******/ // define __esModule on exports 51 | /******/ __webpack_require__.r = function(exports) { 52 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 53 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 54 | /******/ } 55 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 56 | /******/ }; 57 | /******/ 58 | /******/ // create a fake namespace object 59 | /******/ // mode & 1: value is a module id, require it 60 | /******/ // mode & 2: merge all properties of value into the ns 61 | /******/ // mode & 4: return value when already ns object 62 | /******/ // mode & 8|1: behave like require 63 | /******/ __webpack_require__.t = function(value, mode) { 64 | /******/ if(mode & 1) value = __webpack_require__(value); 65 | /******/ if(mode & 8) return value; 66 | /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 67 | /******/ var ns = Object.create(null); 68 | /******/ __webpack_require__.r(ns); 69 | /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 70 | /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 71 | /******/ return ns; 72 | /******/ }; 73 | /******/ 74 | /******/ // getDefaultExport function for compatibility with non-harmony modules 75 | /******/ __webpack_require__.n = function(module) { 76 | /******/ var getter = module && module.__esModule ? 77 | /******/ function getDefault() { return module['default']; } : 78 | /******/ function getModuleExports() { return module; }; 79 | /******/ __webpack_require__.d(getter, 'a', getter); 80 | /******/ return getter; 81 | /******/ }; 82 | /******/ 83 | /******/ // Object.prototype.hasOwnProperty.call 84 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 85 | /******/ 86 | /******/ // __webpack_public_path__ 87 | /******/ __webpack_require__.p = ""; 88 | /******/ 89 | /******/ 90 | /******/ // Load entry module and return exports 91 | /******/ return __webpack_require__(__webpack_require__.s = "./src/snap.js"); 92 | /******/ }) 93 | /************************************************************************/ 94 | /******/ ({ 95 | 96 | /***/ "./src/snap.js": 97 | /*!*********************!*\ 98 | !*** ./src/snap.js ***! 99 | \*********************/ 100 | /*! exports provided: snap, settings */ 101 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 102 | 103 | "use strict"; 104 | __webpack_require__.r(__webpack_exports__); 105 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "snap", function() { return snap; }); 106 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "settings", function() { return settings; }); 107 | /* harmony import */ var sketch__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! sketch */ "sketch"); 108 | /* harmony import */ var sketch__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(sketch__WEBPACK_IMPORTED_MODULE_0__); 109 | 110 | function snap(context) { 111 | // Document & Selection 112 | var document = sketch__WEBPACK_IMPORTED_MODULE_0__["Document"].getSelectedDocument(); 113 | var selection = document.selectedLayers; // Run 114 | 115 | if (!selection.isEmpty) { 116 | // Get setting for grid type 117 | var amount_point_grid = sketch__WEBPACK_IMPORTED_MODULE_0__["Settings"].documentSettingForKey(document, 'gridType') || 8; // !important Specify type which gets snapped in manifests identifiers 118 | 119 | var commands = [context.command.identifier().replace('snap-', '')]; // Split up if there are multiple types to snap to 120 | 121 | commands = commands[0].split("-"); // Snap 122 | 123 | commands.forEach(function (type) { 124 | selection.layers.forEach(function (layer) { 125 | var key = "frame"; 126 | 127 | if (type == "lineHeight" || type == "fontSize") { 128 | key = "style"; 129 | } 130 | 131 | if (layer[key][type]) { 132 | var offset = layer[key][type] % amount_point_grid; 133 | 134 | if (offset < amount_point_grid * 0.5) { 135 | layer[key][type] -= offset; 136 | } else { 137 | layer[key][type] += amount_point_grid - offset; 138 | } 139 | } 140 | }); 141 | }); // Message 142 | 143 | sketch__WEBPACK_IMPORTED_MODULE_0__["UI"].message("👌Snapped to " + amount_point_grid + "pt grid!"); 144 | } else { 145 | sketch__WEBPACK_IMPORTED_MODULE_0__["UI"].message("It seems you haven't selected any layers"); 146 | } 147 | } 148 | function settings(context) { 149 | var document = sketch__WEBPACK_IMPORTED_MODULE_0__["Document"].getSelectedDocument(); 150 | sketch__WEBPACK_IMPORTED_MODULE_0__["UI"].getInputFromUser("Change point grid setting", { 151 | type: sketch__WEBPACK_IMPORTED_MODULE_0__["UI"].INPUT_TYPE.selection, 152 | possibleValues: ['2pt Grid', '4pt Grid', '6pt Grid', '8pt Grid', '10pt Grid', '12pt Grid', '16pt Grid'], 153 | initialValue: (sketch__WEBPACK_IMPORTED_MODULE_0__["Settings"].documentSettingForKey(document, 'gridType') || 8) + 'pt Grid' 154 | }, function (err, value) { 155 | if (err) { 156 | // most likely the user canceled the input 157 | return; 158 | } 159 | 160 | var point_value = value.split('pt Grid')[0]; 161 | sketch__WEBPACK_IMPORTED_MODULE_0__["Settings"].setDocumentSettingForKey(document, 'gridType', point_value || 8); 162 | }); 163 | } 164 | 165 | /***/ }), 166 | 167 | /***/ "sketch": 168 | /*!*************************!*\ 169 | !*** external "sketch" ***! 170 | \*************************/ 171 | /*! no static exports found */ 172 | /***/ (function(module, exports) { 173 | 174 | module.exports = require("sketch"); 175 | 176 | /***/ }) 177 | 178 | /******/ }); 179 | if (key === 'default' && typeof exports === 'function') { 180 | exports(context); 181 | } else if (typeof exports[key] !== 'function') { 182 | throw new Error('Missing export named "' + key + '". Your command should contain something like `export function " + key +"() {}`.'); 183 | } else { 184 | exports[key](context); 185 | } 186 | } catch (err) { 187 | if (typeof process !== 'undefined' && process.listenerCount && process.listenerCount('uncaughtException')) { 188 | process.emit("uncaughtException", err, "uncaughtException"); 189 | } else { 190 | throw err 191 | } 192 | } 193 | } 194 | globalThis['snap'] = __skpm_run.bind(this, 'snap'); 195 | globalThis['onRun'] = __skpm_run.bind(this, 'default'); 196 | globalThis['snap'] = __skpm_run.bind(this, 'snap'); 197 | globalThis['snap'] = __skpm_run.bind(this, 'snap'); 198 | globalThis['snap'] = __skpm_run.bind(this, 'snap'); 199 | globalThis['snap'] = __skpm_run.bind(this, 'snap'); 200 | globalThis['snap'] = __skpm_run.bind(this, 'snap'); 201 | globalThis['snap'] = __skpm_run.bind(this, 'snap'); 202 | globalThis['snap'] = __skpm_run.bind(this, 'snap'); 203 | globalThis['settings'] = __skpm_run.bind(this, 'settings') 204 | 205 | //# sourceMappingURL=__snap.js.map -------------------------------------------------------------------------------- /Snap to 8pt Grid.sketchplugin/Contents/Sketch/__snap.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack://exports/webpack/bootstrap","webpack://exports/./src/snap.js","webpack://exports/external \"sketch\""],"names":["snap","context","document","Document","getSelectedDocument","selection","selectedLayers","isEmpty","amount_point_grid","Settings","documentSettingForKey","commands","command","identifier","replace","split","forEach","type","layers","layer","key","offset","UI","message","settings","getInputFromUser","INPUT_TYPE","possibleValues","initialValue","err","value","point_value","setDocumentSettingForKey"],"mappings":"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","file":"__snap.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/snap.js\");\n","import { Document, UI, Settings } from 'sketch'\n\nexport function snap (context) {\n\t// Document & Selection\n\tvar document = Document.getSelectedDocument()\n\tvar selection = document.selectedLayers\n\n\t// Run\n\tif (!selection.isEmpty) {\n\t\t// Get setting for grid type\n\t\tvar amount_point_grid = Settings.documentSettingForKey(document, 'gridType') || 8\n\n\t\t// !important Specify type which gets snapped in manifests identifiers\n\t\tlet commands = [ context.command.identifier().replace('snap-','') ]\n\n\t\t// Split up if there are multiple types to snap to\n\t\tcommands = commands[0].split(\"-\")\n\n\t\t// Snap\n\t\tcommands.forEach(type => {\n\t\t\tselection.layers.forEach(layer => {\n\t\t\t\tlet key = \"frame\"\n\t\t\t\t\n\t\t\t\tif (type == \"lineHeight\" || type == \"fontSize\") {\n\t\t\t\t\tkey = \"style\"\n\t\t\t\t}\n\n\t\t\t\tif (layer[key][type]) {\n\t\t\t\t\tlet offset = layer[key][type] % amount_point_grid\n\t\t\t\t\tif (offset < (amount_point_grid * 0.5)) {\n\t\t\t\t\t\tlayer[key][type] -= offset\n\t\t\t\t\t} else {\n\t\t \tlayer[key][type] += (amount_point_grid - offset)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t})\n\t\t})\n\n\t\t// Message\n\t\tUI.message(\"👌Snapped to \" + amount_point_grid + \"pt grid!\")\n\n\t} else {\n\t\tUI.message(\"It seems you haven't selected any layers\")\n\t}\n\n}\n\nexport function settings (context) {\n\tvar document = Document.getSelectedDocument()\n\n\tUI.getInputFromUser(\n\t \"Change point grid setting\",\n\t {\n\t type: UI.INPUT_TYPE.selection,\n\t possibleValues: ['2pt Grid', '4pt Grid', '6pt Grid', '8pt Grid', '10pt Grid', '12pt Grid', '16pt Grid'],\n\t initialValue: (Settings.documentSettingForKey(document, 'gridType') || 8) + 'pt Grid'\n\t },\n\t (err, value) => {\n\t if (err) {\n\t // most likely the user canceled the input\n\t return\n\t }\n\n\t let point_value = value.split('pt Grid')[0]\n\t Settings.setDocumentSettingForKey(document, 'gridType', point_value || 8);\n\t }\n\t)\n}","module.exports = require(\"sketch\");"],"sourceRoot":""} -------------------------------------------------------------------------------- /Snap to 8pt Grid.sketchplugin/Contents/Sketch/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/sketch-hq/SketchAPI/develop/docs/sketch-plugin-manifest-schema.json", 3 | "name": "Snap to 8pt Grid", 4 | "version": "1.0.2", 5 | "description": "A Sketch plugin which helps with snapping layer properties to the 8 point grid.", 6 | "icon": "icon-square.png", 7 | "appcast": "https://raw.githubusercontent.com/mheesakkers/sketch-plugin-snap-to-8pt-grid/master/appcast.xml", 8 | "authorEmail": "misha.heesakkers@gmail.com", 9 | "author": "Misha Heesakkers", 10 | "commands": [ 11 | { 12 | "name": "Snap X", 13 | "description": "Snap X position of layer to the 8 point grid", 14 | "identifier": "snap-x", 15 | "icon": "snap-x.png", 16 | "script": "__snap.js", 17 | "handler": "snap" 18 | }, 19 | { 20 | "name": "Snap Y", 21 | "description": "Snap Y position of layer to the 8 point grid", 22 | "identifier": "snap-y", 23 | "icon": "snap-y.png", 24 | "script": "__snap.js", 25 | "handler": "snap" 26 | }, 27 | { 28 | "name": "Snap Width", 29 | "description": "Snap width of layer to the 8 point grid", 30 | "identifier": "snap-width", 31 | "icon": "snap-width.png", 32 | "script": "__snap.js", 33 | "handler": "snap" 34 | }, 35 | { 36 | "name": "Snap Height", 37 | "description": "Snap height of layer to the 8 point grid", 38 | "identifier": "snap-height", 39 | "icon": "snap-height.png", 40 | "script": "__snap.js", 41 | "handler": "snap" 42 | }, 43 | { 44 | "name": "Snap Horizontal", 45 | "description": "Snap width and x position of layer to the 8 point grid", 46 | "identifier": "snap-width-x", 47 | "script": "__snap.js", 48 | "handler": "snap" 49 | }, 50 | { 51 | "name": "Snap Vertical", 52 | "description": "Snap height and y position of layer to the 8 point grid", 53 | "identifier": "snap-height-y", 54 | "script": "__snap.js", 55 | "handler": "snap" 56 | }, 57 | { 58 | "name": "Snap Font size", 59 | "description": "Snap font size of Text layer to the 8 point grid", 60 | "identifier": "snap-fontSize", 61 | "icon": "snap-fontSize.png", 62 | "script": "__snap.js", 63 | "handler": "snap" 64 | }, 65 | { 66 | "name": "Snap Line-height", 67 | "description": "Snap line-height of Text layer to the 8 point grid", 68 | "identifier": "snap-lineHeight", 69 | "icon": "snap-lineHeight.png", 70 | "script": "__snap.js", 71 | "handler": "snap" 72 | }, 73 | { 74 | "name": "⚙️ Settings", 75 | "description": "Change settings of the point grid", 76 | "identifier": "settings", 77 | "script": "__snap.js", 78 | "handler": "settings" 79 | } 80 | ], 81 | "menu": { 82 | "title": "Snap to 8pt Grid", 83 | "items": [ 84 | "snap-x", 85 | "snap-y", 86 | "snap-width", 87 | "snap-height", 88 | "snap-width-x", 89 | "snap-height-y", 90 | "snap-fontSize", 91 | "snap-lineHeight", 92 | "settings" 93 | ] 94 | }, 95 | "identifier": "SnapTo8ptGrid", 96 | "disableCocoaScriptPreprocessor": true 97 | } -------------------------------------------------------------------------------- /appcast.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Sketch Plugin: Snap to 8pt Grid 5 | http://sparkle-project.org/files/sparkletestcast.xml 6 | A Sketch plugin which helps with snapping layer properties to the 8 point grid. 7 | en 8 | 9 | Version 1.0.2 10 | Added a settings feature to change the point grid amount 11 | 12 | 13 | 14 | Version 1.0.1 15 | Initial release of the plugin 16 | 17 | 18 | 19 | Beta 20 | Beta release 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /assets/icon-square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mheesakkers/sketch-plugin-snap-to-8pt-grid/9575329fd4b7bee105b372677797a509fe2f4ef6/assets/icon-square.png -------------------------------------------------------------------------------- /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mheesakkers/sketch-plugin-snap-to-8pt-grid/9575329fd4b7bee105b372677797a509fe2f4ef6/assets/icon.png -------------------------------------------------------------------------------- /assets/screengrab.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mheesakkers/sketch-plugin-snap-to-8pt-grid/9575329fd4b7bee105b372677797a509fe2f4ef6/assets/screengrab.gif -------------------------------------------------------------------------------- /assets/snap-fontSize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mheesakkers/sketch-plugin-snap-to-8pt-grid/9575329fd4b7bee105b372677797a509fe2f4ef6/assets/snap-fontSize.png -------------------------------------------------------------------------------- /assets/snap-height.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mheesakkers/sketch-plugin-snap-to-8pt-grid/9575329fd4b7bee105b372677797a509fe2f4ef6/assets/snap-height.png -------------------------------------------------------------------------------- /assets/snap-lineHeight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mheesakkers/sketch-plugin-snap-to-8pt-grid/9575329fd4b7bee105b372677797a509fe2f4ef6/assets/snap-lineHeight.png -------------------------------------------------------------------------------- /assets/snap-width.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mheesakkers/sketch-plugin-snap-to-8pt-grid/9575329fd4b7bee105b372677797a509fe2f4ef6/assets/snap-width.png -------------------------------------------------------------------------------- /assets/snap-x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mheesakkers/sketch-plugin-snap-to-8pt-grid/9575329fd4b7bee105b372677797a509fe2f4ef6/assets/snap-x.png -------------------------------------------------------------------------------- /assets/snap-y.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mheesakkers/sketch-plugin-snap-to-8pt-grid/9575329fd4b7bee105b372677797a509fe2f4ef6/assets/snap-y.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "SnapTo8ptGrid", 3 | "description": "A Sketch plugin which helps with snapping layer properties to the 8 point grid.", 4 | "version": "1.0.0", 5 | "engines": { 6 | "sketch": ">=49.0" 7 | }, 8 | "skpm": { 9 | "name": "SnapTo8ptGrid", 10 | "manifest": "src/manifest.json", 11 | "main": "Snap to 8pt Grid.sketchplugin", 12 | "assets": [ 13 | "assets/**/*" 14 | ], 15 | "sketch-assets-file": "sketch-assets/icons.sketch" 16 | }, 17 | "scripts": { 18 | "build": "skpm-build", 19 | "watch": "skpm-build --watch", 20 | "start": "skpm-build --watch --run", 21 | "postinstall": "npm run build && skpm-link" 22 | }, 23 | "devDependencies": { 24 | "@skpm/builder": "^0.7.0" 25 | }, 26 | "author": "Misha Heesakkers ", 27 | "repository": { 28 | "type": "git", 29 | "url": "https://github.com/mheesakkers/sketch-plugin-snap-to-8pt-grid" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /sketch-assets/icons.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mheesakkers/sketch-plugin-snap-to-8pt-grid/9575329fd4b7bee105b372677797a509fe2f4ef6/sketch-assets/icons.sketch -------------------------------------------------------------------------------- /src/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/sketch-hq/SketchAPI/develop/docs/sketch-plugin-manifest-schema.json", 3 | "name" : "Snap to 8pt Grid", 4 | "version" : "1.0.2", 5 | "description": "A Sketch plugin which helps with snapping layer properties to the 8 point grid.", 6 | "icon": "icon-square.png", 7 | "appcast" : "https://raw.githubusercontent.com/mheesakkers/sketch-plugin-snap-to-8pt-grid/master/appcast.xml", 8 | "authorEmail" : "misha.heesakkers@gmail.com", 9 | "author" : "Misha Heesakkers", 10 | "commands": [ 11 | { 12 | "name": "Snap X", 13 | "description": "Snap X position of layer to the 8 point grid", 14 | "identifier": "snap-x", 15 | "icon": "snap-x.png", 16 | "script": "./snap.js", 17 | "handler": "snap" 18 | }, 19 | { 20 | "name": "Snap Y", 21 | "description": "Snap Y position of layer to the 8 point grid", 22 | "identifier": "snap-y", 23 | "icon": "snap-y.png", 24 | "script": "./snap.js", 25 | "handler": "snap" 26 | }, 27 | { 28 | "name": "Snap Width", 29 | "description": "Snap width of layer to the 8 point grid", 30 | "identifier": "snap-width", 31 | "icon": "snap-width.png", 32 | "script": "./snap.js", 33 | "handler": "snap" 34 | }, 35 | { 36 | "name": "Snap Height", 37 | "description": "Snap height of layer to the 8 point grid", 38 | "identifier": "snap-height", 39 | "icon": "snap-height.png", 40 | "script": "./snap.js", 41 | "handler": "snap" 42 | }, 43 | { 44 | "name": "Snap Horizontal", 45 | "description": "Snap width and x position of layer to the 8 point grid", 46 | "identifier": "snap-width-x", 47 | "script": "./snap.js", 48 | "handler": "snap" 49 | }, 50 | { 51 | "name": "Snap Vertical", 52 | "description": "Snap height and y position of layer to the 8 point grid", 53 | "identifier": "snap-height-y", 54 | "script": "./snap.js", 55 | "handler": "snap" 56 | }, 57 | { 58 | "name": "Snap Font size", 59 | "description": "Snap font size of Text layer to the 8 point grid", 60 | "identifier": "snap-fontSize", 61 | "icon": "snap-fontSize.png", 62 | "script": "./snap.js", 63 | "handler": "snap" 64 | }, 65 | { 66 | "name": "Snap Line-height", 67 | "description": "Snap line-height of Text layer to the 8 point grid", 68 | "identifier": "snap-lineHeight", 69 | "icon": "snap-lineHeight.png", 70 | "script": "./snap.js", 71 | "handler": "snap" 72 | }, 73 | { 74 | "name": "⚙️ Settings", 75 | "description": "Change settings of the point grid", 76 | "identifier": "settings", 77 | "script": "./snap.js", 78 | "handler": "settings" 79 | } 80 | ], 81 | "menu": { 82 | "title": "Snap to 8pt Grid", 83 | "items": [ 84 | "snap-x", 85 | "snap-y", 86 | "snap-width", 87 | "snap-height", 88 | "snap-width-x", 89 | "snap-height-y", 90 | "snap-fontSize", 91 | "snap-lineHeight", 92 | "settings" 93 | ] 94 | } 95 | } -------------------------------------------------------------------------------- /src/snap.js: -------------------------------------------------------------------------------- 1 | import { Document, UI, Settings } from 'sketch' 2 | 3 | export function snap (context) { 4 | // Document & Selection 5 | var document = Document.getSelectedDocument() 6 | var selection = document.selectedLayers 7 | 8 | // Run 9 | if (!selection.isEmpty) { 10 | // Get setting for grid type 11 | var amount_point_grid = Settings.documentSettingForKey(document, 'gridType') || 8 12 | 13 | // !important Specify type which gets snapped in manifests identifiers 14 | let commands = [ context.command.identifier().replace('snap-','') ] 15 | 16 | // Split up if there are multiple types to snap to 17 | commands = commands[0].split("-") 18 | 19 | // Snap 20 | commands.forEach(type => { 21 | selection.layers.forEach(layer => { 22 | let key = "frame" 23 | 24 | if (type == "lineHeight" || type == "fontSize") { 25 | key = "style" 26 | } 27 | 28 | if (layer[key][type]) { 29 | let offset = layer[key][type] % amount_point_grid 30 | if (offset < (amount_point_grid * 0.5)) { 31 | layer[key][type] -= offset 32 | } else { 33 | layer[key][type] += (amount_point_grid - offset) 34 | } 35 | } 36 | 37 | }) 38 | }) 39 | 40 | // Message 41 | UI.message("👌Snapped to " + amount_point_grid + "pt grid!") 42 | 43 | } else { 44 | UI.message("It seems you haven't selected any layers") 45 | } 46 | 47 | } 48 | 49 | export function settings (context) { 50 | var document = Document.getSelectedDocument() 51 | 52 | UI.getInputFromUser( 53 | "Change point grid setting", 54 | { 55 | type: UI.INPUT_TYPE.selection, 56 | possibleValues: ['2pt Grid', '4pt Grid', '6pt Grid', '8pt Grid', '10pt Grid', '12pt Grid', '16pt Grid'], 57 | initialValue: (Settings.documentSettingForKey(document, 'gridType') || 8) + 'pt Grid' 58 | }, 59 | (err, value) => { 60 | if (err) { 61 | // most likely the user canceled the input 62 | return 63 | } 64 | 65 | let point_value = value.split('pt Grid')[0] 66 | Settings.setDocumentSettingForKey(document, 'gridType', point_value || 8); 67 | } 68 | ) 69 | } --------------------------------------------------------------------------------