├── LICENSE ├── README.md ├── Sketch bootstrap guides.sketchplugin └── Contents │ └── Sketch │ ├── main.js │ └── manifest.json └── docs └── screenshot.png /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Tomoyuki Kashiro 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sketch bootstrap guides 2 | 3 | # Feature 4 | 5 | This plugin generate guides along with twitter bootstrap(v3,v4) grid system. 6 | 7 | # Install 8 | 9 | ## Via Sketch app 10 | 11 | Open Sketch, on menu `Plugins` > `Reveal Plugins Folder`. Download the repo as ZIP and extract to above directory. 12 | 13 | # Usage 14 | 15 | menu `Plugins` > `Sketch bootstrap guide` > select `Generate Twbs3 Guides` or `Generate Twbs4 Guides`. 16 | 17 | These are menu you can use. 18 | 19 | - Remove All Guides 20 | - Remove Horizontal Guides 21 | - Remove Vertical Guides 22 | - Generate Twbs3 Guides 23 | - Generate Twbs3 Fluid Guides 24 | - Generate Twbs4 Guides 25 | - Generate Twbs4 Fluid Guides 26 | 27 | # Screenshot 28 | 29 | ![screenshot](https://tomoyukikashiro.github.io/Sketch-bootstrap-guides/screenshot.png) 30 | -------------------------------------------------------------------------------- /Sketch bootstrap guides.sketchplugin/Contents/Sketch/main.js: -------------------------------------------------------------------------------- 1 | // function generateGuide(context) { 2 | // 3 | // // We are passed a context variable when we're run. 4 | // // We use this to get hold of a javascript object 5 | // // which we can use in turn to manipulate Sketch. 6 | // var sketch = context.api(); 7 | // 8 | // // Next we want to extract the selected page of the selected (front-most) document 9 | // var document = sketch.selectedDocument; 10 | // var page = document.selectedPage; 11 | // 12 | // // Now let's create a new text layer, using a large font, and a traditional value... 13 | // var layer = page.newText({alignment: NSTextAlignmentCenter, systemFontSize: 36, text:"Hello World"}); 14 | // 15 | // // ...resize it so that the text just fits... 16 | // layer.resizeToFitContents(); 17 | // 18 | // // Finally, lets center the view on our new layer 19 | // // so that we can see where it is. 20 | // document.centerOnLayer(layer); 21 | // }; 22 | 23 | function extend(org, options) { 24 | var res = Object.create(null); 25 | for (key in org) { 26 | if (org.hasOwnProperty(key)) { 27 | res[key] = org[key]; 28 | } 29 | } 30 | for (key in options) { 31 | if (options.hasOwnProperty(key)) { 32 | res[key] = options[key]; 33 | } 34 | } 35 | return res; 36 | } 37 | 38 | function showMessage(message) { 39 | var userInput = COSAlertWindow.new(); 40 | userInput.setMessageText(message); 41 | userInput.runModal(); 42 | } 43 | 44 | function createSelect(msg, items){ 45 | var itemsCount = items.length 46 | 47 | var accessory = NSComboBox.alloc().initWithFrame(NSMakeRect(0,0,200,25)) 48 | accessory.addItemsWithObjectValues(items) 49 | accessory.selectItemAtIndex(0) 50 | 51 | var alert = NSAlert.alloc().init() 52 | alert.setMessageText(msg) 53 | alert.addButtonWithTitle('OK') 54 | alert.addButtonWithTitle('Cancel') 55 | alert.setAccessoryView(accessory) 56 | 57 | return { 58 | responseCode: alert.runModal(), 59 | value: accessory.objectValue() 60 | } 61 | } 62 | 63 | var Twbs = { 64 | GUTTER_WIDTH: 15, 65 | MINIMUM_WIDTH_FOR_12CULUMN: undefined, 66 | getGridKey: function(width) { 67 | if (width >= this.grid.xl) { 68 | return 'xl'; 69 | } else if (width >= this.grid.lg) { 70 | return 'lg'; 71 | } else if (width >= this.grid.md) { 72 | return 'md'; 73 | } else if (width >= this.grid.sm) { 74 | return 'sm'; 75 | } else { 76 | return 'xs'; 77 | } 78 | }, 79 | /** 80 | * If grid is xs this function does not return anything 81 | */ 82 | getContainerWidth: function(width) { 83 | return this.container[this.getGridKey(width)]; 84 | }, 85 | canUse12Column: function(outerWidth) { 86 | var minWidthFor12Column = this.grid[this.MINIMUM_WIDTH_FOR_12CULUMN]; 87 | return outerWidth >= minWidthFor12Column; 88 | } 89 | }; 90 | 91 | var Twbs3 = extend(Twbs, { 92 | MINIMUM_WIDTH_FOR_12CULUMN: 'sm', 93 | grid: { 94 | sm: 768, 95 | md: 992, 96 | lg: 1200 97 | }, 98 | container: { 99 | sm: 750, 100 | md: 970, 101 | lg: 1170 102 | }, 103 | }); 104 | 105 | var Twbs4 = extend(Twbs, { 106 | MINIMUM_WIDTH_FOR_12CULUMN: 'md', 107 | isVersion4: true, 108 | grid: { 109 | sm: 576, 110 | md: 768, 111 | lg: 992, 112 | xl: 1200 113 | }, 114 | container: { 115 | sm: 540, 116 | md: 720, 117 | lg: 960, 118 | xl: 1140 119 | }, 120 | }); 121 | 122 | 123 | function removeAllGuides(context) { 124 | removeHorizontalGuides(context); 125 | removeVerticalGuides(context); 126 | } 127 | function removeHorizontalGuides(context) { 128 | var doc = context.document; 129 | var page = doc.currentPage(); 130 | var artBoard = page.currentArtboard(); 131 | removeGuides(artBoard.horizontalRulerData()); 132 | } 133 | function removeVerticalGuides(context) { 134 | var doc = context.document; 135 | var page = doc.currentPage(); 136 | var artBoard = page.currentArtboard(); 137 | removeGuides(artBoard.verticalRulerData()); 138 | } 139 | function generateTwbs3Guide(context) { 140 | generateGuide(context, Twbs3) 141 | } 142 | function generateTwbs3FluidGuide(context) { 143 | generateGuide(context, Twbs3, true) 144 | } 145 | 146 | function generateTwbs4Guide(context) { 147 | generateGuide(context, Twbs4) 148 | } 149 | function generateTwbs4FluidGuide(context) { 150 | generateGuide(context, Twbs4, true) 151 | } 152 | 153 | 154 | function removeGuides(guideData) { 155 | while (guideData.numberOfGuides() > 0) { 156 | guideData.removeGuideAtIndex(0); 157 | } 158 | } 159 | 160 | function generateGuide(context, twbs, isFluid) { 161 | this.context = context; 162 | this.doc = this.context.document; 163 | this.page = this.doc.currentPage(); 164 | this.artBoard = this.page.currentArtboard(); 165 | 166 | if (!this.artBoard) { 167 | showMessage('This plugin needs Artboard.'); 168 | return; 169 | } 170 | if (twbs.getGridKey(this.artBoard.frame().width()) === 'xs') { 171 | // twbs use 100% width container in this case. 172 | isFluid = true; 173 | } 174 | var twbsContainerWidth = isFluid ? this.artBoard.frame().width() : twbs.getContainerWidth(this.artBoard.frame().width()); 175 | var columnNum; 176 | if (twbs.canUse12Column(twbsContainerWidth)) { 177 | columnNum = 12; 178 | } else { 179 | var res = createSelect('How many columns do you want to use?', [6,4,3,2]); 180 | if (res.responseCode === 1001) { 181 | // cancel 182 | return; 183 | } 184 | columnNum = parseInt(res.value, 10); 185 | } 186 | var guideX = (this.artBoard.frame().width() / 2) - (twbsContainerWidth / 2); 187 | var cellWidth = (twbsContainerWidth / columnNum) - (twbs.GUTTER_WIDTH * 2); 188 | 189 | var artBoardHRuler = this.artBoard.horizontalRulerData(); 190 | artBoardHRuler.addGuideWithValue(guideX); 191 | for (var i = 0; columnNum > i; i++) { 192 | guideX += twbs.GUTTER_WIDTH; 193 | artBoardHRuler.addGuideWithValue(guideX); 194 | guideX += cellWidth; 195 | artBoardHRuler.addGuideWithValue(guideX); 196 | guideX += twbs.GUTTER_WIDTH; 197 | if (i == columnNum - 1) { 198 | artBoardHRuler.addGuideWithValue(guideX); 199 | } 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /Sketch bootstrap guides.sketchplugin/Contents/Sketch/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "Sketch bootstrap guides", 3 | "identifier" : "me.tomoyukikashiro.sketch_bootstrap_guides", 4 | "version" : "1.1.0", 5 | "description" : "generate guides along with twitter bootstrap grid system.", 6 | "authorEmail" : "ksrtmyk@gmail.com", 7 | "author" : "Tomoyuki Kashiro", 8 | "commands" : [ 9 | { 10 | "script" : "main.js", 11 | "handler" : "removeAllGuides", 12 | "shortcut" : "", 13 | "name" : "Remove All Guides", 14 | "identifier" : "removeAllGuides" 15 | }, 16 | { 17 | "script" : "main.js", 18 | "handler" : "removeHorizontalGuides", 19 | "shortcut" : "", 20 | "name" : "Remove Horizontal Guides", 21 | "identifier" : "removeHorizontalGuides" 22 | }, 23 | { 24 | "script" : "main.js", 25 | "handler" : "removeVerticalGuides", 26 | "shortcut" : "", 27 | "name" : "Remove Vertical Guides", 28 | "identifier" : "removeVerticalGuides" 29 | }, 30 | { 31 | "script" : "main.js", 32 | "handler" : "generateTwbs3Guide", 33 | "shortcut" : "", 34 | "name" : "Generate Twbs3 Guides", 35 | "identifier" : "generateTwbs3Guide" 36 | }, 37 | { 38 | "script" : "main.js", 39 | "handler" : "generateTwbs3FluidGuide", 40 | "shortcut" : "", 41 | "name" : "Generate Twbs3 Fluid Guides", 42 | "identifier" : "generateTwbs3FluidGuide" 43 | }, 44 | { 45 | "script" : "main.js", 46 | "handler" : "generateTwbs4Guide", 47 | "shortcut" : "", 48 | "name" : "Generate Twbs4 Guides", 49 | "identifier" : "generateTwbs4Guide" 50 | }, 51 | { 52 | "script" : "main.js", 53 | "handler" : "generateTwbs4FluidGuide", 54 | "shortcut" : "", 55 | "name" : "Generate Twbs4 Fluid Guides", 56 | "identifier" : "generateTwbs4FluidGuide" 57 | } 58 | ], 59 | "menu": { 60 | "isRoot": true, 61 | "items": [ 62 | { 63 | "title" : "bootstrap guides", 64 | "items" : [ 65 | "removeAllGuides", 66 | "removeHorizontalGuides", 67 | "removeVerticalGuides", 68 | "generateTwbs3Guide", 69 | "generateTwbs3FluidGuide", 70 | "generateTwbs4Guide", 71 | "generateTwbs4FluidGuide" 72 | ] 73 | } 74 | ] 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /docs/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/t-jindai/Sketch-bootstrap-guides/bde4290bd3cea6b18a2b25ebad6ef2a1b2e3d684/docs/screenshot.png --------------------------------------------------------------------------------