├── .gitignore ├── .nowignore ├── LICENSE ├── README.md ├── assets └── demo.gif ├── now.json ├── package-lock.json ├── package.json ├── rollup.config.js ├── src ├── client.js ├── components │ ├── About.svelte │ ├── CSSOutput.svelte │ ├── ContextMenu │ │ ├── index.svelte │ │ └── kind.js │ ├── HighlightGrid │ │ ├── HighlightGrid.svelte │ │ └── index.svelte │ ├── Modal.svelte │ ├── ModalCSSDynamicImport.svelte │ ├── ModalCSSOutput.svelte │ └── Settings.svelte ├── routes │ └── index.svelte ├── server.js ├── service-worker.js ├── store │ └── index.js ├── template.html └── utils │ └── index.js ├── static ├── global.css ├── logo-192.png ├── logo-512.png ├── logo.png └── manifest.json └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | 63 | less.exe.stackdump 64 | 65 | /__sapper__/ 66 | test.html -------------------------------------------------------------------------------- /.nowignore: -------------------------------------------------------------------------------- 1 | assets/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Vahe 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 |

2 | 3 | Layout-master logo 4 |

5 | 6 |

7 | 8 |

9 | 10 |

11 | 12 | 13 | 14 |

15 | 16 | ##### INTRODUCTION 17 | 18 | This tool was created to create css3 grid layouts. This generates the grid and aims to generate css output. It is also a good place to learn CSS3 grid. 19 | 20 | ##### USAGE 21 | 22 | There are no menus, footers or ads in the app, or other disturbing extraneous widgets. 23 | Everything is controlled using only the context menu. Right-click to toogle the context menu 24 | 25 | ##### TIP 26 | 27 | You can highlight the grid in the context menu by selecting "Highlight grid" 28 | 29 | ![](https://res.cloudinary.com/dmtrk3yns/image/upload/c_scale,h_388,q_auto/v1566135912/grid-maker/ezgif-2-a3ef207c2eec.gif) 30 | 31 | ##### EXTERNAL LINKS 32 | 33 | - [Dev.to — Make CSS3 grid layout in 1 minute](https://dev.to/vaheqelyan/make-css3-grid-layout-in-1-minute-4eo4) 34 | - [MDN web docs — CSS Grid Layout](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout) 35 | -------------------------------------------------------------------------------- /assets/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vaheqelyan/layout-master/e4eabee3d0d4e47a7be6a074b65456949a849f8c/assets/demo.gif -------------------------------------------------------------------------------- /now.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "layout-master", 3 | "alias": "layout-master", 4 | "public": true 5 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "layout-master", 3 | "description": "layout-master", 4 | "version": "0.0.1", 5 | "scripts": { 6 | "dev": "sapper dev", 7 | "build": "sapper export", 8 | "start": "node __sapper__/build" 9 | }, 10 | "dependencies": { 11 | "compression": "^1.7.1", 12 | "cookie-session": "^1.3.3", 13 | "polka": "^0.5.0", 14 | "sirv": "^0.4.0" 15 | }, 16 | "devDependencies": { 17 | "@babel/core": "^7.5.5", 18 | "@babel/plugin-syntax-dynamic-import": "^7.0.0", 19 | "@babel/plugin-transform-runtime": "^7.5.5", 20 | "@babel/preset-env": "^7.5.5", 21 | "@babel/runtime": "^7.5.5", 22 | "npm-run-all": "^4.1.5", 23 | "rollup": "^1.19.4", 24 | "rollup-plugin-babel": "^4.3.3", 25 | "rollup-plugin-commonjs": "^9.3.4", 26 | "rollup-plugin-node-resolve": "^4.2.4", 27 | "rollup-plugin-replace": "^2.0.0", 28 | "rollup-plugin-svelte": "^5.0.1", 29 | "rollup-plugin-terser": "^4.0.4", 30 | "sapper": "^0.27.8", 31 | "svelte": "^3.8.1", 32 | "svelte-grid": "^1.9.0", 33 | "svelte-loader": "^2.13.6", 34 | "webpack": "^4.39.2" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import resolve from 'rollup-plugin-node-resolve'; 2 | import replace from 'rollup-plugin-replace'; 3 | import commonjs from 'rollup-plugin-commonjs'; 4 | import svelte from 'rollup-plugin-svelte'; 5 | import babel from 'rollup-plugin-babel'; 6 | import { terser } from 'rollup-plugin-terser'; 7 | import config from 'sapper/config/rollup.js'; 8 | import pkg from './package.json'; 9 | 10 | const mode = process.env.NODE_ENV; 11 | const dev = mode === 'development'; 12 | const legacy = !!process.env.SAPPER_LEGACY_BUILD; 13 | 14 | const onwarn = (warning, onwarn) => (warning.code === 'CIRCULAR_DEPENDENCY' && warning.message.includes('/@sapper/')) || onwarn(warning); 15 | 16 | export default { 17 | client: { 18 | input: config.client.input(), 19 | output: config.client.output(), 20 | plugins: [ 21 | replace({ 22 | 'process.browser': true, 23 | 'process.env.NODE_ENV': JSON.stringify(mode) 24 | }), 25 | svelte({ 26 | dev, 27 | hydratable: true, 28 | emitCss: true 29 | }), 30 | resolve({ 31 | browser: true 32 | }), 33 | commonjs(), 34 | 35 | legacy && babel({ 36 | extensions: ['.js', '.mjs', '.html', '.svelte'], 37 | runtimeHelpers: true, 38 | exclude: ['node_modules/@babel/**'], 39 | presets: [ 40 | ['@babel/preset-env', { 41 | targets: '> 0.25%, not dead' 42 | }] 43 | ], 44 | plugins: [ 45 | '@babel/plugin-syntax-dynamic-import', 46 | ['@babel/plugin-transform-runtime', { 47 | useESModules: true 48 | }] 49 | ] 50 | }), 51 | 52 | !dev && terser({ 53 | module: true 54 | }) 55 | ], 56 | 57 | onwarn, 58 | }, 59 | 60 | server: { 61 | input: config.server.input(), 62 | output: config.server.output(), 63 | plugins: [ 64 | replace({ 65 | 'process.browser': false, 66 | 'process.env.NODE_ENV': JSON.stringify(mode) 67 | }), 68 | svelte({ 69 | generate: 'ssr', 70 | dev 71 | }), 72 | resolve(), 73 | commonjs() 74 | ], 75 | external: Object.keys(pkg.dependencies).concat( 76 | require('module').builtinModules || Object.keys(process.binding('natives')) 77 | ), 78 | 79 | onwarn, 80 | }, 81 | 82 | serviceworker: { 83 | input: config.serviceworker.input(), 84 | output: config.serviceworker.output(), 85 | plugins: [ 86 | resolve(), 87 | replace({ 88 | 'process.browser': true, 89 | 'process.env.NODE_ENV': JSON.stringify(mode) 90 | }), 91 | commonjs(), 92 | !dev && terser() 93 | ], 94 | 95 | onwarn, 96 | } 97 | }; 98 | -------------------------------------------------------------------------------- /src/client.js: -------------------------------------------------------------------------------- 1 | import * as sapper from '@sapper/app'; 2 | 3 | sapper.start({ 4 | target: document.querySelector('#sapper') 5 | }); -------------------------------------------------------------------------------- /src/components/About.svelte: -------------------------------------------------------------------------------- 1 | 33 | 34 |
35 |

