├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .prettierignore ├── .prettierrc ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── rollup.config.js ├── src ├── MoveResize │ └── index.svelte ├── index.svelte └── utils │ ├── container.js │ ├── helper.js │ ├── item.js │ ├── matrix.js │ └── other.js └── www ├── .gitignore ├── .nowignore ├── now.json ├── package-lock.json ├── package.json ├── rollup.config.js ├── src ├── client.js ├── components │ ├── Footer.svelte │ ├── Nav.svelte │ └── Ribbon.svelte ├── routes │ ├── _layout.svelte │ ├── examples │ │ ├── add_remove.svx │ │ ├── autoscroll.svx │ │ ├── basic.svx │ │ ├── custom-dragger.svx │ │ ├── custom-resizer.svx │ │ ├── events.svx │ │ ├── fast-start.svx │ │ ├── fill-space.svx │ │ ├── fixed.svx │ │ ├── gap.svx │ │ ├── github.js │ │ ├── index.svx │ │ ├── local-storage.svx │ │ ├── min_max.svx │ │ ├── responsive-local-storage.svx │ │ └── responsive.svx │ ├── features.svelte │ ├── index.svelte │ └── usage.svx ├── server.js ├── service-worker.js └── template.html └── static ├── favicon.png ├── global.css ├── logo-192.png ├── logo-512.png └── manifest.json /.eslintignore: -------------------------------------------------------------------------------- 1 | public/ 2 | *.svelte 3 | index.js 4 | index.mjs 5 | www/ -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "env": { 3 | "browser": true, 4 | "es6": true, 5 | "node": true 6 | }, 7 | "extends": "eslint:recommended", 8 | "globals": { 9 | "Atomics": "readonly", 10 | "SharedArrayBuffer": "readonly" 11 | }, 12 | "parserOptions": { 13 | "ecmaVersion": 2019, 14 | "sourceType": "module" 15 | }, 16 | "rules": { 17 | }, 18 | }; -------------------------------------------------------------------------------- /.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 | build/ 64 | less.exe.stackdump 65 | 66 | # www 67 | www/__sapper__/ 68 | www/src/components/svelte-grid/ 69 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | www/src/routes/usage.svelte -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": false, 3 | "printWidth": 300, 4 | "tabWidth": 2, 5 | "semi": true, 6 | "trailingComma": "all", 7 | "singleQuote": false 8 | } 9 | -------------------------------------------------------------------------------- /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 | # svelte-grid 2 | 3 |

4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |

