├── LICENSE.md ├── README.md ├── formr-2.1.zip ├── formr.sketchplugin └── Contents │ └── Sketch │ ├── library.cocoascript │ ├── manifest.json │ └── script.cocoascript └── screenshot.png /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2017 Sasha Katin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Formr 2 | 3 | Sketch plugin that helps to maintain simple layer proportions. 4 | 5 | Simple proportions of shapes in most cases look aesthetically better than random. 6 | For now it supports `1:1`, `2:1`, `4:3` and `16:9` built-in proportions where first number is width and second is height. 7 | 8 | You can also use custom proportions by adding `::prop` to the layer/artboard name (where "prop" can be any simple fraction) and than pressing `ctrl+alt+shift+e`. For example, adding `::1/2` to 100×100 layer name gets you 50×100 layer. 9 | 10 | *Formr* supports layers, artboards, and multiple selection. 11 | 12 | __Works with Sketch 48+__ 13 | 14 | ## Shortcuts 15 | 16 | 1. To even out proportions press `ctrl+alt+shift+e` 17 | 2. To use 2:1 proportion press `ctrl+alt+shift+h` 18 | 3. To use 4:3 proportion press `ctrl+alt+shift+j` 19 | 4. To use 4:3 proportion press `ctrl+alt+shift+k` 20 | 5. To use custom proportion via layer name pattern press `ctrl+alt+shift+l` 21 | 22 | For other options, as for now, please use plugin menu. 23 | 24 | ## Screenshot 25 | 26 | ![screenshot](https://github.com/lessthanzero/Formr/blob/master/screenshot.png) 27 | 28 | ## Installation 29 | 30 | ### Sketch Runner 31 | 1. Install [Runner](http://sketchrunner.com) 32 | 2. Launch Runner `CMD+'` 33 | 3. Install Formr 34 | 35 | ### Sketch Toolbox 36 | 1. Install [Sketch Toolbox](http://sketchtoolbox.com) 37 | 2. Launch Toolbox and search for "Formr" 38 | 3. Click Install button 39 | 40 | ### Sketchpacks 41 | [![Install Formr with Sketchpacks](http://sketchpacks-com.s3.amazonaws.com/assets/badges/sketchpacks-badge-install.png "Install Formr with Sketchpacks")](https://sketchpacks.com/lessthanzero/Formr/install) 42 | 43 | ### Manually 44 | 45 | 1. Download and unpack [zip](https://github.com/lessthanzero/Formr/blob/master/formr-2.1.zip). 46 | 2. Install by double-clicking _formr.sketchplugin_ file or by manually putting it into _path-to-user/Library/Application Support/com.bohemiancoding.sketch3/Plugins_ folder. 47 | -------------------------------------------------------------------------------- /formr-2.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lessthanzero/Formr/f5e06a43752d5e172243b2702dff8dea81456e10/formr-2.1.zip -------------------------------------------------------------------------------- /formr.sketchplugin/Contents/Sketch/library.cocoascript: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lessthanzero/Formr/f5e06a43752d5e172243b2702dff8dea81456e10/formr.sketchplugin/Contents/Sketch/library.cocoascript -------------------------------------------------------------------------------- /formr.sketchplugin/Contents/Sketch/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "commands" : [ 3 | { 4 | "script" : "script.cocoascript", 5 | "handler" : "setEven", 6 | "shortcut" : "ctrl alt shift e", 7 | "name" : "1:1", 8 | "identifier" : "even" 9 | }, 10 | { 11 | "script" : "script.cocoascript", 12 | "handler" : "setHalf", 13 | "shortcut" : "ctrl alt shift h", 14 | "name" : "2:1", 15 | "identifier" : "half" 16 | }, 17 | { 18 | "script" : "script.cocoascript", 19 | "handler" : "setThreeQuarters", 20 | "shortcut" : "ctrl alt shift j", 21 | "name" : "4:3", 22 | "identifier" : "threequarters" 23 | }, 24 | { 25 | "script" : "script.cocoascript", 26 | "handler" : "setWidescreen", 27 | "shortcut" : "ctrl alt shift k", 28 | "name" : "16:9", 29 | "identifier" : "widescreen" 30 | }, 31 | { 32 | "script" : "script.cocoascript", 33 | "handler" : "setCustom", 34 | "shortcut" : "ctrl alt shift l", 35 | "name" : "Parse Layer Name", 36 | "identifier" : "setcustom" 37 | } 38 | ], 39 | "menu": { 40 | "isRoot": false, 41 | "items": [ 42 | "even", 43 | "half", 44 | "threequarters", 45 | "widescreen", 46 | "setcustom" 47 | ], 48 | }, 49 | "identifier" : "com.example.sketch.formr", 50 | "compatibleVersion": "42", 51 | "name": "Formr", 52 | "version": "2.1.3", 53 | "description": "Plugin for Sketch app, helping to maintain proportions of layers and artboards", 54 | "keywords": [ 55 | "sketch-app, plugin, proportion, layer, artboard, sketchapp" 56 | ], 57 | "author": "Sasha Katin", 58 | "authorEmail": "aleksandr.katin@gmail.com", 59 | "license": "MIT", 60 | "homepage": "https://github.com/lessthanzero/Formr", 61 | "repository": "https://github.com/lessthanzero/Formr.git", 62 | "updateURL": "https://github.com/downloads/example/sketchplugins/sketchplugins.json" 63 | } 64 | -------------------------------------------------------------------------------- /formr.sketchplugin/Contents/Sketch/script.cocoascript: -------------------------------------------------------------------------------- 1 | var com = com || {}; 2 | 3 | com.lessthanzero = { 4 | context: undefined, 5 | selection: undefined, 6 | page: undefined, 7 | pages: undefined, 8 | init: function(context, currentIsArtboard) { 9 | this.app = NSApplication.sharedApplication(); 10 | this.context = context; 11 | this.document = context.document; 12 | this.command = context.command; 13 | this.selection = context.selection; 14 | this.pages = this.document.pages(); 15 | this.page = this.document.currentPage(); 16 | }, 17 | extend: function(options, target) { 18 | var target = target || this; 19 | 20 | for (var key in options) { 21 | target[key] = options[key]; 22 | } 23 | return target; 24 | } 25 | } 26 | 27 | com.lessthanzero.extend({ 28 | setEven: function() { 29 | this.universal("even"); 30 | }, 31 | setHalf: function() { 32 | this.universal("half"); 33 | }, 34 | setThreeQuarters: function() { 35 | this.universal("threequarters"); 36 | }, 37 | setWidescreen: function() { 38 | this.universal("widescreen"); 39 | }, 40 | setCustom: function() { 41 | this.universal("custom"); 42 | }, 43 | universal: function(mode) { 44 | 45 | var coef = 1; 46 | var sl = this.selection.count(); 47 | 48 | if (sl != 0) { 49 | 50 | for (var i = 0; i < sl; i++) { 51 | 52 | var layer = this.selection[i]; 53 | var height = layer.absoluteRect().height(); 54 | var width = layer.absoluteRect().width(); 55 | 56 | if (mode == "custom") { 57 | var newProportion = this.parseName(layer); 58 | layer.absoluteRect().setWidth(height * newProportion); 59 | } else { 60 | 61 | if (mode == "even") { 62 | 63 | if (height > width) { 64 | layer.absoluteRect().setWidth(height); 65 | } else if (width > height) { 66 | layer.absoluteRect().setHeight(width); 67 | } 68 | 69 | } else { 70 | 71 | if (mode == "half") { 72 | coef = 0.5; 73 | } else if (mode == "threequarters") { 74 | coef = 0.75; 75 | } else if (mode == "widescreen") { 76 | coef = 0.5625; 77 | } 78 | var normalizedWidth = Math.floor(width * coef) 79 | layer.absoluteRect().setHeight(normalizedWidth) 80 | 81 | } 82 | 83 | } 84 | 85 | } 86 | 87 | } else { 88 | this.app.displayDialog_withTitle("Please, select at least one layer", "Nothing is selected") 89 | } 90 | }, 91 | parseName: function(layer) { 92 | var name = layer.name(); 93 | var nameKey = name.split("::"); 94 | var proportion = nameKey[1]; 95 | if (proportion) { 96 | 97 | propParts = proportion.split("/"); 98 | if (propParts) { 99 | 100 | var upper = parseInt(propParts[0], 10); 101 | var lower = parseInt(propParts[1], 10); 102 | if (upper && lower) { 103 | var detectedProportion = upper/lower; 104 | return detectedProportion; 105 | } else { 106 | this.app.displayDialog_withTitle("Please, use only integers in simple fraction. Like '::1/2'", "Incorrect proportion!") 107 | } 108 | 109 | } 110 | 111 | } 112 | } 113 | }) 114 | 115 | function setEven(context) { 116 | com.lessthanzero.init(context, true); 117 | com.lessthanzero.setEven(); 118 | } 119 | 120 | function setHalf(context) { 121 | com.lessthanzero.init(context, true); 122 | com.lessthanzero.setHalf(); 123 | } 124 | 125 | function setThreeQuarters(context) { 126 | com.lessthanzero.init(context, true); 127 | com.lessthanzero.setThreeQuarters(); 128 | } 129 | 130 | function setWidescreen(context) { 131 | com.lessthanzero.init(context, true); 132 | com.lessthanzero.setWidescreen(); 133 | } 134 | 135 | function setCustom(context) { 136 | com.lessthanzero.init(context, true); 137 | com.lessthanzero.setCustom(); 138 | } 139 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lessthanzero/Formr/f5e06a43752d5e172243b2702dff8dea81456e10/screenshot.png --------------------------------------------------------------------------------