Welcome

36 | 47 |
48 |

INTRODUCTION

49 |

This tool was created to create css3 grid layouts. This generates the grid and aims to generate css output. It is also a good place to learn CSS3 grid.

50 |
51 |
52 |

USAGE

53 |

There are no menus, footers or ads in the app, or other disturbing extraneous widgets.

54 |

Everything is controlled using only the context menu. Right-click to toogle the context menu

55 |
56 | 57 |
58 |

TIP

59 |

You can highlight the grid in the context menu by selecting "Highlight grid"

60 | Highlight grid 61 |
62 | 63 |
64 |

EXTERNAL LINKS

65 |

Author — vaheqelyan

66 |

GitHub Repo — layout-master

67 |

Dev.to — Make CSS3 Grid layout in 1 minute

68 |

MDN web docs — CSS Grid Layout

69 |
70 | 71 |
72 | -------------------------------------------------------------------------------- /src/components/CSSOutput.svelte: -------------------------------------------------------------------------------- 1 | 37 | 38 | 39 |
40 |
41 | {#each generate($items,view,$gridTemplateRows,$gridTemplateColumns,$rowHeight,$columns,$gap,$container) as line, i} 42 |
{@html line}
43 | {/each} 44 |
45 |
46 | {#each new Array(result.length) as line, i} 47 |
{i}
48 | {/each} 49 |
50 |
51 | 52 |
53 | grid-template-columns 54 | 58 | 62 |
63 | 64 |
65 | grid-template-rows 66 | 70 | 74 | 78 |
79 | 80 | -------------------------------------------------------------------------------- /src/components/ContextMenu/index.svelte: -------------------------------------------------------------------------------- 1 | 66 | 67 | 68 | {#if visible} 69 | 78 | {/if} 79 | 80 | -------------------------------------------------------------------------------- /src/components/ContextMenu/kind.js: -------------------------------------------------------------------------------- 1 | export const CONTEXT_MENU_KIND = { 2 | ADD:'ADD_ITEM', 3 | REMOVE:"REMOVE_ITEM", 4 | SETTINGS:'TOOGLE_SETTINGS', 5 | CLOSE_SETTINGS: 'CLOSE_SETTINGS', 6 | MAKE:'GENERATE_CSS_CODE', 7 | DIVIDE:'DIVIDER', 8 | ABOUT:'ABOUT', 9 | HIGHLIGHT:'HIGHLIGHT_GRID' 10 | } -------------------------------------------------------------------------------- /src/components/HighlightGrid/HighlightGrid.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 | {#each new Array(columns*rowsCount) as block,i} 10 |
15 | {/each} 16 | 17 | -------------------------------------------------------------------------------- /src/components/HighlightGrid/index.svelte: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/components/Modal.svelte: -------------------------------------------------------------------------------- 1 | 27 | 28 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/components/ModalCSSDynamicImport.svelte: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/components/ModalCSSOutput.svelte: -------------------------------------------------------------------------------- 1 | 41 | 42 |
43 |
44 |

CSS output

45 | {$columns} column and {rows} row 46 |
47 | 48 |
49 |
50 |
grid-template-areas
51 |
grid-area
52 |
other choice
53 |
54 | 55 |
56 | 57 |
58 | 59 | -------------------------------------------------------------------------------- /src/components/Settings.svelte: -------------------------------------------------------------------------------- 1 | 84 | 85 | 179 | 180 | -------------------------------------------------------------------------------- /src/routes/index.svelte: -------------------------------------------------------------------------------- 1 | 46 | 47 | 297 | 298 | 299 | 300 | {#if modals.about} 301 | 302 | 303 | 304 | {/if} 305 | 306 | {#if modals.css} 307 | 308 | 309 | 310 | {/if} 311 | 312 | 313 | 314 | {#if toogleSettings} 315 | 316 | {/if} 317 | 318 | {#if highlightGrid} 319 | 320 | {/if} 321 | 322 | 323 |
324 | Template name 325 | 326 | Class name 327 | 328 |
329 |
330 | 331 | -------------------------------------------------------------------------------- /src/server.js: -------------------------------------------------------------------------------- 1 | import sirv from 'sirv'; 2 | import polka from 'polka'; 3 | import compression from 'compression'; 4 | import * as sapper from '@sapper/server'; 5 | 6 | const { PORT, NODE_ENV } = process.env; 7 | const dev = NODE_ENV === 'development'; 8 | 9 | polka() 10 | .use( 11 | compression({ threshold: 0 }), 12 | sirv('static', { dev }), 13 | sapper.middleware() 14 | ) 15 | .listen(PORT, err => { 16 | if (err) console.log('error', err); 17 | }); -------------------------------------------------------------------------------- /src/service-worker.js: -------------------------------------------------------------------------------- 1 | import { timestamp, files, shell, routes } from '@sapper/service-worker'; 2 | 3 | const ASSETS = `cache${timestamp}`; 4 | 5 | // `shell` is an array of all the files generated by the bundler, 6 | // `files` is an array of everything in the `static` directory 7 | const to_cache = shell.concat(files); 8 | const cached = new Set(to_cache); 9 | 10 | self.addEventListener('install', event => { 11 | event.waitUntil( 12 | caches 13 | .open(ASSETS) 14 | .then(cache => cache.addAll(to_cache)) 15 | .then(() => { 16 | self.skipWaiting(); 17 | }) 18 | ); 19 | }); 20 | 21 | self.addEventListener('activate', event => { 22 | event.waitUntil( 23 | caches.keys().then(async keys => { 24 | // delete old caches 25 | for (const key of keys) { 26 | if (key !== ASSETS) await caches.delete(key); 27 | } 28 | 29 | self.clients.claim(); 30 | }) 31 | ); 32 | }); 33 | 34 | self.addEventListener('fetch', event => { 35 | if (event.request.method !== 'GET' || event.request.headers.has('range')) return; 36 | 37 | const url = new URL(event.request.url); 38 | 39 | // don't try to handle e.g. data: URIs 40 | if (!url.protocol.startsWith('http')) return; 41 | 42 | // ignore dev server requests 43 | if (url.hostname === self.location.hostname && url.port !== self.location.port) return; 44 | 45 | // always serve static files and bundler-generated assets from cache 46 | if (url.host === self.location.host && cached.has(url.pathname)) { 47 | event.respondWith(caches.match(event.request)); 48 | return; 49 | } 50 | 51 | // for pages, you might want to serve a shell `service-worker-index.html` file, 52 | // which Sapper has generated for you. It's not right for every 53 | // app, but if it's right for yours then uncomment this section 54 | /* 55 | if (url.origin === self.origin && routes.find(route => route.pattern.test(url.pathname))) { 56 | event.respondWith(caches.match('/service-worker-index.html')); 57 | return; 58 | } 59 | */ 60 | 61 | if (event.request.cache === 'only-if-cached') return; 62 | 63 | // for everything else, try the network first, falling back to 64 | // cache if the user is offline. (If the pages never change, you 65 | // might prefer a cache-first approach to a network-first one.) 66 | event.respondWith( 67 | caches 68 | .open(`offline${timestamp}`) 69 | .then(async cache => { 70 | try { 71 | const response = await fetch(event.request); 72 | cache.put(event.request, response.clone()); 73 | return response; 74 | } catch(err) { 75 | const response = await cache.match(event.request); 76 | if (response) return response; 77 | 78 | throw err; 79 | } 80 | }) 81 | ); 82 | }); 83 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import { writable } from 'svelte/store'; 2 | 3 | let settings = { 4 | columns:3, 5 | rowHeight:100, 6 | gap:10, 7 | gridTemplateColumns:'auto', 8 | gridTemplateRows:undefined, 9 | container:true 10 | } 11 | 12 | let getSettingsFromStorage; 13 | 14 | if(typeof window !== 'undefined') { 15 | if(!localStorage.getItem('settings')) { 16 | localStorage.setItem('settings',JSON.stringify(settings)) 17 | } else { 18 | settings = JSON.parse(localStorage.getItem('settings')) 19 | } 20 | } 21 | 22 | export const columns = writable(settings.columns); 23 | export const rowHeight = writable(settings.rowHeight); 24 | export const gap = writable(settings.gap); 25 | export const items = writable([]) 26 | export const gridTemplateColumns = writable(settings.gridTemplateColumns) 27 | export const gridTemplateRows = writable(settings.gridTemplateRows) 28 | export const container = writable(settings.container) -------------------------------------------------------------------------------- /src/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | %sapper.base% 9 | 10 | 11 | 12 | 13 | LM ▦ — Generate CSS3 grid layout 14 | 15 | 16 | 17 | 18 | 19 | 22 | %sapper.styles% 23 | 24 | 26 | %sapper.head% 27 | 28 | 29 | 31 |
%sapper.html%
32 | 33 | 36 | %sapper.scripts% 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/utils/index.js: -------------------------------------------------------------------------------- 1 | export const id = () => 2 | "_" + 3 | Math.random() 4 | .toString(36) 5 | .substr(2, 9); 6 | 7 | export const debounce = (fn, ms = 0) => { 8 | let timeoutId; 9 | return function(...args) { 10 | clearTimeout(timeoutId); 11 | timeoutId = setTimeout(() => fn.apply(this, args), ms); 12 | }; 13 | }; 14 | 15 | // export const makeMatrix = (rows, cols) => Array.from(Array(rows), () => new Array(cols)); // make 2d array 16 | export const initialize2DArray = (w, h, val = null) => Array.from({ length: h }).map(() => Array.from({ length: w }).fill(val)); 17 | 18 | export function makeMatrixFromItems(items, _row, _col) { 19 | let matrix = initialize2DArray(_col, _row, "."); 20 | for (var i = 0; i < items.length; i++) { 21 | const value = items[i]; 22 | const { 23 | x, 24 | y, 25 | w, 26 | h, 27 | responsive: { valueW } 28 | } = value; 29 | 30 | for (var j = y; j < y + h; j++) { 31 | const row = matrix[j]; 32 | for (var k = x; k < x + (w - valueW); k++) { 33 | row[k] = value.templateName; 34 | } 35 | } 36 | } 37 | return matrix; 38 | } 39 | 40 | function tag(html) { 41 | return !this.noHtml ? html : ""; 42 | } 43 | 44 | export const generateCSSOutput = (items, view, settingsRow, settingsColumn, rowHeight, columns, gap, container, noHtml = false) => { 45 | let rowsCount = Math.max(...items.map(val => val.y + val.h), 1); 46 | 47 | let vals = { auto: "auto", "1fr": "1fr" }; 48 | 49 | var fn = tag.bind({ noHtml }); 50 | 51 | var gridGap = `${fn('')}grid-gap${fn("")}: ${fn('')}${gap}px${fn("")};`; 52 | 53 | var gridTemplateRowsSettings = `${fn('')}${`${settingsRow ? vals[settingsRow] : `${rowHeight}px`} `.repeat(rowsCount).trimRight()}${fn("")}`; 54 | 55 | var gridTemplateColumnsSettings = `${fn('')}${`${vals[settingsColumn]} `.repeat(columns).trimRight()}${fn("")}`; 56 | 57 | switch (view) { 58 | case "other": 59 | var res = items.map(value => { 60 | var { x, y, w, h, templateName, className } = value; 61 | x = x === 0 ? 1 : x + 1; 62 | y = y === 0 ? 1 : y + 1; 63 | return `.${fn('')}${className}${fn("")} { 64 | ${fn('')}grid-row-start${fn("")}: ${fn('')}${y}${fn("")}; 65 | ${fn('')}grid-row-end${fn("")}: ${fn('')}${y + h}${fn("")}; 66 | ${fn('')}grid-column-start${fn("")}: ${fn('')}${x}${fn("")}; 67 | ${fn('')}grid-column-end${fn("")}: ${fn('')}${x + w}${fn("")}; 68 | }`; 69 | }); 70 | if (container) { 71 | res = [ 72 | ...[ 73 | `${fn('')}.container${fn("")} { 74 | ${fn('')}grid-template-rows${fn("")}: ${gridTemplateRowsSettings}; 75 | ${fn('')}grid-template-columns${fn("")}: ${gridTemplateColumnsSettings}; 76 | ${gridGap} 77 | }\n` 78 | ], 79 | ...res 80 | ]; 81 | } 82 | if (noHtml) { 83 | return res.join("\n"); 84 | } 85 | return res.join("\n").split("\n"); 86 | break; 87 | 88 | case "grid-area": 89 | var res = items.map(value => { 90 | var { x, y, w, h, templateName,className } = value; 91 | x = x === 0 ? 1 : x + 1; 92 | y = y === 0 ? 1 : y + 1; 93 | return `.${fn('')}${className}${fn("")} { 94 | ${fn('')}grid-area${fn("")}: ${fn('')}${y}${fn("")} / ${fn('')}${x}${fn("")} / ${fn('')}${y + h}${fn("")} / ${fn('')}${x + w}${fn("")}; 95 | }`; 96 | }); 97 | 98 | if (container) { 99 | res = [ 100 | ...[ 101 | `${fn('')}.container${fn("")} { 102 | ${fn('')}grid-template-rows${fn("")}: ${gridTemplateRowsSettings}; 103 | ${fn('')}grid-template-columns${fn("")}: ${gridTemplateColumnsSettings}; 104 | ${gridGap} 105 | }\n` 106 | ], 107 | ...res 108 | ]; 109 | } 110 | 111 | //${'1fr '.repeat(columns).trimRight()}; 112 | if (noHtml) { 113 | return res.join("\n"); 114 | } 115 | return res.join("\n").split("\n"); 116 | 117 | break; 118 | 119 | case "grid-template-areas": 120 | const m = makeMatrixFromItems(items, Math.max(...items.map(val => val.y + val.h), 1), columns); 121 | let template = m 122 | .join("\n") 123 | .split(",") 124 | .join(" ") 125 | .split("\n") 126 | .map((val, i) => `${" ".repeat(i === 0 ? 0 : 17)}${fn('')}"${val}${fn("")}"`) 127 | .join("\n"); 128 | var res = items.map((value, index) => { 129 | const {templateName,className} = value; 130 | return `.${fn('')}${className}${fn("")} { 131 | ${fn('')}grid-area${fn("")}: ${templateName}; 132 | }`; 133 | }); 134 | 135 | res = [ 136 | ...[ 137 | `${fn('')}.container${fn("")} { 138 | ${fn('')}grid-template-areas${fn("")}: ${template}; 139 | ${fn('')}grid-template-rows${fn("")}: ${gridTemplateRowsSettings}; 140 | ${fn('')}grid-template-columns${fn("")}: ${gridTemplateColumnsSettings}; 141 | ${gridGap} 142 | }\n` 143 | ], 144 | ...res 145 | ]; 146 | 147 | if (noHtml) { 148 | return res.join("\n"); 149 | } 150 | return res.join("\n").split("\n"); 151 | 152 | break; 153 | 154 | default: 155 | return []; 156 | break; 157 | } 158 | }; 159 | -------------------------------------------------------------------------------- /static/global.css: -------------------------------------------------------------------------------- 1 | * { 2 | user-select: none; 3 | } 4 | 5 | .string { 6 | color: #a67f59; 7 | } 8 | .num { 9 | color: rgb(0, 0, 205); 10 | } 11 | 12 | .selector { 13 | color: rgb(49, 132, 149); 14 | } 15 | .prop { 16 | color: #c80000; 17 | } 18 | 19 | img { 20 | margin: 10px 0; 21 | -webkit-user-drag: none; 22 | -khtml-user-drag: none; 23 | -moz-user-drag: none; 24 | -o-user-drag: none; 25 | user-drag: none; 26 | } 27 | 28 | body { 29 | margin: 0; 30 | font-family: Roboto, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, 31 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 32 | font-size: 14px; 33 | line-height: 1.5; 34 | color: #333; 35 | } 36 | 37 | h1, 38 | h2, 39 | h3, 40 | h4, 41 | h5, 42 | h6 { 43 | margin: 0 0 0.5em 0; 44 | font-weight: 400; 45 | line-height: 1.2; 46 | } 47 | 48 | h1 { 49 | font-size: 2em; 50 | } 51 | 52 | a { 53 | color: inherit; 54 | } 55 | 56 | code { 57 | font-family: menlo, inconsolata, monospace; 58 | font-size: calc(1em - 2px); 59 | color: #555; 60 | background-color: #f0f0f0; 61 | padding: 0.2em 0.4em; 62 | border-radius: 2px; 63 | } 64 | 65 | @media (min-width: 400px) { 66 | body { 67 | font-size: 16px; 68 | } 69 | } 70 | 71 | button { 72 | padding-bottom: 8px; 73 | padding-left: 12px; 74 | padding-right: 12px; 75 | padding-top: 8px; 76 | cursor: pointer; 77 | 78 | text-transform: capitalize; 79 | font-size: smaller; 80 | font-weight: bold; 81 | color: #1a73e8; 82 | border: 1px solid #cccccc; 83 | border-radius: 4px; 84 | background: white; 85 | outline-color: #b5c9eb; 86 | } 87 | 88 | #sapper { 89 | min-height: 100vh; 90 | background: linear-gradient(-90deg, rgba(0, 0, 0, 0.02) 1px, transparent 0), 91 | linear-gradient(rgba(0, 0, 0, 0.02) 1px, transparent 0), 92 | linear-gradient(-90deg, rgba(0, 0, 0, 0.03) 1px, transparent 0), 93 | linear-gradient(rgba(0, 0, 0, 0.03) 1px, transparent 0), 94 | linear-gradient(transparent 4px, #f5f5f5 0, #f5f5f5 97px, transparent 0), 95 | linear-gradient(-90deg, #e5e5e5 1px, transparent 0), 96 | linear-gradient( 97 | -90deg, 98 | transparent 4px, 99 | #f5f5f5 0, 100 | #f5f5f5 97px, 101 | transparent 0 102 | ), 103 | linear-gradient(#e5e5e5 1px, transparent 0), #f5f5f5; 104 | background-size: 10px 10px, 10px 10px, 100px 100px, 100px 100px, 100px 100px, 105 | 100px 100px, 100px 100px, 100px 100px; 106 | } 107 | -------------------------------------------------------------------------------- /static/logo-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vaheqelyan/layout-master/e4eabee3d0d4e47a7be6a074b65456949a849f8c/static/logo-192.png -------------------------------------------------------------------------------- /static/logo-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vaheqelyan/layout-master/e4eabee3d0d4e47a7be6a074b65456949a849f8c/static/logo-512.png -------------------------------------------------------------------------------- /static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vaheqelyan/layout-master/e4eabee3d0d4e47a7be6a074b65456949a849f8c/static/logo.png -------------------------------------------------------------------------------- /static/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "background_color": "#ffffff", 3 | "theme_color": "#232331", 4 | "name": "Layout-master", 5 | "short_name": "LM", 6 | "display": "standalone", 7 | "start_url": "/", 8 | "icons": [ 9 | { 10 | "src": "logo-192.png", 11 | "sizes": "192x192", 12 | "type": "image/png" 13 | }, 14 | { 15 | "src": "logo-512.png", 16 | "sizes": "512x512", 17 | "type": "image/png" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const config = require('sapper/config/webpack.js'); 3 | const pkg = require('./package.json'); 4 | 5 | const mode = process.env.NODE_ENV; 6 | const dev = mode === 'development'; 7 | 8 | const extensions = ['.mjs', '.js', '.json', '.svelte', '.html']; 9 | const mainFields = ['svelte', 'module', 'browser', 'main']; 10 | 11 | module.exports = { 12 | client: { 13 | entry: config.client.entry(), 14 | output: config.client.output(), 15 | resolve: { extensions, mainFields }, 16 | module: { 17 | rules: [ 18 | { 19 | test: /\.(svelte|html)$/, 20 | use: { 21 | loader: 'svelte-loader', 22 | options: { 23 | dev, 24 | hydratable: true, 25 | hotReload: false // pending https://github.com/sveltejs/svelte/issues/2377 26 | } 27 | } 28 | } 29 | ] 30 | }, 31 | mode, 32 | plugins: [ 33 | // pending https://github.com/sveltejs/svelte/issues/2377 34 | // dev && new webpack.HotModuleReplacementPlugin(), 35 | new webpack.DefinePlugin({ 36 | 'process.browser': true, 37 | 'process.env.NODE_ENV': JSON.stringify(mode) 38 | }), 39 | ].filter(Boolean), 40 | devtool: dev && 'inline-source-map' 41 | }, 42 | 43 | server: { 44 | entry: config.server.entry(), 45 | output: config.server.output(), 46 | target: 'node', 47 | resolve: { extensions, mainFields }, 48 | externals: Object.keys(pkg.dependencies).concat('encoding'), 49 | module: { 50 | rules: [ 51 | { 52 | test: /\.(svelte|html)$/, 53 | use: { 54 | loader: 'svelte-loader', 55 | options: { 56 | css: false, 57 | generate: 'ssr', 58 | dev 59 | } 60 | } 61 | } 62 | ] 63 | }, 64 | mode: process.env.NODE_ENV, 65 | performance: { 66 | hints: false // it doesn't matter if server.js is large 67 | } 68 | }, 69 | 70 | serviceworker: { 71 | entry: config.serviceworker.entry(), 72 | output: config.serviceworker.output(), 73 | mode: process.env.NODE_ENV 74 | } 75 | }; 76 | --------------------------------------------------------------------------------