19 | 20 | ![](https://res.cloudinary.com/dmtrk3yns/video/upload/q_auto/v1565455366/ice_video_20190810-202954_fuquxt.gif) 21 | 22 | ## About 23 | 24 | - 100% Svelte (or vanillajs) - no jQuery, no 3rd party dependencies 25 | - Compatible with Sapper (SSR Svelte) 26 | - Draggable widgets 27 | - Resizable widgets 28 | - Static widgets 29 | - Layout can be serialized and restored 30 | - Responsive breakpoints 31 | - Limit the minimum and maximum width / height when resizing 32 | - Provide helper functions 33 | - Custom dragging 34 | - Grid gap 35 | - Soft autoscroll 36 | 37 | ## Installation 38 | 39 | **via NPM** 40 | 41 | ```code 42 | npm i svelte-grid --save-dev 43 | ``` 44 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "svelte-grid", 3 | "version": "5.1.2", 4 | "description": "A responsive, draggable and resizable grid layout, for Svelte.", 5 | "svelte": "src/index.svelte", 6 | "module": "build/index.mjs", 7 | "main": "build/index.js", 8 | "scripts": { 9 | "test": "echo \"Error: no test specified\" && exit 1", 10 | "lint": "eslint .", 11 | "pretty": "prettier --config .prettierrc --write --svelte-sort-order styles-markup-scripts \"rollup.config.js\" \"package.json\" \"src/**/*.js\" \"www/src/**/**/*.svelte\" \"*.md\" \"src/*.svelte\" \"src/**/*.svelte\" ", 12 | "build": "node_modules/.bin/rollup -c", 13 | "go": "npm-run-all pretty build" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/vaheqelyan/svelte-grid.git" 18 | }, 19 | "keywords": [ 20 | "svelte", 21 | "grid", 22 | "drag", 23 | "draggable", 24 | "resize", 25 | "resizable", 26 | "fluid", 27 | "responsive" 28 | ], 29 | "author": "Vahe Araqelyan ", 30 | "license": "MIT", 31 | "bugs": { 32 | "url": "https://github.com/vaheqelyan/svelte-grid/issues" 33 | }, 34 | "homepage": "https://github.com/vaheqelyan/svelte-grid#readme", 35 | "devDependencies": { 36 | "@rollup/plugin-commonjs": "^17.0.0", 37 | "eslint": "^7.13.0", 38 | "npm-run-all": "^4.1.5", 39 | "prettier": "^2.2.0", 40 | "prettier-plugin-svelte": "^1.4.1", 41 | "rollup": "^2.33.3", 42 | "rollup-plugin-node-resolve": "^5.2.0", 43 | "rollup-plugin-svelte": "^6.1.1", 44 | "svelte": "^3.30.0" 45 | }, 46 | "files": [ 47 | "src", 48 | "build" 49 | ] 50 | } 51 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import svelte from "rollup-plugin-svelte"; 2 | import resolve from "rollup-plugin-node-resolve"; 3 | import commonjs from "@rollup/plugin-commonjs"; 4 | import pkg from "./package.json"; 5 | 6 | const name = pkg.name 7 | .replace(/^(@\S+\/)?(svelte-)?(\S+)/, "$3") 8 | .replace(/^\w/, (m) => m.toUpperCase()) 9 | .replace(/-\w/g, (m) => m[1].toUpperCase()); 10 | 11 | export default [ 12 | { 13 | input: "src/index.svelte", 14 | output: [ 15 | { file: pkg.module, format: "es" }, 16 | { file: pkg.main, format: "umd", name }, 17 | ], 18 | plugins: [svelte(), resolve(), commonjs()], 19 | }, 20 | { 21 | input: "./src/utils/helper.js", 22 | output: [ 23 | { file: "build/helper/index.mjs", format: "es" }, 24 | { file: "build/helper/index.js", format: "umd", name: "gridHelper" }, 25 | ], 26 | }, 27 | ]; 28 | -------------------------------------------------------------------------------- /src/MoveResize/index.svelte: -------------------------------------------------------------------------------- 1 | 59 | 60 |
67 | 68 | {#if resizable && !item.customResizer} 69 |
70 | {/if} 71 |
72 | 73 | {#if active || trans} 74 |
75 | {/if} 76 | 77 | 334 | -------------------------------------------------------------------------------- /src/index.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 |
9 | {#if xPerPx || !fastStart} 10 | {#each items as item, i (item.id)} 11 | 34 | {#if item[getComputedCols]} 35 | 36 | {/if} 37 | 38 | {/each} 39 | {/if} 40 |
41 | 42 | 166 | -------------------------------------------------------------------------------- /src/utils/container.js: -------------------------------------------------------------------------------- 1 | import { getRowsCount } from "./other.js"; 2 | 3 | export function getContainerHeight(items, yPerPx, cols) { 4 | return getRowsCount(items, cols) * yPerPx; 5 | } 6 | -------------------------------------------------------------------------------- /src/utils/helper.js: -------------------------------------------------------------------------------- 1 | import { makeMatrixFromItems } from "../utils/matrix.js"; 2 | import { findFreeSpaceForItem, normalize, adjust } from "../utils/item.js"; 3 | import { getRowsCount } from "./other.js"; 4 | 5 | function makeItem(item) { 6 | const { min = { w: 1, h: 1 }, max } = item; 7 | return { 8 | fixed: false, 9 | resizable: !item.fixed, 10 | draggable: !item.fixed, 11 | customDragger: false, 12 | customResizer: false, 13 | min: { 14 | w: Math.max(1, min.w), 15 | h: Math.max(1, min.h), 16 | }, 17 | max: { ...max }, 18 | ...item, 19 | }; 20 | } 21 | 22 | const gridHelp = { 23 | normalize(items, col) { 24 | const rows = getRowsCount(items, col); 25 | return normalize(items, col, rows); 26 | }, 27 | 28 | adjust(items, col) { 29 | return adjust(items, col); 30 | }, 31 | 32 | item(obj) { 33 | return makeItem(obj); 34 | }, 35 | 36 | findSpace(item, items, cols) { 37 | let matrix = makeMatrixFromItems(items, getRowsCount(items, cols), cols); 38 | 39 | let position = findFreeSpaceForItem(matrix, item[cols]); 40 | return position; 41 | }, 42 | }; 43 | 44 | export default gridHelp; 45 | -------------------------------------------------------------------------------- /src/utils/item.js: -------------------------------------------------------------------------------- 1 | import { makeMatrix, makeMatrixFromItemsIgnore, findCloseBlocks, findItemsById, makeMatrixFromItems } from "./matrix.js"; 2 | import { getRowsCount } from "./other.js"; 3 | 4 | export function getItemById(id, items) { 5 | return items.find((value) => value.id === id); 6 | } 7 | 8 | export function findFreeSpaceForItem(matrix, item) { 9 | const cols = matrix[0].length; 10 | const w = Math.min(cols, item.w); 11 | let xNtime = cols - w; 12 | let getMatrixRows = matrix.length; 13 | 14 | for (var i = 0; i < getMatrixRows; i++) { 15 | const row = matrix[i]; 16 | for (var j = 0; j < xNtime + 1; j++) { 17 | const sliceA = row.slice(j, j + w); 18 | const empty = sliceA.every((val) => val === undefined); 19 | if (empty) { 20 | const isEmpty = matrix.slice(i, i + item.h).every((a) => a.slice(j, j + w).every((n) => n === undefined)); 21 | 22 | if (isEmpty) { 23 | return { y: i, x: j }; 24 | } 25 | } 26 | } 27 | } 28 | 29 | return { 30 | y: getMatrixRows, 31 | x: 0, 32 | }; 33 | } 34 | 35 | const getItem = (item, col) => { 36 | return { ...item[col], id: item.id }; 37 | }; 38 | 39 | const updateItem = (elements, active, position, col) => { 40 | return elements.map((value) => { 41 | if (value.id === active.id) { 42 | return { ...value, [col]: { ...value[col], ...position } }; 43 | } 44 | return value; 45 | }); 46 | }; 47 | 48 | export function moveItemsAroundItem(active, items, cols, original) { 49 | // Get current item from the breakpoint 50 | const activeItem = getItem(active, cols); 51 | const ids = items.map((value) => value.id).filter((value) => value !== activeItem.id); 52 | 53 | const els = items.filter((value) => value.id !== activeItem.id); 54 | 55 | // Update items 56 | let newItems = updateItem(items, active, activeItem, cols); 57 | 58 | let matrix = makeMatrixFromItemsIgnore(newItems, ids, getRowsCount(newItems, cols), cols); 59 | let tempItems = newItems; 60 | 61 | // Exclude resolved elements ids in array 62 | let exclude = []; 63 | 64 | els.forEach((item) => { 65 | // Find position for element 66 | let position = findFreeSpaceForItem(matrix, item[cols]); 67 | // Exclude item 68 | exclude.push(item.id); 69 | 70 | tempItems = updateItem(tempItems, item, position, cols); 71 | 72 | // Recreate ids of elements 73 | let getIgnoreItems = ids.filter((value) => exclude.indexOf(value) === -1); 74 | 75 | // Update matrix for next iteration 76 | matrix = makeMatrixFromItemsIgnore(tempItems, getIgnoreItems, getRowsCount(tempItems, cols), cols); 77 | }); 78 | 79 | // Return result 80 | return tempItems; 81 | } 82 | 83 | export function moveItem(active, items, cols, original) { 84 | // Get current item from the breakpoint 85 | const item = getItem(active, cols); 86 | 87 | // Create matrix from the items expect the active 88 | let matrix = makeMatrixFromItemsIgnore(items, [item.id], getRowsCount(items, cols), cols); 89 | // Getting the ids of items under active Array 90 | const closeBlocks = findCloseBlocks(items, matrix, item); 91 | // Getting the objects of items under active Array 92 | let closeObj = findItemsById(closeBlocks, items); 93 | // Getting whenever of these items is fixed 94 | const fixed = closeObj.find((value) => value[cols].fixed); 95 | 96 | // If found fixed, reset the active to its original position 97 | if (fixed) return items; 98 | 99 | // Update items 100 | items = updateItem(items, active, item, cols); 101 | 102 | // Create matrix of items expect close elements 103 | matrix = makeMatrixFromItemsIgnore(items, closeBlocks, getRowsCount(items, cols), cols); 104 | 105 | // Create temp vars 106 | let tempItems = items; 107 | let tempCloseBlocks = closeBlocks; 108 | 109 | // Exclude resolved elements ids in array 110 | let exclude = []; 111 | 112 | // Iterate over close elements under active item 113 | closeObj.forEach((item) => { 114 | // Find position for element 115 | let position = findFreeSpaceForItem(matrix, item[cols]); 116 | // Exclude item 117 | exclude.push(item.id); 118 | 119 | // Assign the position to the element in the column 120 | tempItems = updateItem(tempItems, item, position, cols); 121 | 122 | // Recreate ids of elements 123 | let getIgnoreItems = tempCloseBlocks.filter((value) => exclude.indexOf(value) === -1); 124 | 125 | // Update matrix for next iteration 126 | matrix = makeMatrixFromItemsIgnore(tempItems, getIgnoreItems, getRowsCount(tempItems, cols), cols); 127 | }); 128 | 129 | // Return result 130 | return tempItems; 131 | } 132 | 133 | // Helper function 134 | export function normalize(items, col) { 135 | let result = items.slice(); 136 | 137 | result.forEach((value) => { 138 | const getItem = value[col]; 139 | if (!getItem.static) { 140 | result = moveItem(getItem, result, col, { ...getItem }); 141 | } 142 | }); 143 | 144 | return result; 145 | } 146 | 147 | // Helper function 148 | export function adjust(items, col) { 149 | let matrix = makeMatrix(getRowsCount(items, col), col); 150 | 151 | const order = items.toSorted((a, b) => { 152 | const aItem = a[col]; 153 | const bItem = b[col]; 154 | 155 | return aItem.x - bItem.x || aItem.y - bItem.y; 156 | }); 157 | 158 | return order.reduce((acc, item) => { 159 | let position = findFreeSpaceForItem(matrix, item[col]); 160 | 161 | acc.push({ 162 | ...item, 163 | [col]: { 164 | ...item[col], 165 | ...position, 166 | }, 167 | }); 168 | 169 | matrix = makeMatrixFromItems(acc, getRowsCount(acc, col), col); 170 | 171 | return acc; 172 | }, []); 173 | } 174 | 175 | export function getUndefinedItems(items, col, breakpoints) { 176 | return items 177 | .map((value) => { 178 | if (!value[col]) { 179 | return value.id; 180 | } 181 | }) 182 | .filter(Boolean); 183 | } 184 | 185 | export function getClosestColumn(items, item, col, breakpoints) { 186 | return breakpoints 187 | .map(([_, column]) => item[column] && column) 188 | .filter(Boolean) 189 | .reduce(function (acc, value) { 190 | const isLower = Math.abs(value - col) < Math.abs(acc - col); 191 | 192 | return isLower ? value : acc; 193 | }); 194 | } 195 | 196 | export function specifyUndefinedColumns(items, col, breakpoints) { 197 | let matrix = makeMatrixFromItems(items, getRowsCount(items, col), col); 198 | 199 | const getUndefinedElements = getUndefinedItems(items, col, breakpoints); 200 | 201 | let newItems = [...items]; 202 | 203 | getUndefinedElements.forEach((elementId) => { 204 | const getElement = items.find((item) => item.id === elementId); 205 | 206 | const closestColumn = getClosestColumn(items, getElement, col, breakpoints); 207 | 208 | const position = findFreeSpaceForItem(matrix, getElement[closestColumn]); 209 | 210 | const newItem = { 211 | ...getElement, 212 | [col]: { 213 | ...getElement[closestColumn], 214 | ...position, 215 | }, 216 | }; 217 | 218 | newItems = newItems.map((value) => (value.id === elementId ? newItem : value)); 219 | 220 | matrix = makeMatrixFromItems(newItems, getRowsCount(newItems, col), col); 221 | }); 222 | return newItems; 223 | } 224 | -------------------------------------------------------------------------------- /src/utils/matrix.js: -------------------------------------------------------------------------------- 1 | export const makeMatrix = (rows, cols) => Array.from(Array(rows), () => new Array(cols)); // make 2d array 2 | 3 | export function makeMatrixFromItems(items, _row, _col) { 4 | let matrix = makeMatrix(_row, _col); 5 | 6 | for (var i = 0; i < items.length; i++) { 7 | const value = items[i][_col]; 8 | if (value) { 9 | const { x, y, h } = value; 10 | const id = items[i].id; 11 | const w = Math.min(_col, value.w); 12 | 13 | for (var j = y; j < y + h; j++) { 14 | const row = matrix[j]; 15 | for (var k = x; k < x + w; k++) { 16 | row[k] = { ...value, id }; 17 | } 18 | } 19 | } 20 | } 21 | return matrix; 22 | } 23 | 24 | export function findCloseBlocks(items, matrix, curObject) { 25 | const { h, x, y } = curObject; 26 | 27 | const w = Math.min(matrix[0].length, curObject.w); 28 | const tempR = matrix.slice(y, y + h); 29 | 30 | let result = []; 31 | for (var i = 0; i < tempR.length; i++) { 32 | let tempA = tempR[i].slice(x, x + w); 33 | result = [...result, ...tempA.map((val) => val.id && val.id !== curObject.id && val.id).filter(Boolean)]; 34 | } 35 | 36 | return [...new Set(result)]; 37 | } 38 | 39 | export function makeMatrixFromItemsIgnore(items, ignoreList, _row, _col) { 40 | let matrix = makeMatrix(_row, _col); 41 | for (var i = 0; i < items.length; i++) { 42 | const value = items[i][_col]; 43 | const id = items[i].id; 44 | const { x, y, h } = value; 45 | const w = Math.min(_col, value.w); 46 | 47 | if (ignoreList.indexOf(id) === -1) { 48 | for (var j = y; j < y + h; j++) { 49 | const row = matrix[j]; 50 | if (row) { 51 | for (var k = x; k < x + w; k++) { 52 | row[k] = { ...value, id }; 53 | } 54 | } 55 | } 56 | } 57 | } 58 | return matrix; 59 | } 60 | 61 | export function findItemsById(closeBlocks, items) { 62 | return items.filter((value) => closeBlocks.indexOf(value.id) !== -1); 63 | } 64 | -------------------------------------------------------------------------------- /src/utils/other.js: -------------------------------------------------------------------------------- 1 | export function throttle(func, timeFrame) { 2 | let lastTime = 0; 3 | return function (...args) { 4 | let now = new Date(); 5 | if (now - lastTime >= timeFrame) { 6 | func(...args); 7 | lastTime = now; 8 | } 9 | }; 10 | } 11 | 12 | export function getRowsCount(items, cols) { 13 | const getItemsMaxHeight = items.map((val) => { 14 | const item = val[cols]; 15 | 16 | return (item && item.y) + (item && item.h) || 0; 17 | }); 18 | 19 | return Math.max(...getItemsMaxHeight, 1); 20 | } 21 | 22 | export const getColumn = (containerWidth, columns) => { 23 | const sortColumns = columns.slice().sort((a, b) => a[0] - b[0]); 24 | 25 | const breakpoint = sortColumns.find((value) => { 26 | const [width] = value; 27 | return containerWidth <= width; 28 | }); 29 | 30 | if (breakpoint) { 31 | return breakpoint[1]; 32 | } else { 33 | return sortColumns[sortColumns.length - 1][1]; 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /www/.gitignore: -------------------------------------------------------------------------------- 1 | .now 2 | .vercel -------------------------------------------------------------------------------- /www/.nowignore: -------------------------------------------------------------------------------- 1 | Dockerfile 2 | .dockerignore 3 | docker-compose.yml 4 | -------------------------------------------------------------------------------- /www/now.json: -------------------------------------------------------------------------------- 1 | { 2 | "public": true 3 | } -------------------------------------------------------------------------------- /www/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "dev": "sapper dev --ext '.svelte .svx'", 4 | "build": "sapper build --legacy --ext '.svelte .svx'", 5 | "export": "sapper export --legacy --ext '.svelte .svx'", 6 | "start": "node __sapper__/build" 7 | }, 8 | "dependencies": { 9 | "compression": "^1.7.1" 10 | }, 11 | "devDependencies": { 12 | "@babel/core": "^7.12.10", 13 | "@babel/plugin-syntax-dynamic-import": "^7.0.0", 14 | "@babel/plugin-transform-runtime": "^7.12.10", 15 | "@babel/preset-env": "^7.12.11", 16 | "@babel/runtime": "^7.12.5", 17 | "@rollup/plugin-babel": "^5.2.2", 18 | "@rollup/plugin-commonjs": "^16.0.0", 19 | "@rollup/plugin-node-resolve": "^10.0.0", 20 | "@rollup/plugin-replace": "^2.3.4", 21 | "mdsvex": "^0.8.9", 22 | "npm-run-all": "^4.1.5", 23 | "polka": "^0.5.2", 24 | "prism": "^4.1.2", 25 | "prism-svelte": "^0.4.7", 26 | "prismjs": "^1.23.0", 27 | "rehype-autolink-headings": "^5.0.1", 28 | "rehype-slug": "^4.0.1", 29 | "rollup": "^2.36.2", 30 | "rollup-plugin-glob": "^1.0.2", 31 | "rollup-plugin-svelte": "^6.1.1", 32 | "rollup-plugin-terser": "^7.0.2", 33 | "sapper": "^0.28.10", 34 | "sirv": "^1.0.10", 35 | "svelte": "^3.31.2" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /www/rollup.config.js: -------------------------------------------------------------------------------- 1 | import 'prismjs'; 2 | import "prism-svelte"; 3 | 4 | import resolve from "@rollup/plugin-node-resolve"; 5 | import replace from "@rollup/plugin-replace"; 6 | import commonjs from "@rollup/plugin-commonjs"; 7 | import svelte from "rollup-plugin-svelte"; 8 | import babel from "@rollup/plugin-babel"; 9 | import { terser } from "rollup-plugin-terser"; 10 | import config from "sapper/config/rollup.js"; 11 | import pkg from "./package.json"; 12 | import { mdsvex } from "mdsvex"; 13 | import glob from 'rollup-plugin-glob' 14 | 15 | const mode = process.env.NODE_ENV; 16 | const dev = mode === "development"; 17 | const legacy = !!process.env.SAPPER_LEGACY_BUILD; 18 | 19 | const onwarn = (warning, onwarn) => 20 | (warning.code === 'MISSING_EXPORT' && /'preload'/.test(warning.message)) || 21 | (warning.code === 'CIRCULAR_DEPENDENCY' && /[/\\]@sapper[/\\]/.test(warning.message)) || 22 | onwarn(warning); 23 | 24 | const extensions = [".svelte", ".svx"]; 25 | export default { 26 | client: { 27 | input: config.client.input(), 28 | output: config.client.output(), 29 | plugins: [ 30 | glob(), 31 | replace({ 32 | "process.browser": true, 33 | "process.env.NODE_ENV": JSON.stringify(mode) 34 | }), 35 | svelte({ 36 | extensions, 37 | dev, 38 | hydratable: true, 39 | emitCss: true, 40 | preprocess: mdsvex() 41 | }), 42 | resolve({ 43 | browser: true, 44 | dedupe: ['svelte'] 45 | }), 46 | commonjs(), 47 | 48 | legacy && 49 | babel({ 50 | extensions: [".js", ".mjs", ".html", ...extensions], 51 | babelHelpers: "runtime", 52 | exclude: ["node_modules/@babel/**"], 53 | presets: [ 54 | [ 55 | "@babel/preset-env", 56 | { 57 | targets: "> 0.25%, not dead" 58 | } 59 | ] 60 | ], 61 | plugins: [ 62 | "@babel/plugin-syntax-dynamic-import", 63 | [ 64 | "@babel/plugin-transform-runtime", 65 | { 66 | useESModules: true 67 | } 68 | ] 69 | ] 70 | }), 71 | 72 | !dev && 73 | terser({ 74 | module: true 75 | }) 76 | ], 77 | 78 | onwarn 79 | }, 80 | 81 | server: { 82 | input: config.server.input(), 83 | output: config.server.output(), 84 | plugins: [ 85 | glob(), 86 | replace({ 87 | "process.browser": false, 88 | "process.env.NODE_ENV": JSON.stringify(mode) 89 | }), 90 | svelte({ 91 | extensions, 92 | hydratable: true, 93 | preprocess: mdsvex(), 94 | generate: "ssr", 95 | dev 96 | }), 97 | resolve({ 98 | dedupe: ['svelte'] 99 | }), 100 | commonjs() 101 | ], 102 | external: Object.keys(pkg.dependencies).concat(require('module').builtinModules), 103 | preserveEntrySignatures: 'strict', 104 | onwarn 105 | }, 106 | 107 | serviceworker: { 108 | input: config.serviceworker.input(), 109 | output: config.serviceworker.output(), 110 | plugins: [ 111 | resolve(), 112 | replace({ 113 | "process.browser": true, 114 | "process.env.NODE_ENV": JSON.stringify(mode) 115 | }), 116 | commonjs(), 117 | !dev && terser() 118 | ], 119 | preserveEntrySignatures: false, 120 | onwarn 121 | } 122 | }; 123 | -------------------------------------------------------------------------------- /www/src/client.js: -------------------------------------------------------------------------------- 1 | import * as sapper from '@sapper/app'; 2 | 3 | sapper.start({ 4 | target: document.querySelector('#sapper') 5 | }); -------------------------------------------------------------------------------- /www/src/components/Footer.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /www/src/components/Nav.svelte: -------------------------------------------------------------------------------- 1 | 38 | 39 | 46 | 47 | 50 | -------------------------------------------------------------------------------- /www/src/components/Ribbon.svelte: -------------------------------------------------------------------------------- 1 | 28 | 29 | 30 | 31 | 32 | 36 | 37 | -------------------------------------------------------------------------------- /www/src/routes/_layout.svelte: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | 27 |