├── .gitignore ├── LICENSE.md ├── README.md ├── nodejs └── htmlGenerator.mjs ├── package-lock.json ├── package.json ├── rollup.config.js ├── src ├── client.js ├── components │ ├── Footer.svelte │ ├── LangSelect.svelte │ ├── Logo.svelte │ ├── Nav.svelte │ ├── ShinyButton.svelte │ ├── SimpleAutocomplete.svelte │ └── StickyFooter.svelte ├── css │ ├── global.css │ └── pickr.css ├── routes │ ├── [slug].json.js │ ├── [slug].svelte │ ├── _constants.js │ ├── _error.svelte │ ├── _index.js │ ├── _lang.js │ ├── _layout.svelte │ ├── _values.js │ ├── api.svelte │ ├── changelog.svelte │ ├── confirmed.svelte │ ├── downloads.svelte │ ├── features.svelte │ ├── index.json.js │ ├── index.svelte │ ├── privacy-policy.svelte │ └── stores.js ├── server.js ├── service-worker.js └── template.html └── static ├── .well-known └── brave-rewards-verification.txt ├── Screenshot1.png ├── Screenshot2.png ├── Screenshot3.png ├── ads.txt ├── coffeefont.ttf ├── favicon.png ├── global-1725151604.min.css ├── icons ├── mstile-144x144.png ├── mstile-150x150.png ├── mstile-310x150.png ├── mstile-310x310.png └── mstile-70x70.png ├── logo-192.png ├── logo-512.png ├── manifest.json ├── pickr-1725151604.min.css ├── robots.txt ├── sitemap.xml └── social ├── test.png └── test.svg /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /node_modules/ 3 | /src/node_modules/@sapper/ 4 | yarn-error.log 5 | /cypress/screenshots/ 6 | /__sapper__/ 7 | Samples.md 8 | createScreenshot.js 9 | create* 10 | airtable.js 11 | /static/archive 12 | /static/social 13 | /static/screenshots 14 | redbubble 15 | SVGtoPNG.js 16 | test-worker/ 17 | *.pattern.monster/ 18 | src/css/*-* 19 | *.env -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 - 2023 pattern.monster 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pattern Monster - SVG Pattern Generator 2 | 3 | ![GitHub repo size](https://img.shields.io/github/repo-size/catchspider2002/svelte-svg-patterns) 4 | [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) 5 | ![GitHub last commit](https://img.shields.io/github/last-commit/catchspider2002/svelte-svg-patterns) 6 | ![Website](https://img.shields.io/website?up_message=online&url=https%3A%2F%2Fpattern.monster%2F) 7 | 8 |
9 | pattern.monster 10 |
11 |

12 | 13 | Create seamless patterns in SVG to use as website backgrounds, header images, stationery design and package design 14 | 15 | 320+ patterns available 16 | 17 | ## Features: 18 | 19 | ✔ Customize foreground and background colors 20 | 21 | ✔ Modify stroke width for supported patterns 22 | 23 | ✔ Change the angle to generate unique images 24 | 25 | ✔ Copy CSS and SVG code directly to your clipboard for web projects 26 | 27 | ✔ Download a tileable SVG or a high resolution seamless PNG image for print projects 28 | 29 | ✔ Filter patterns by stroke / fill or by number of colors 30 | 31 | ✔ Search for patterns 32 | 33 | ✔ Sort patterns alphabetically or by date updated 34 | 35 | # License 36 | 37 | MIT License 38 | 39 | Copyright (c) 2020 - 2023 pattern.monster 40 | 41 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 42 | 43 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 44 | 45 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /nodejs/htmlGenerator.mjs: -------------------------------------------------------------------------------- 1 | // const fs = require("fs"); 2 | // const fsextra = require("fs-extra"); 3 | 4 | // const xlsxFile = require("read-excel-file/node"); 5 | 6 | // const minify = require("@node-minify/core"); 7 | // const cleanCSS = require("@node-minify/clean-css"); 8 | // const glob = require("glob"); 9 | 10 | import fs from "fs"; 11 | import fsextra from "fs-extra"; 12 | import xlsxFile from "read-excel-file/node"; 13 | import minify from "@node-minify/core"; 14 | import cleanCSS from "@node-minify/clean-css"; 15 | import glob from "glob"; 16 | import dotenv from "dotenv"; 17 | 18 | dotenv.config({ path: "../.env" }); 19 | 20 | let timestamp = Math.round(+new Date() / 1000); 21 | let globalCSS = "global-" + timestamp + ".min.css"; 22 | let pickrCSS = "pickr-" + timestamp + ".min.css"; 23 | 24 | minify({ 25 | compressor: cleanCSS, 26 | input: "../src/css/global.css", 27 | output: "../src/css/" + globalCSS, 28 | callback: function (err, min) {}, 29 | }); 30 | 31 | minify({ 32 | compressor: cleanCSS, 33 | input: "../src/css/pickr.css", 34 | output: "../src/css/" + pickrCSS, 35 | callback: function (err, min) {}, 36 | }); 37 | 38 | let prog = async () => { 39 | const CROWDIN = process.env.VITE_CROWDIN; 40 | 41 | var requestOptions = { 42 | method: "GET", 43 | headers: { Authorization: `Bearer ${CROWDIN}` }, 44 | redirect: "follow", 45 | }; 46 | 47 | const targetLanguages = await ( 48 | await fetch( 49 | "https://api.crowdin.com/api/v2/projects/431524?limit=50", 50 | requestOptions 51 | ) 52 | ).json(); 53 | 54 | // console.log(JSON.stringify(targetLanguages.data)) 55 | 56 | const targetLang = await targetLanguages.data.targetLanguages.map((val) => ({ 57 | id: val.id, 58 | name: val.name, 59 | code: 60 | val.editorCode.length > 2 61 | ? val.editorCode.slice(0, 2) + "-" + val.editorCode.substring(2) 62 | : val.editorCode, 63 | })); 64 | 65 | const progress = await ( 66 | await fetch( 67 | "https://api.crowdin.com/api/v2/projects/431524/languages/progress?limit=50", 68 | requestOptions 69 | ) 70 | ).json(); 71 | 72 | const translationStatus = progress.data.map((val) => ({ 73 | id: val.data.languageId, 74 | translation: val.data.translationProgress, 75 | approval: val.data.approvalProgress, 76 | })); 77 | 78 | const mergedArray = targetLang.map((lang) => { 79 | const status = translationStatus.find((status) => status.id === lang.id); 80 | return { ...lang, ...status }; 81 | }); 82 | 83 | mergedArray.sort((a, b) => a.name.localeCompare(b.name)); 84 | 85 | return mergedArray; 86 | }; 87 | 88 | let langs = await prog(); 89 | 90 | let languages = [ 91 | { 92 | lang: "en", 93 | name: "English", 94 | col: 1, 95 | site: "https://pattern.monster", 96 | path: "../", 97 | }, 98 | { 99 | lang: "de", 100 | name: "Deutsch", 101 | col: 2, 102 | site: "https://de.pattern.monster", 103 | path: "../de.pattern.monster/", 104 | }, 105 | { 106 | lang: "pl", 107 | name: "Polski", 108 | col: 3, 109 | site: "https://pl.pattern.monster", 110 | path: "../pl.pattern.monster/", 111 | }, 112 | { 113 | lang: "tr", 114 | name: "Türkçe", 115 | col: 4, 116 | site: "https://tr.pattern.monster", 117 | path: "../tr.pattern.monster/", 118 | }, 119 | { 120 | lang: "es", 121 | name: "Español", 122 | col: 5, 123 | site: "https://es.pattern.monster", 124 | path: "../es.pattern.monster/", 125 | }, 126 | { 127 | lang: "it", 128 | name: "Italiano", 129 | col: 6, 130 | site: "https://it.pattern.monster", 131 | path: "../it.pattern.monster/", 132 | }, 133 | { 134 | lang: "ro", 135 | name: "Română", 136 | col: 7, 137 | site: "https://ro.pattern.monster", 138 | path: "../ro.pattern.monster/", 139 | }, 140 | { 141 | lang: "fr", 142 | name: "Français", 143 | col: 8, 144 | site: "https://fr.pattern.monster", 145 | path: "../fr.pattern.monster/", 146 | }, 147 | { 148 | lang: "ar", 149 | name: "العربية", 150 | col: 9, 151 | site: "https://ar.pattern.monster", 152 | path: "../ar.pattern.monster/", 153 | }, 154 | { 155 | lang: "pt", 156 | name: "Português", 157 | col: 10, 158 | site: "https://pt.pattern.monster", 159 | path: "../pt.pattern.monster/", 160 | }, 161 | { 162 | lang: "zh-cn", 163 | name: "中文(简体)", 164 | col: 11, 165 | site: "https://cn.pattern.monster", 166 | path: "../cn.pattern.monster/", 167 | }, 168 | { 169 | lang: "nl", 170 | name: "Nederlands", 171 | col: 12, 172 | site: "https://nl.pattern.monster", 173 | path: "../nl.pattern.monster/", 174 | }, 175 | { 176 | lang: "sv", 177 | name: "Svenska", 178 | col: 13, 179 | site: "https://sv.pattern.monster", 180 | path: "../sv.pattern.monster/", 181 | }, 182 | { 183 | lang: "uk", 184 | name: "Українська", 185 | col: 14, 186 | site: "https://uk.pattern.monster", 187 | path: "../uk.pattern.monster/", 188 | }, 189 | { 190 | lang: "ru", 191 | name: "Русский", 192 | col: 15, 193 | site: "https://ru.pattern.monster", 194 | path: "../ru.pattern.monster/", 195 | }, 196 | { 197 | lang: "hu", 198 | name: "Magyar", 199 | col: 16, 200 | site: "https://hu.pattern.monster", 201 | path: "../hu.pattern.monster/", 202 | }, 203 | { 204 | lang: "af", 205 | name: "Afrikaans", 206 | col: 17, 207 | site: "https://af.pattern.monster", 208 | path: "../af.pattern.monster/", 209 | }, 210 | { 211 | lang: "ca", 212 | name: "Català", 213 | col: 18, 214 | site: "https://ca.pattern.monster", 215 | path: "../ca.pattern.monster/", 216 | }, 217 | { 218 | lang: "zh-tw", 219 | name: "中文 (繁體)", 220 | col: 19, 221 | site: "https://tw.pattern.monster", 222 | path: "../tw.pattern.monster/", 223 | }, 224 | { 225 | lang: "cs", 226 | name: "Čeština", 227 | col: 20, 228 | site: "https://cs.pattern.monster", 229 | path: "../cs.pattern.monster/", 230 | }, 231 | { 232 | lang: "da", 233 | name: "Dansk", 234 | col: 21, 235 | site: "https://da.pattern.monster", 236 | path: "../da.pattern.monster/", 237 | }, 238 | { 239 | lang: "fi", 240 | name: "Suomi", 241 | col: 22, 242 | site: "https://fi.pattern.monster", 243 | path: "../fi.pattern.monster/", 244 | }, 245 | { 246 | lang: "ja", 247 | name: "日本語", 248 | col: 25, 249 | site: "https://ja.pattern.monster", 250 | path: "../ja.pattern.monster/", 251 | }, 252 | { 253 | lang: "ko", 254 | name: "한국어", 255 | col: 26, 256 | site: "https://ko.pattern.monster", 257 | path: "../ko.pattern.monster/", 258 | }, 259 | ]; 260 | 261 | let versions = languages.map((language) => ({ 262 | lang: language.lang, 263 | name: language.name, 264 | website: language.site, 265 | })); 266 | 267 | xlsxFile("../../../../OneDrive/Documents/Patterns.xlsm", { 268 | sheet: "Patterns", 269 | }).then((rows) => { 270 | languages.forEach((language) => { 271 | xlsxFile("../../../../OneDrive/Documents/Patterns.xlsm", { 272 | sheet: "Translation", 273 | }).then((transRows) => { 274 | let array = getArray(language.col); 275 | 276 | function getArray(col) { 277 | let o = {}; 278 | for (let j = 63; j < transRows.length; j++) { 279 | // console.log(transRows[j][1]) 280 | o[transRows[j][1].toLowerCase()] = 281 | transRows[j][col] === "" || !transRows[j][col] 282 | ? transRows[j][1] 283 | : transRows[j][col]; 284 | } 285 | 286 | return o; 287 | } 288 | 289 | let translations = getTranslation(language.col); 290 | 291 | function getTranslation(col) { 292 | let o = {}; 293 | for (let j = 0; j < transRows.length; j++) { 294 | o[transRows[j][0]] = 295 | transRows[j][col] === "" || !transRows[j][col] 296 | ? transRows[j][1] 297 | : transRows[j][col]; 298 | } 299 | 300 | return o; 301 | } 302 | 303 | function getStrings(col) { 304 | let o = {}; 305 | for (let j = 1; j < transRows.length; j++) { 306 | o[transRows[j][0]] = 307 | transRows[j][col] === "" || !transRows[j][col] 308 | ? transRows[j][1] 309 | : transRows[j][col]; 310 | } 311 | 312 | return o; 313 | } 314 | 315 | glob(language.path + "static/global*.css", function (er, files) { 316 | for (const file of files) { 317 | try { 318 | fs.unlinkSync(file); 319 | } catch (err) { 320 | console.error(err); 321 | } 322 | } 323 | }); 324 | 325 | glob(language.path + "static/pickr*.css", function (er, files) { 326 | for (const file of files) { 327 | try { 328 | fs.unlinkSync(file); 329 | } catch (err) { 330 | console.error(err); 331 | } 332 | } 333 | }); 334 | 335 | let direction = ``; 336 | if (language.lang === "ar") direction = ` dir="rtl"`; 337 | let templateFile = ` 338 | 339 | 340 | 341 | 342 | 343 | %sapper.base% 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | %sapper.styles% 371 | %sapper.head% 372 | 374 | 375 | 376 |
%sapper.html%
377 | 378 | %sapper.scripts% 379 | 380 | 381 | 382 | 383 | `; 384 | 385 | fs.writeFile( 386 | language.path + "src/template.html", 387 | templateFile, 388 | function (err) { 389 | if (err) return console.log(err); 390 | } 391 | ); 392 | 393 | // _lang.js 394 | let writeStream = fs.createWriteStream( 395 | language.path + "src/routes/_lang.js" 396 | ); 397 | writeStream.write("const strings = "); 398 | writeStream.write(JSON.stringify(getStrings(language.col))); 399 | writeStream.write(";export default { strings };"); 400 | 401 | writeStream.on("finish", () => { 402 | console.log("Created strings"); 403 | }); 404 | writeStream.end(); 405 | 406 | // stores.js 407 | writeStream = fs.createWriteStream( 408 | language.path + "src/routes/stores.js" 409 | ); 410 | writeStream.write(`import { writable } from "svelte/store"; 411 | 412 | export const themeStore = writable("light"); 413 | export const langStore = writable("${language.lang}");`); 414 | 415 | writeStream.on("finish", () => { 416 | console.log("Created "); 417 | }); 418 | writeStream.end(); 419 | 420 | // robots.txt 421 | writeStream = fs.createWriteStream(language.path + "static/robots.txt"); 422 | writeStream.write(`Sitemap: ${language.site}/sitemap.xml 423 | User-agent: * 424 | Crawl-Delay: 20`); 425 | 426 | writeStream.on("finish", () => { 427 | console.log("Created "); 428 | }); 429 | writeStream.end(); 430 | 431 | // _index.js 432 | let langValues = printObject(language.col); 433 | 434 | writeStream = fs.createWriteStream( 435 | language.path + "src/routes/_index.js" 436 | ); 437 | writeStream.write("const index = "); 438 | writeStream.write(JSON.stringify(langValues)); 439 | writeStream.write("; export default index;"); 440 | 441 | writeStream.on("finish", () => { 442 | console.log("Created "); 443 | }); 444 | writeStream.end(); 445 | 446 | // pro/_index.js 447 | if (language.lang == "en") { 448 | let newValues = printObject(language.col, "premium"); 449 | 450 | writeStream = fs.createWriteStream( 451 | "../pro.pattern.monster/src/lib/_index.js" 452 | ); 453 | writeStream.write("const index = "); 454 | writeStream.write(JSON.stringify(newValues)); 455 | writeStream.write("; export default index;"); 456 | 457 | writeStream.on("finish", () => { 458 | console.log("Created "); 459 | }); 460 | writeStream.end(); 461 | } 462 | 463 | let sitePath = ["features", "downloads", "changelog", "privacy-policy"]; 464 | 465 | // sitemap.xml 466 | writeStream = fs.createWriteStream(language.path + "static/sitemap.xml"); 467 | 468 | let date = new Date().toISOString(); 469 | 470 | writeStream.write('\n'); 471 | writeStream.write( 472 | '\n' 473 | ); 474 | writeStream.write(" \n"); 475 | writeStream.write(" " + language.site + "\n"); 476 | writeStream.write(" " + date + "\n"); 477 | writeStream.write(" 1.0\n"); 478 | writeStream.write(" \n"); 479 | 480 | sitePath.forEach((path) => { 481 | writeStream.write(" \n"); 482 | writeStream.write( 483 | " " + language.site + "/" + path + "/\n" 484 | ); 485 | writeStream.write(" " + date + "\n"); 486 | writeStream.write(" 0.8\n"); 487 | writeStream.write(" \n"); 488 | }); 489 | 490 | langValues.forEach((path) => { 491 | writeStream.write(" \n"); 492 | writeStream.write( 493 | " " + language.site + "/" + path.slug + "/\n" 494 | ); 495 | writeStream.write(" " + date + "\n"); 496 | writeStream.write(" 0.8\n"); 497 | writeStream.write(" \n"); 498 | }); 499 | 500 | writeStream.write(""); 501 | 502 | // the finish event is emitted when all data has been flushed from the stream 503 | writeStream.on("finish", () => { 504 | console.log("Created sitemap"); 505 | }); 506 | 507 | // close the stream 508 | writeStream.end(); 509 | 510 | // package.json 511 | writeStream = fs.createWriteStream(language.path + "package.json"); 512 | writeStream.write(`{ 513 | "name": "${language.site}", 514 | "description": "SVG Patterns", 515 | "version": "0.0.1", 516 | "scripts": { 517 | "dev": "sapper dev", 518 | "build": "sapper build --legacy", 519 | "export": "sapper export --entry \\"index api features confirmed herringbone-7 herringbone-8 flower-1 flower-2 flower-3 flower-4 flower-5 flower-6 flower-7 plus-1 plus-2 plus-3 plus-4 circles-1 circles-2 circles-3 circles-4 circles-5 circles-6 circles-7 concentric-circles-1 concentric-circles-2 concentric-circles-3 adjointed-circles adjointed-diamonds diamonds-1 diamonds-2 diamonds-3 hexagon-1 hexagon-2 hexagon-3 hexagon-4 hexagon-5 hexagon-6 hexagon-7 hexagon-8 overlapping-hexagons squares-and-squares-1 squares-and-squares-2 squares-and-diamonds squares-and-circles-1 squares-and-circles-2 squares-and-plus-1 squares-and-plus-2 squares-and-stars-1 squares-and-stars-2 stars-and-lines-1 stars-and-lines-2 triangles-1 triangles-2 triangles-3 triangles-4 triangles-5 triangles-6 triangles-7 triangles-8 triangles-9 triangles-10 inverted-triangles checkerboard japanese-pattern-1 japanese-pattern-2 japanese-pattern-3 japanese-pattern-4 japanese-pattern-5 japanese-pattern-6 eyes-1 eyes-2 eyes-3 eyes-4 jigsaw railroad octagons-1 octagons-2 lines-1 lines-2 scales-1 scales-2 scales-3 scales-4 leaves-1 leaves-2 leaves-3 leaves-4 leaves-5 leaves-6 leaves-7 leaves-8 pipes zebra memphis-1 memphis-2 memphis-3 memphis-4 memphis-5 memphis-6 greek-key chinese-1 chinese-2 chinese-3 chinese-4 chinese-9 chinese-5 chinese-6 chinese-7 chinese-8 new-1 new-2 new-3 new-4 new-5 new-6 new-7 new-8 new-9 new-10 new-11 new-12 new-13 new-14 new-15 new-16 new-17 double-bubble-1 double-bubble-2 stars-1 stars-2 stars-3 stars-4 stars-5 stars-6 semicircles-1 songket-1 christmas-tree-1 candy-cane-1 christmas-bells-1 christmas-pattern-1 christmas-pattern-2 christmas-pattern-3 snowflakes-1 christmas-tree-balls santa-claus christmas-gift cubes-1 cubes-2 cubes-3 stained-glass tiles-1 rectangles-and-squares-1 mexican-pattern-1 mexican-pattern-2 ethnic-pattern-1 ethnic-pattern-2 ethnic-pattern-3 plaid-pattern-1 plaid-pattern-2 plaid-pattern-3 plaid-pattern-4 doodle-1 doodle-2 batik-1 batik-2 batik-3 batik-4 batik-5 batik-6 african-1 african-2 african-3 african-4 triangles-11 hexagon-9 tiles-2 tiles-3 tribal-1 tribal-2 waves-8 leaves-9 blobs african-5 triangles-12 squares-and-triangles-1 tribal-3 circles-8 triangles-13 triangles-14 triangles-15 triangles-16 circles-9 concentric-circles-4 concentric-circles-5 concentric-circles-6 stripes-1 stripes-2 chevron-4 chevron-5 terrazzo-1 geometric-1 halloween-1 halloween-2 halloween-3 halloween-4 halloween-5 halloween-6 hexagon-10 hexagon-11 squares-1 squares-2 sprinkles-1 cubes-4 geometric-2 geometric-3 geometric-4 circles-10 circles-11 circles-12 triangles-17 triangles-18 geometric-5 geometric-6 squiggle-1 moroccan-1 moroccan-2 japanese-pattern-7 waves-9 christmas-pattern-4 christmas-pattern-5 plaid-pattern-5 plaid-pattern-6 circles-13 circles-14 interlocked-hexagons-1 interlocked-hexagons-2 interlocked-hexagons-3 lanterns-1 leaves-10 lines-3 rope-1 waves-10 waves-11 lines-4 lines-5 lines-6 plus-5 plus-6 scales-5 scales-6 scales-7 scales-8 scales-9 triangles-19 triangles-20 batik-7 circles-15 circles-16 circles-17 circles-and-diamonds diamonds-4 diamonds-5 diamonds-6 geometric-7 geometric-8 geometric-9 geometric-10 waves-12 waves-13 waves-14 waves-15 double-bubble-3 double-bubble-4 patches squares-3 squares-4 squares-5 squares-6 triangles-21 triangles-22 triangles-23 tribal-4 tribal-5 chinese-10 chinese-11 diamonds-7 diamonds-8 diamonds-9 waves-16 waves-17 waves-18 waves-19 waves-20 diamonds-10 diamonds-11 diamonds-12 diamonds-13 chinese-12 chinese-13 chinese-14 egyptian-1 egyptian-2 egyptian-3 circles-19 circles-20 egyptian-4 egyptian-6 waves-22 squares-and-circles-3 japanese-pattern-8 circles-22 diamonds-14 diamonds-15\\"", 520 | "start": "node __sapper__/build", 521 | "test": "run-p --race dev cy:run" 522 | }, 523 | "dependencies": { 524 | "@rollup/plugin-json": "^4.1.0", 525 | "@simonwep/pickr": "^1.8.2", 526 | "compression": "^1.7.4", 527 | "dayjs": "^1.11.9", 528 | "dotenv": "^16.3.1", 529 | "polka": "next", 530 | "prettier": "^2.8.8", 531 | "save-svg-as-png": "^1.4.17", 532 | "sirv": "^1.0.7" 533 | }, 534 | "devDependencies": { 535 | "@rollup/plugin-commonjs": "^16.0.0", 536 | "@rollup/plugin-node-resolve": "^10.0.0", 537 | "@rollup/plugin-replace": "^2.3.4", 538 | "npm-run-all": "^4.1.5", 539 | "rollup": "^2.33.3", 540 | "rollup-plugin-svelte": "^6.1.1", 541 | "rollup-plugin-terser": "^7.0.2", 542 | "sapper": "^0.29.1"`); 543 | 544 | if (language.lang == "en") 545 | writeStream.write(`, 546 | "svelte": "^3.59.1", 547 | "fs-extra": "^11.1.1", 548 | "@node-minify/clean-css": "^8.0.6", 549 | "@node-minify/core": "^8.0.6", 550 | "read-excel-file": "^5.6.1", 551 | "glob": "^8.1.0", 552 | "tinycolor2": "^1.6.0", 553 | "sharp": "^0.32.3", 554 | "convert-svg-to-png": "^0.6.4"`); 555 | writeStream.write(` 556 | } 557 | }`); 558 | 559 | writeStream.on("finish", () => { 560 | console.log("Created "); 561 | }); 562 | writeStream.end(); 563 | 564 | // fs.copyFile("global.css", lang + "/css/global.css", (err) => { 565 | // if (err) throw err; 566 | // }); 567 | // copyFile("../src/routes/_error.svelte", language.path + "src/components"); 568 | 569 | if (language.lang !== "en") { 570 | fsextra 571 | .copy("../src/components", language.path + "src/components") 572 | .then(() => console.log("Files copied successfully!")) 573 | .catch((err) => console.error(err)); 574 | } 575 | 576 | let routesFiles = [ 577 | "_error.svelte", 578 | "_layout.svelte", 579 | "_values.js", 580 | "[slug].json.js", 581 | "[slug].svelte", 582 | "changelog.svelte", 583 | "confirmed.svelte", 584 | "downloads.svelte", 585 | "features.svelte", 586 | "index.json.js", 587 | // "index.svelte", -- Don't copy this - have to change the language 588 | "privacy-policy.svelte", 589 | ]; 590 | 591 | routesFiles.forEach((filename) => { 592 | if (language.lang !== "en") 593 | copyFile( 594 | "../src/routes/" + filename, 595 | language.path + "src/routes/" + filename 596 | ); 597 | }); 598 | 599 | copyFile( 600 | "../src/css/" + globalCSS, 601 | language.path + "static/" + globalCSS 602 | ); 603 | copyFile("../src/css/" + pickrCSS, language.path + "static/" + pickrCSS); 604 | copyFile("../src/server.js", language.path + "src/server.js"); 605 | 606 | function copyFile(source, dest) { 607 | fs.copyFile(source, dest, (err) => { 608 | if (err) throw err; 609 | }); 610 | } 611 | 612 | let createConstants = () => { 613 | let writeStream = fs.createWriteStream( 614 | `${language.path}src/routes/_constants.js` 615 | ); 616 | 617 | writeStream.write(`const strings = { 618 | website: "${language.site}", 619 | title: "Pattern Monster", 620 | description: 621 | "${translations.description}", 622 | description2: "${translations.description2}", 623 | description3: 624 | "${translations.description3}", 625 | keywords: 626 | "${translations.keywords}", 627 | pages: [ 628 | { 629 | page: "index", 630 | title: "${translations.title}", 631 | keywords: "", 632 | description: "", 633 | image: "", 634 | }, 635 | { 636 | page: "changelog", 637 | title: "${translations.changelog}", 638 | keywords: "${translations.changelog.toLowerCase()}", 639 | description: "Changelog for Pattern Monster.", 640 | image: "", 641 | }, 642 | { 643 | page: "downloads", 644 | title: "${translations.downloads}", 645 | keywords: "${translations.downloads.toLowerCase()}", 646 | description: "Downloads for Pattern Monster.", 647 | image: "", 648 | }, 649 | { 650 | page: "features", 651 | title: "${translations.features}", 652 | keywords: "${translations.features.toLowerCase()}", 653 | description: "Features for Pattern Monster.", 654 | image: "", 655 | }, 656 | { 657 | page: "privacy-policy", 658 | title: "${translations.privacy}", 659 | keywords: "${translations.privacy.toLowerCase()}", 660 | description: "Privacy Policy for Pattern Monster.", 661 | image: "", 662 | }, 663 | { 664 | page: "api", 665 | title: "API", 666 | keywords: "api", 667 | description: "API for Pattern Monster.", 668 | image: "", 669 | }, 670 | ], 671 | versions: ${JSON.stringify(versions)}, 672 | langs:${JSON.stringify(langs)} 673 | }; 674 | 675 | const pageDetails = (page) => { 676 | let imagePrefix = "https://giguom.com/pattern.monster/images/"; 677 | let pageValues = 678 | strings.pages.filter((currentPage) => currentPage.page === page)[0] || 679 | strings.pages.filter((currentPage) => currentPage.page === "index")[0]; 680 | 681 | let website = strings.website; 682 | let title = strings.title + " - " + strings.pages[0].title; 683 | let url = website; 684 | let keywords = strings.keywords; 685 | let desc = strings.description + " " + strings.description3; 686 | let image = 687 | pageValues.image == "" ? imagePrefix + "/TwitterBG2.png" : pageValues.image; 688 | 689 | let versions = strings.versions.map((version) => { 690 | return { 691 | lang: version.lang, 692 | website: version.website + (page === "index" ? "" : "/" + page + "/"), 693 | }; 694 | }); 695 | 696 | if (page != "index") { 697 | title = 698 | pageValues.title + " - " + strings.title + " | " + strings.pages[0].title; 699 | url = website + "/" + page + "/"; 700 | desc = 701 | pageValues.description + 702 | " " + 703 | strings.description + 704 | " " + 705 | strings.description3; 706 | keywords = pageValues.keywords + ", " + strings.keywords; 707 | } 708 | 709 | return { title, url, keywords, desc, image, versions }; 710 | }; 711 | 712 | let lightColors = [ 713 | "hsla(0,0%,100%,1)", 714 | "hsla(258.5,59.4%,59.4%,1)", 715 | "hsla(339.6,82.2%,51.6%,1)", 716 | "hsla(198.7,97.6%,48.4%,1)", 717 | "hsla(47,80.9%,61%,1)", 718 | ]; 719 | let darkColors = [ 720 | "hsla(240,6.7%,17.6%,1)", 721 | "hsla(47,80.9%,61%,1)", 722 | "hsla(4.1,89.6%,58.4%,1)", 723 | "hsla(186.8,100%,41.6%,1)", 724 | "hsla(258.5,59.4%,59.4%,1)", 725 | ]; 726 | 727 | export default { strings, pageDetails, lightColors, darkColors }; 728 | `); 729 | // writeStream.write(JSON.stringify(getStrings(language.col))); 730 | // writeStream.write(';export default { strings };'); 731 | 732 | writeStream.on("finish", () => { 733 | console.log("Created strings"); 734 | }); 735 | writeStream.end(); 736 | }; 737 | 738 | createConstants(); 739 | 740 | function printObject(col, pro) { 741 | let p = []; 742 | for (let j = 1; j < rows.length; j++) { 743 | // for (let j = 1; j < 12; j++) { 744 | let row = rows[j]; 745 | let title = rows[j][1]; 746 | let tags = rows[j][11]; 747 | 748 | let isPremium = rows[j][15] === "premium"; 749 | 750 | if (!pro && isPremium) { 751 | continue; 752 | } 753 | 754 | var newTitle = 755 | title.indexOf(" -") > 0 756 | ? title.substring(0, title.indexOf(" -")) 757 | : title; 758 | var newArray = tags.split(","); 759 | let newTag = newArray; 760 | 761 | newArray.forEach((val) => { 762 | if ( 763 | array[val.toLowerCase()] && 764 | array[val.toLowerCase()].toLowerCase() !== val 765 | ) 766 | newTag.push(array[val.toLowerCase()].toLowerCase()); 767 | }); 768 | 769 | p.push({ 770 | title: array[newTitle.toLowerCase()] 771 | ? title.replace(newTitle, array[newTitle.toLowerCase()]) 772 | : title, 773 | slug: row[2], 774 | mode: row[3], 775 | colors: row[4], 776 | maxStroke: row[5], 777 | maxScale: row[6], 778 | maxSpacing: JSON.parse(row[7]), 779 | width: row[8], 780 | height: row[9], 781 | vHeight: row[10], 782 | tags: newTag, 783 | path: row[12], 784 | creationDate: row[14], // recently changed 785 | }); 786 | } 787 | 788 | return p; 789 | } 790 | }); 791 | }); 792 | }); 793 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "https://pattern.monster", 3 | "description": "SVG Patterns", 4 | "version": "0.0.1", 5 | "scripts": { 6 | "dev": "sapper dev", 7 | "build": "sapper build --legacy", 8 | "export": "sapper export --entry \"index api features confirmed herringbone-7 herringbone-8 flower-1 flower-2 flower-3 flower-4 flower-5 flower-6 flower-7 plus-1 plus-2 plus-3 plus-4 circles-1 circles-2 circles-3 circles-4 circles-5 circles-6 circles-7 concentric-circles-1 concentric-circles-2 concentric-circles-3 adjointed-circles adjointed-diamonds diamonds-1 diamonds-2 diamonds-3 hexagon-1 hexagon-2 hexagon-3 hexagon-4 hexagon-5 hexagon-6 hexagon-7 hexagon-8 overlapping-hexagons squares-and-squares-1 squares-and-squares-2 squares-and-diamonds squares-and-circles-1 squares-and-circles-2 squares-and-plus-1 squares-and-plus-2 squares-and-stars-1 squares-and-stars-2 stars-and-lines-1 stars-and-lines-2 triangles-1 triangles-2 triangles-3 triangles-4 triangles-5 triangles-6 triangles-7 triangles-8 triangles-9 triangles-10 inverted-triangles checkerboard japanese-pattern-1 japanese-pattern-2 japanese-pattern-3 japanese-pattern-4 japanese-pattern-5 japanese-pattern-6 eyes-1 eyes-2 eyes-3 eyes-4 jigsaw railroad octagons-1 octagons-2 lines-1 lines-2 scales-1 scales-2 scales-3 scales-4 leaves-1 leaves-2 leaves-3 leaves-4 leaves-5 leaves-6 leaves-7 leaves-8 pipes zebra memphis-1 memphis-2 memphis-3 memphis-4 memphis-5 memphis-6 greek-key chinese-1 chinese-2 chinese-3 chinese-4 chinese-9 chinese-5 chinese-6 chinese-7 chinese-8 new-1 new-2 new-3 new-4 new-5 new-6 new-7 new-8 new-9 new-10 new-11 new-12 new-13 new-14 new-15 new-16 new-17 double-bubble-1 double-bubble-2 stars-1 stars-2 stars-3 stars-4 stars-5 stars-6 semicircles-1 songket-1 christmas-tree-1 candy-cane-1 christmas-bells-1 christmas-pattern-1 christmas-pattern-2 christmas-pattern-3 snowflakes-1 christmas-tree-balls santa-claus christmas-gift cubes-1 cubes-2 cubes-3 stained-glass tiles-1 rectangles-and-squares-1 mexican-pattern-1 mexican-pattern-2 ethnic-pattern-1 ethnic-pattern-2 ethnic-pattern-3 plaid-pattern-1 plaid-pattern-2 plaid-pattern-3 plaid-pattern-4 doodle-1 doodle-2 batik-1 batik-2 batik-3 batik-4 batik-5 batik-6 african-1 african-2 african-3 african-4 triangles-11 hexagon-9 tiles-2 tiles-3 tribal-1 tribal-2 waves-8 leaves-9 blobs african-5 triangles-12 squares-and-triangles-1 tribal-3 circles-8 triangles-13 triangles-14 triangles-15 triangles-16 circles-9 concentric-circles-4 concentric-circles-5 concentric-circles-6 stripes-1 stripes-2 chevron-4 chevron-5 terrazzo-1 geometric-1 halloween-1 halloween-2 halloween-3 halloween-4 halloween-5 halloween-6 hexagon-10 hexagon-11 squares-1 squares-2 sprinkles-1 cubes-4 geometric-2 geometric-3 geometric-4 circles-10 circles-11 circles-12 triangles-17 triangles-18 geometric-5 geometric-6 squiggle-1 moroccan-1 moroccan-2 japanese-pattern-7 waves-9 christmas-pattern-4 christmas-pattern-5 plaid-pattern-5 plaid-pattern-6 circles-13 circles-14 interlocked-hexagons-1 interlocked-hexagons-2 interlocked-hexagons-3 lanterns-1 leaves-10 lines-3 rope-1 waves-10 waves-11 lines-4 lines-5 lines-6 plus-5 plus-6 scales-5 scales-6 scales-7 scales-8 scales-9 triangles-19 triangles-20 batik-7 circles-15 circles-16 circles-17 circles-and-diamonds diamonds-4 diamonds-5 diamonds-6 geometric-7 geometric-8 geometric-9 geometric-10 waves-12 waves-13 waves-14 waves-15 double-bubble-3 double-bubble-4 patches squares-3 squares-4 squares-5 squares-6 triangles-21 triangles-22 triangles-23 tribal-4 tribal-5 chinese-10 chinese-11 diamonds-7 diamonds-8 diamonds-9 waves-16 waves-17 waves-18 waves-19 waves-20 diamonds-10 diamonds-11 diamonds-12 diamonds-13 chinese-12 chinese-13 chinese-14 egyptian-1 egyptian-2 egyptian-3 circles-19 circles-20 egyptian-4 egyptian-6 waves-22 squares-and-circles-3 japanese-pattern-8 circles-22 diamonds-14 diamonds-15\"", 9 | "start": "node __sapper__/build", 10 | "test": "run-p --race dev cy:run" 11 | }, 12 | "dependencies": { 13 | "@rollup/plugin-json": "^4.1.0", 14 | "@simonwep/pickr": "^1.8.2", 15 | "compression": "^1.7.4", 16 | "dayjs": "^1.11.9", 17 | "dotenv": "^16.3.1", 18 | "polka": "next", 19 | "prettier": "^2.8.8", 20 | "save-svg-as-png": "^1.4.17", 21 | "sirv": "^1.0.7" 22 | }, 23 | "devDependencies": { 24 | "@rollup/plugin-commonjs": "^16.0.0", 25 | "@rollup/plugin-node-resolve": "^10.0.0", 26 | "@rollup/plugin-replace": "^2.3.4", 27 | "npm-run-all": "^4.1.5", 28 | "rollup": "^2.33.3", 29 | "rollup-plugin-svelte": "^6.1.1", 30 | "rollup-plugin-terser": "^7.0.2", 31 | "sapper": "^0.29.1", 32 | "svelte": "^3.59.1", 33 | "fs-extra": "^11.1.1", 34 | "@node-minify/clean-css": "^8.0.6", 35 | "@node-minify/core": "^8.0.6", 36 | "read-excel-file": "^5.6.1", 37 | "glob": "^8.1.0", 38 | "tinycolor2": "^1.6.0", 39 | "sharp": "^0.32.3", 40 | "convert-svg-to-png": "^0.6.4" 41 | } 42 | } -------------------------------------------------------------------------------- /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 { terser } from "rollup-plugin-terser"; 6 | import config from "sapper/config/rollup.js"; 7 | import pkg from "./package.json"; 8 | import json from '@rollup/plugin-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' && /[/\\]@sapper[/\\]/.test(warning.message)) || onwarn(warning); 15 | const onwarn = (warning, onwarn) => 16 | (warning.code === "MISSING_EXPORT" && /'preload'/.test(warning.message)) || 17 | (warning.code === "CIRCULAR_DEPENDENCY" && /[/\\]@sapper[/\\]/.test(warning.message)) || 18 | onwarn(warning); 19 | 20 | export default { 21 | client: { 22 | input: config.client.input(), 23 | output: config.client.output(), 24 | plugins: [ 25 | replace({ 26 | "process.browser": true, 27 | "process.env.NODE_ENV": JSON.stringify(mode), 28 | }), 29 | json(), 30 | svelte({ 31 | dev, 32 | hydratable: true, 33 | emitCss: true, 34 | }), 35 | resolve({ 36 | browser: true, 37 | dedupe: ["svelte"], 38 | }), 39 | commonjs(), 40 | 41 | !dev && 42 | terser({ 43 | module: true, 44 | }), 45 | ], 46 | 47 | preserveEntrySignatures: false, 48 | onwarn, 49 | }, 50 | 51 | server: { 52 | input: config.server.input(), 53 | output: config.server.output(), 54 | plugins: [ 55 | replace({ 56 | "process.browser": false, 57 | "process.env.NODE_ENV": JSON.stringify(mode), 58 | }), 59 | svelte({ 60 | generate: "ssr", 61 | dev, 62 | }), 63 | resolve({ 64 | dedupe: ["svelte"], 65 | }), 66 | commonjs(), 67 | ], 68 | external: Object.keys(pkg.dependencies).concat(require("module").builtinModules || Object.keys(process.binding("natives"))), 69 | 70 | preserveEntrySignatures: "strict", 71 | onwarn, 72 | }, 73 | 74 | serviceworker: { 75 | input: config.serviceworker.input(), 76 | output: config.serviceworker.output(), 77 | plugins: [ 78 | resolve(), 79 | replace({ 80 | "process.browser": true, 81 | "process.env.NODE_ENV": JSON.stringify(mode), 82 | }), 83 | commonjs(), 84 | !dev && terser(), 85 | ], 86 | 87 | preserveEntrySignatures: false, 88 | onwarn, 89 | }, 90 | }; 91 | -------------------------------------------------------------------------------- /src/client.js: -------------------------------------------------------------------------------- 1 | import * as sapper from '@sapper/app'; 2 | 3 | sapper.start({ 4 | target: document.querySelector('#sapper') 5 | }); -------------------------------------------------------------------------------- /src/components/Footer.svelte: -------------------------------------------------------------------------------- 1 | 32 | 33 | 202 | -------------------------------------------------------------------------------- /src/components/LangSelect.svelte: -------------------------------------------------------------------------------- 1 | 67 | 68 | 69 | 70 | 71 | 125 | 126 | 201 | -------------------------------------------------------------------------------- /src/components/Logo.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 |
7 | 36 | PATTERN MONSTER 37 |
38 | -------------------------------------------------------------------------------- /src/components/Nav.svelte: -------------------------------------------------------------------------------- 1 | 116 | 117 | 118 | 140 | 141 | 296 | -------------------------------------------------------------------------------- /src/components/ShinyButton.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 | {strings.upgradePro} 12 | 13 | 50 | -------------------------------------------------------------------------------- /src/components/SimpleAutocomplete.svelte: -------------------------------------------------------------------------------- 1 | 560 | 561 | 719 | 720 |
724 | 741 | {#if showClear}{/if} 742 | 766 |
767 | 768 | 769 | -------------------------------------------------------------------------------- /src/components/StickyFooter.svelte: -------------------------------------------------------------------------------- 1 | 43 | 44 |
45 |
46 | {link.prefix} 47 | {link.title} 53 | 54 | {link.suffix} 55 |
56 |
57 | -------------------------------------------------------------------------------- /src/css/global.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --main-bg-color: rgb(42, 42, 48); 3 | --accent-color: #44337a; 4 | --pattern-bg: rgb(235, 235, 235); 5 | --card-bg: rgb(245, 245, 245); 6 | --input-bg: #ffffff; 7 | --secondary-color: #ffc800; 8 | --accent-text: #805ad5; 9 | --accent-hover: #805ad5aa; 10 | --accent-text-color: #ffffff; 11 | --secondary-text-color: #000000; 12 | --accent-color-hover: rgba(68, 51, 122, 0.8); 13 | --secondary-color-hover: rgba(255, 200, 0, 0.8); 14 | --border-radius: 4px; 15 | --blockquote-color: 103, 106, 109; 16 | --gray-300: #e2e8f0; 17 | --gray-400: #cbd5e0; 18 | --gray-500: #a0aec0; 19 | --gray-600: #718096; 20 | --gray-700: #4a5568; 21 | --gray-800: #2d3748; 22 | --gray-900: #1a202c; 23 | --font: "Nunito", sans-serif; 24 | /* --defaultFont: -apple-system,BlinkMacSystemFont,SFUI,HelveticaNeue,Helvetica,Arial,sans-serif; */ 25 | --svg-bg: white; 26 | --gray-bg: var(--gray-400); 27 | --gray-text: var(--gray-600); 28 | --input-background: url("data:image/svg+xml;charset=US-ASCII,"), 29 | linear-gradient(to bottom, var(--card-bg) 0%, var(--card-bg) 100%); 30 | /* --list-background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' class='icon icon-tabler icon-tabler-checkbox' width='1.5em' height='2em' viewBox='0 0 24 24' stroke-width='1.5' stroke='%231a202c' fill='none' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath stroke='none' d='M0 0h24v24H0z' fill='none'/%3E%3Cpolyline points='9 11 12 14 20 6' /%3E%3Cpath d='M20 12v6a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2v-12a2 2 0 0 1 2 -2h9' /%3E%3C/svg%3E"); */ 31 | /* --shop-gradient: linear-gradient(-45deg, #805ad5, #e91e63, #03a9f4, #ecc94b); */ 32 | 33 | --notification-list-padding: 0.5em 1em 0.5em 2.5em; 34 | --notification-header-padding: 1.5em 1em 0.5em 1.5em; 35 | --notification-header-margin: 1em -0.8em 0 -2.5em; 36 | } 37 | [data-theme="dark"] { 38 | --pattern-bg: rgb(24, 24, 30); 39 | --card-bg: rgb(42, 42, 48); 40 | --input-bg: rgb(62, 62, 48); 41 | --accent-text-color: #000000; 42 | --secondary-text-color: #ffffff; 43 | --accent-text: #ecc94b; 44 | --accent-hover: #ecc94baa; 45 | --svg-bg: rgb(42, 42, 48); 46 | --gray-bg: var(--gray-700); 47 | --gray-text: var(--gray-500); 48 | --blockquote-color: 148, 146, 143; 49 | --input-background: url("data:image/svg+xml;charset=US-ASCII,"), 50 | linear-gradient(to bottom, var(--card-bg) 0%, var(--card-bg) 100%); 51 | /* --list-background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' class='icon icon-tabler icon-tabler-checkbox' width='1.5em' height='2em' viewBox='0 0 24 24' stroke-width='1.5' stroke='%23f7fafc' fill='none' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath stroke='none' d='M0 0h24v24H0z' fill='none'/%3E%3Cpolyline points='9 11 12 14 20 6' /%3E%3Cpath d='M20 12v6a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2v-12a2 2 0 0 1 2 -2h9' /%3E%3C/svg%3E"); */ 52 | /* --shop-gradient: linear-gradient(-45deg, #ecc94b, #f44336, #00bcd4, #805ad5); */ 53 | } 54 | 55 | [dir="rtl"] { 56 | --notification-list-padding: 0.5em 2.5em 0.5em 1em; 57 | --notification-header-padding: 1.5em 1.5em 0.5em 1em; 58 | --notification-header-margin: 1em -2.5em 0 -0.8em; 59 | } 60 | 61 | *, 62 | ::after, 63 | ::before { 64 | box-sizing: border-box; 65 | border-width: 0; 66 | border-style: solid; 67 | border-color: var(--accent-color); 68 | } 69 | img, 70 | video { 71 | max-width: 100%; 72 | height: auto; 73 | } 74 | 75 | audio, 76 | canvas, 77 | embed, 78 | iframe, 79 | img, 80 | object, 81 | svg, 82 | video { 83 | display: block; 84 | /* vertical-align: middle; */ 85 | } 86 | 87 | @font-face { 88 | font-family: Coffee; 89 | src: local("Coffee"), local("coffee"), 90 | url("https://giguom.com/pattern.monster/fonts/coffeefont.ttf"); 91 | font-weight: normal; 92 | font-display: swap; 93 | } 94 | 95 | .coffee { 96 | font-family: Coffee, "Arial Narrow Bold", sans-serif; 97 | margin-left: 0.6rem; 98 | font-size: 0.9rem; 99 | font-weight: 500; 100 | color: white; 101 | } 102 | 103 | html { 104 | /* font-family: Roboto, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; */ 105 | font-family: var(--font); 106 | font-display: swap; 107 | } 108 | 109 | body { 110 | background-color: var(--main-bg-color); 111 | margin: 0; 112 | line-height: 1.5; 113 | /* background-color: #545454; */ 114 | color: var(--accent-color); 115 | font-size: 19px; 116 | } 117 | .closed { 118 | display: none; 119 | } 120 | 121 | h1 { 122 | /* font-size: 2em; */ 123 | font-weight: 400; 124 | /* line-height: 1.2; */ 125 | /* color: var(--secondary-color); */ 126 | font-size: 3.2em; 127 | margin-top: 0.5rem; 128 | line-height: 1em; 129 | } 130 | h1 > span { 131 | color: var(--accent-text); 132 | } 133 | 134 | h2, 135 | h3, 136 | h4, 137 | h5, 138 | h6 { 139 | font-weight: 700; 140 | line-height: 1.2; 141 | } 142 | 143 | h2 { 144 | font-size: 1.6em; 145 | color: var(--dark-text); 146 | margin-bottom: 0.5rem; 147 | } 148 | 149 | a { 150 | color: inherit; 151 | /* text-decoration: inherit; */ 152 | text-decoration: none; 153 | } 154 | 155 | a:hover { 156 | color: var(--secondary-color); 157 | } 158 | 159 | input { 160 | font-family: var(--font); 161 | font-display: swap; 162 | background-color: var(--input-bg); 163 | } 164 | 165 | input[type="number"] { 166 | /* color: var(--pattern-bg); */ 167 | color: var(--secondary-text-color); 168 | /* border-color: rgb(159,122,234); */ 169 | line-height: 1.25; 170 | padding: 0.5rem; 171 | font-size: 1rem; 172 | width: 80px; 173 | -webkit-appearance: textfield; 174 | -moz-appearance: textfield; /* Hide arrows for input number - Firefox */ 175 | appearance: textfield; 176 | border-radius: var(--border-radius); 177 | background-color: var(--gray-bg); 178 | } 179 | 180 | /* Hide arrows for input number - Chrome, Safari, Edge, Opera */ 181 | input::-webkit-outer-spin-button, 182 | input::-webkit-inner-spin-button { 183 | -webkit-appearance: none; 184 | margin: 0; 185 | } 186 | 187 | input[type="range"] { 188 | width: 100%; 189 | margin: 7.3px 0; 190 | background-color: transparent; 191 | -webkit-appearance: none; 192 | } 193 | input[type="range"]:focus { 194 | outline: none; 195 | } 196 | input[type="range"]::-webkit-slider-runnable-track { 197 | background: var(--accent-text); 198 | border-radius: var(--border-radius); 199 | width: 100%; 200 | height: 4px; 201 | cursor: pointer; 202 | } 203 | input[type="range"]::-moz-range-track { 204 | background: var(--accent-text); 205 | border-radius: var(--border-radius); 206 | width: 100%; 207 | height: 4px; 208 | cursor: pointer; 209 | } 210 | input[type="range"]:focus::-webkit-slider-runnable-track { 211 | background: var(--accent-hover); 212 | } 213 | input[type="range"]::-webkit-slider-thumb { 214 | margin-top: -10.5px; 215 | width: 28px; 216 | height: 28px; 217 | background: var(--pattern-bg); 218 | border: 4px solid var(--accent-text); 219 | border-radius: var(--border-radius); 220 | cursor: pointer; 221 | -webkit-appearance: none; 222 | } 223 | input[type="range"]::-moz-range-thumb { 224 | width: 20px; 225 | height: 20px; 226 | background: var(--pattern-bg); 227 | border: 4px solid var(--accent-text); 228 | border-radius: var(--border-radius); 229 | cursor: pointer; 230 | } 231 | 232 | button { 233 | display: inline-block; 234 | border: none; 235 | padding: 0.375rem 0.75rem; 236 | margin: 0; 237 | text-decoration: none; 238 | background-color: var(--secondary-color); 239 | border-radius: var(--border-radius); 240 | color: var(--main-bg-color); 241 | font-family: var(--font); 242 | font-display: swap; 243 | font-size: 1em; 244 | cursor: pointer; 245 | text-align: center; 246 | transition: background 250ms ease-in-out, transform 150ms ease; 247 | -webkit-appearance: none; 248 | -moz-appearance: none; 249 | appearance: none; 250 | } 251 | 252 | button:hover, 253 | button:focus { 254 | background-color: var(--secondary-color-hover); 255 | } 256 | 257 | button:focus { 258 | outline: 1px solid #fff; 259 | /* outline-offset: -4px; */ 260 | } 261 | 262 | button:active { 263 | transform: scale(0.99); 264 | } 265 | 266 | .accent-text { 267 | color: var(--accent-color); 268 | } 269 | 270 | .secondary-text { 271 | color: var(--secondary-color); 272 | } 273 | .accent-bg { 274 | background-color: var(--accent-color); 275 | } 276 | .secondary-bg { 277 | background-color: var(--secondary-color); 278 | } 279 | .main-bg { 280 | background-color: var(--main-bg-color); 281 | } 282 | .light-text { 283 | color: var(--gray-300); 284 | } 285 | .dark-text { 286 | color: var(--gray-900); 287 | } 288 | .gray-text { 289 | color: var(--gray-text); 290 | } 291 | .white-text { 292 | color: white; 293 | } 294 | .secondary-text-color { 295 | color: var(--secondary-text-color); 296 | } 297 | .pattern-bg { 298 | background-color: var(--pattern-bg); 299 | } 300 | .secondary-link { 301 | color: var(--secondary-color); 302 | } 303 | .secondary-link:hover { 304 | color: var(--secondary-color-hover); 305 | } 306 | 307 | /* Tailwind Utilities */ 308 | .p-0 { 309 | padding: 0; 310 | } 311 | .p-2 { 312 | padding: 0.5rem; 313 | } 314 | .p-4 { 315 | padding: 1rem; 316 | } 317 | .p-5 { 318 | padding: 1.25rem; 319 | } 320 | .p-6 { 321 | padding: 1.5rem; 322 | } 323 | .p-8 { 324 | padding: 2rem; 325 | } 326 | .pt-2 { 327 | padding-top: 0.5rem; 328 | } 329 | .pt-12 { 330 | padding-top: 3rem; 331 | } 332 | .pt-20 { 333 | padding-top: 4rem; 334 | } 335 | .pb-4 { 336 | padding-bottom: 1rem; 337 | } 338 | .pb-5 { 339 | padding-bottom: 1.25rem; 340 | } 341 | .pb-6 { 342 | padding-bottom: 1.5rem; 343 | } 344 | .pb-20 { 345 | padding-bottom: 4rem; 346 | } 347 | .px-4 { 348 | padding-left: 1rem; 349 | padding-right: 1rem; 350 | } 351 | .px-5 { 352 | padding-left: 1.25rem; 353 | padding-right: 1.25rem; 354 | } 355 | .px-6 { 356 | padding-left: 1.5rem; 357 | padding-right: 1.5rem; 358 | } 359 | .py-3 { 360 | padding-top: 0.75rem; 361 | padding-bottom: 0.75rem; 362 | } 363 | .py-24 { 364 | padding-top: 6rem; 365 | padding-bottom: 6rem; 366 | } 367 | .mr-5 { 368 | margin-right: 1.25rem; 369 | } 370 | .mt-0 { 371 | margin-top: 0; 372 | } 373 | .mt-2 { 374 | margin-top: 0.5rem; 375 | } 376 | .mt-6 { 377 | margin-top: 1.5rem; 378 | } 379 | .mt-12 { 380 | margin-top: 3rem; 381 | } 382 | .mb-2 { 383 | margin-bottom: 0.5rem; 384 | } 385 | .mb-4 { 386 | margin-bottom: 1rem; 387 | } 388 | .mx-3 { 389 | margin-left: 0.75rem; 390 | margin-right: 0.75rem; 391 | } 392 | .-mx-8 { 393 | margin-left: -2rem; 394 | margin-right: -2rem; 395 | } 396 | .-mx-3 { 397 | margin-left: -0.75rem; 398 | margin-right: -0.75rem; 399 | } 400 | .mx-auto { 401 | margin-left: auto; 402 | margin-right: auto; 403 | } 404 | .my-2 { 405 | margin-top: 0.5rem; 406 | margin-bottom: 0.5rem; 407 | } 408 | .gap-2 { 409 | gap: 0.5rem; 410 | } 411 | .gap-4 { 412 | gap: 1rem; 413 | } 414 | .gap-6 { 415 | gap: 1.5rem; 416 | } 417 | .font-semibold { 418 | font-weight: 600; 419 | } 420 | .font-normal { 421 | font-weight: 400; 422 | } 423 | .text-center { 424 | text-align: center; 425 | } 426 | .text-start { 427 | text-align: start; 428 | } 429 | .text-end { 430 | text-align: end; 431 | } 432 | .text-sm { 433 | font-size: 0.85em; 434 | } 435 | 436 | .test-xl { 437 | font-size: 1.25rem /* 20px */; 438 | line-height: 1.75rem /* 28px */; 439 | } 440 | 441 | .text-4xl { 442 | font-size: 2em; 443 | } 444 | .uppercase { 445 | text-transform: uppercase; 446 | } 447 | .tracking-wider { 448 | letter-spacing: 0.05em; 449 | } 450 | .container { 451 | max-width: 1280px; 452 | } 453 | .flex { 454 | display: flex; 455 | } 456 | .flex-wrap { 457 | flex-wrap: wrap; 458 | } 459 | .grid { 460 | display: grid; 461 | } 462 | .grid-flow-col { 463 | grid-auto-flow: column; 464 | } 465 | .grid-flow-row { 466 | grid-auto-flow: row; 467 | } 468 | .items-center { 469 | align-items: center; 470 | } 471 | .justify-center { 472 | justify-content: center; 473 | } 474 | .justify-self-start { 475 | justify-self: start; 476 | } 477 | .justify-self-end { 478 | justify-self: end; 479 | } 480 | .place-content-start { 481 | place-content: start; 482 | } 483 | .place-content-center { 484 | place-content: center; 485 | } 486 | 487 | .text-balance { 488 | text-wrap: balance; 489 | } 490 | 491 | .capitalize { 492 | text-transform: capitalize; 493 | } 494 | .list-none { 495 | list-style-type: none; 496 | } 497 | .list-circle { 498 | list-style-type: circle; 499 | } 500 | .leading-loose { 501 | line-height: 2; 502 | } 503 | .bg-none { 504 | background-image: none; 505 | } 506 | .indent-0 { 507 | text-indent: 0; 508 | } 509 | .max-w-lg { 510 | max-width: 32rem; 511 | } 512 | 513 | .brandName { 514 | line-height: 1; 515 | } 516 | 517 | nav { 518 | position: sticky; 519 | top: 0; 520 | z-index: 5; 521 | background-color: var(--main-bg-color); 522 | height: 3.2em; 523 | font-weight: 300; 524 | padding: 0.4em 1em; 525 | display: grid; 526 | grid-auto-flow: column; 527 | grid-template-columns: 1fr auto; 528 | /* gap: 1em; */ 529 | align-items: center; 530 | font-size: 0.9em; 531 | place-content: center; 532 | } 533 | 534 | .rightLinks { 535 | gap: 0.5em; 536 | } 537 | 538 | nav > a, 539 | .rightLinks a:not(.bmc), 540 | .iconButton { 541 | padding: 0.5em 0.8em; 542 | } 543 | 544 | .iconButton { 545 | background-color: transparent; 546 | } 547 | 548 | nav > a:hover, 549 | .rightLinks a:hover:not(.shiny), 550 | .rightLinks a:focus:not(.shiny), 551 | .rightLinks a:active:not(.shiny), 552 | .iconButton:hover, 553 | .iconButton:focus, 554 | .iconButton:active { 555 | border-radius: var(--border-radius); 556 | background-color: var(--gray-800); 557 | } 558 | 559 | .logo, 560 | .logoHome { 561 | display: grid; 562 | grid-template-columns: auto 1fr; 563 | gap: 1rem; 564 | align-items: center; 565 | font-weight: 700; 566 | letter-spacing: 0.05em; 567 | font-size: 1em; 568 | } 569 | 570 | .logoHome { 571 | padding-top: 2rem; 572 | padding-bottom: 1rem; 573 | } 574 | 575 | .icon { 576 | width: 1.5em; 577 | height: 1.5em; 578 | stroke: currentColor; 579 | stroke-width: 1.5; 580 | stroke-linecap: round; 581 | stroke-linejoin: round; 582 | fill: none; 583 | } 584 | nav button { 585 | color: var(--secondary-color); 586 | background-color: transparent; 587 | padding: 0.25em; 588 | } 589 | nav button:hover { 590 | background-color: transparent; 591 | } 592 | 593 | [aria-current] { 594 | position: relative; 595 | display: inline-block; 596 | } 597 | 598 | [aria-current]::after { 599 | position: absolute; 600 | content: ""; 601 | width: calc(100% - 1em); 602 | display: block; 603 | bottom: -1px; 604 | } 605 | 606 | nav a { 607 | text-decoration: none; 608 | /* padding: 1em 0.5em; */ 609 | display: block; 610 | color: var(--secondary-color); 611 | } 612 | 613 | .logoOuter { 614 | /* display: grid; */ 615 | grid-auto-flow: column; 616 | /* align-items: center; */ 617 | justify-content: start; 618 | gap: 0.75em; 619 | padding: 0 0.8em; 620 | } 621 | 622 | .gitHubIcon, 623 | .bellIcon { 624 | position: relative; 625 | padding-right: 0.8em; 626 | } 627 | .bellIcon { 628 | padding-left: 0.8em; 629 | margin-left: -0.8em; 630 | } 631 | .dropDownName { 632 | display: inline; 633 | } 634 | 635 | .starsCount, 636 | .bellCount { 637 | position: absolute; 638 | font-size: 0.75em; 639 | font-weight: 600; 640 | line-height: 1; 641 | top: -0.3em; 642 | right: 0; 643 | color: var(--main-bg-color); 644 | background-color: var(--secondary-color); 645 | border-radius: var(--border-radius); 646 | padding: 0.25em 0.25em 0.1em; 647 | } 648 | 649 | .bellCount { 650 | color: white; 651 | background-color: red; 652 | right: 0.9em; 653 | } 654 | 655 | .notifications { 656 | /* font-family: var(--defaultFont); */ 657 | z-index: 20; 658 | display: none; 659 | /* width: min(80vw, 360px); */ 660 | width: 80vw; 661 | max-width: 360px; 662 | top: 4.2em; 663 | position: fixed; 664 | font-size: 0.85em; 665 | border: 1px solid var(--accent-text); 666 | box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); 667 | -webkit-background-clip: padding-box; 668 | background-clip: padding-box; 669 | color: var(--secondary-text-color); 670 | border-radius: var(--border-radius); 671 | overflow: hidden; 672 | box-shadow: 0 10px 15px -3px rgb(0 0 0 / 10%), 0 4px 6px -2px rgb(0 0 0 / 5%); 673 | /* --tw-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); 674 | --tw-ring-offset-shadow: 0 0 #0000; 675 | box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); */ 676 | } 677 | .notifications h3 { 678 | background-color: var(--accent-text); 679 | color: var(--accent-text-color); 680 | padding: 0.7em 1em; 681 | margin: 0; 682 | } 683 | 684 | .notifications a { 685 | display: inline; 686 | color: var(--accent-text); 687 | text-underline-offset: 0.15em; 688 | text-decoration: underline; 689 | text-decoration-thickness: 0.15em; 690 | } 691 | 692 | .notifications a:hover { 693 | color: var(--accent-hover); 694 | } 695 | 696 | .viewLink { 697 | margin: 0; 698 | background-color: var(--card-bg); 699 | padding-top: 0.5em; 700 | } 701 | .viewLink a { 702 | text-decoration: none; 703 | display: grid; 704 | grid-auto-flow: column; 705 | place-content: start; 706 | border-top: 1px solid var(--gray-text); 707 | padding: 1.25em 1em; 708 | gap: 0.5em; 709 | font-size: 1.1em; 710 | } 711 | .notifications ul { 712 | padding: var(--notification-list-padding); 713 | overflow: auto; 714 | max-height: 65vh; 715 | margin: 0; 716 | background-color: var(--card-bg); 717 | } 718 | .notifications li { 719 | padding-bottom: 0.5em; 720 | color: var(--gray-text); 721 | } 722 | .notifications li.versionHeader { 723 | list-style: none; 724 | margin: var(--notification-header-margin); 725 | font-weight: 600; 726 | border-top: 1px solid var(--gray-text); 727 | padding: var(--notification-header-padding); 728 | font-size: 1.1em; 729 | color: var(--secondary-text-color); 730 | } 731 | .notifications li:first-child { 732 | margin-top: 0; 733 | border-top: 0; 734 | padding-top: 1em; 735 | } 736 | 737 | button.bellIcon:focus, 738 | button.bellIcon:hover, 739 | button.bellIcon:active { 740 | background-color: transparent; 741 | } 742 | 743 | /* Footer */ 744 | 745 | .footerOuter { 746 | font-size: 0.9em; 747 | grid-template-columns: 1fr; 748 | background-color: var(--main-bg-color); 749 | } 750 | 751 | .bmcCta { 752 | margin: 0.5em 0.5em 1em; 753 | justify-self: center; 754 | } 755 | 756 | .bmc:hover, 757 | .bmcCta:hover, 758 | .bmc:focus, 759 | .bmcCta:focus, 760 | .shiny:hover, 761 | .shiny:focus { 762 | opacity: 0.85; 763 | } 764 | 765 | /* @media (min-width: 768px) { 766 | .footerOuter { 767 | grid-template-columns: 0 1fr 1fr; 768 | } 769 | } */ 770 | 771 | /* Changelog */ 772 | 773 | #logs > li > a { 774 | color: var(--accent-text); 775 | border-bottom: 2px solid var(--accent-text); 776 | padding-bottom: 0.125em; 777 | } 778 | 779 | #logs > li > a:hover { 780 | color: var(--accent-hover); 781 | border-bottom: 2px solid var(--accent-hover); 782 | } 783 | 784 | @media (max-width: 1440px) { 785 | body { 786 | font-size: 18px; 787 | } 788 | } 789 | 790 | @media (max-width: 1280px) { 791 | .container { 792 | max-width: 1024px; 793 | } 794 | .logoHome { 795 | padding-top: 2rem; 796 | } 797 | } 798 | 799 | @media (max-width: 1024px) { 800 | .container { 801 | max-width: 768px; 802 | } 803 | .bmc { 804 | display: none; 805 | } 806 | } 807 | 808 | @media (max-width: 768px) { 809 | body { 810 | font-size: 16px; 811 | } 812 | .container { 813 | max-width: 640px; 814 | } 815 | nav { 816 | padding: 0.6em 0.5em; 817 | } 818 | 819 | .logo, 820 | .logoHome { 821 | justify-self: center; 822 | } 823 | } 824 | 825 | @media (max-width: 640px) { 826 | .container { 827 | width: 100%; 828 | } 829 | .tweetNav { 830 | display: none; 831 | } 832 | .downloadsButton, 833 | .gitHubIcon, 834 | .dropDownName { 835 | display: none; 836 | } 837 | } 838 | 839 | @media (max-width: 450px) { 840 | nav { 841 | padding: 0.3em 0.5em; 842 | } 843 | 844 | nav > a, 845 | .rightLinks a:not(.bmc), 846 | .iconButton { 847 | padding: 0.3em 0.8em; 848 | } 849 | } 850 | 851 | @media (max-width: 420px) { 852 | .brandName { 853 | display: none; 854 | } 855 | } 856 | 857 | .block { 858 | display: block; 859 | } 860 | .inline-block { 861 | display: inline-block; 862 | } 863 | @media (min-width: 768px) { 864 | .md\:.grid-flow-col { 865 | grid-auto-flow: column; 866 | } 867 | } 868 | 869 | @media (min-width: 1024px) { 870 | .lg\:hidden { 871 | display: none; 872 | } 873 | } 874 | 875 | .brightgreen { 876 | background-color: #34d399; 877 | color: rgba(0, 0, 0, 0.8); 878 | } 879 | .green { 880 | background-color: #bef264; 881 | color: rgba(0, 0, 0, 0.8); 882 | } 883 | .yellow { 884 | background-color: #facc15; 885 | color: rgba(0, 0, 0, 0.8); 886 | } 887 | .orange { 888 | background-color: #f97316; 889 | color: rgba(255, 255, 255, 0.8); 890 | } 891 | .red { 892 | background-color: #ef4444; 893 | color: rgba(255, 255, 255, 0.8); 894 | } 895 | .langOuter { 896 | display: inline-grid; 897 | grid-auto-flow: column; 898 | font-size: 0.75em; 899 | place-content: start; 900 | justify-items: center; 901 | letter-spacing: 0.05em; 902 | color: #fff; 903 | font-weight: 600; 904 | font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, 905 | sans-serif, Apple Color Emoji, Segoe UI Emoji; 906 | margin: 0.45em; 907 | cursor: pointer; 908 | } 909 | .langOuter:active, 910 | .langOuter:hover, 911 | .langOuter:visited { 912 | color: #fff; 913 | } 914 | .langOuter > span:first-child { 915 | padding: 1px 6px; 916 | border-radius: 4px 0 0 4px; 917 | background-color: #555; 918 | } 919 | .langOuter > span:last-child { 920 | padding: 1px 6px; 921 | border-radius: 0 4px 4px 0; 922 | } 923 | 924 | /* .alert { 925 | background: var(--shop-gradient); 926 | background-size: 400% 400%; 927 | animation: gradient 10s ease infinite; 928 | margin: 0 auto; 929 | place-content: center; 930 | display: flex; 931 | border-radius: var(--border-radius); 932 | color: var(--secondary-text-color); 933 | } */ 934 | 935 | /* @keyframes gradient { 936 | 0% { 937 | background-position: 0% 50%; 938 | } 939 | 50% { 940 | background-position: 100% 50%; 941 | } 942 | 100% { 943 | background-position: 0% 50%; 944 | } 945 | } */ 946 | /* .shopFeatures { 947 | padding-inline-start: 1.5em; 948 | } 949 | .shopFeatures li { 950 | list-style: none; 951 | position: relative; 952 | padding: var(--list-style-padding); 953 | } 954 | 955 | .shopFeatures li::before { 956 | content: "-"; 957 | position: absolute; 958 | top: 0; 959 | left: var(--list-style-before-left); 960 | right: var(--list-style-before-right); 961 | } 962 | .shop-button { 963 | display: inline-block; 964 | background-color: transparent; 965 | border: 0.125em solid var(--gray-text); 966 | color: var(--gray-text); 967 | padding: 0.375rem 0.75rem; 968 | margin: 0.3em; 969 | } 970 | .shop-button:hover { 971 | border: 0.125em solid var(--secondary-text-color); 972 | color: var(--secondary-text-color); 973 | } */ 974 | 975 | /* Scrollbar */ 976 | @media (pointer: fine) { 977 | * { 978 | scrollbar-width: auto; 979 | scrollbar-color: rgba(var(--blockquote-color), 0.5) 980 | rgba(var(--blockquote-color), 0.2); 981 | } 982 | 983 | ::-webkit-scrollbar { 984 | height: 14px; 985 | width: 14px; 986 | } 987 | 988 | ::-webkit-scrollbar-track { 989 | background-color: rgba(var(--blockquote-color), 0.2); 990 | } 991 | 992 | ::-webkit-scrollbar-thumb { 993 | background-color: rgba(var(--blockquote-color), 0.5); 994 | } 995 | } 996 | 997 | @keyframes gradient { 998 | 0% { 999 | background-position: 0% 50%; 1000 | } 1001 | 50% { 1002 | background-position: 100% 50%; 1003 | } 1004 | 100% { 1005 | background-position: 0% 50%; 1006 | } 1007 | } 1008 | .bottomSticky { 1009 | --sticky-gradient: linear-gradient(-45deg, #86efac, #67e8f9, #a5b4fc); 1010 | position: sticky; 1011 | bottom: 0; 1012 | right: 0; 1013 | left: 0; 1014 | background: var(--sticky-gradient); 1015 | background-size: 400% 400%; 1016 | animation: gradient 10s ease infinite; 1017 | font-size: 0.8em; 1018 | padding: 0.5em; 1019 | display: flex; 1020 | } 1021 | .bottomSticky div { 1022 | place-content: center; 1023 | align-items: center; 1024 | margin: 0 auto; 1025 | } 1026 | .bottomSticky a { 1027 | color: black; 1028 | font-weight: 700; 1029 | text-underline-offset: 0.2em; 1030 | text-decoration: underline; 1031 | text-decoration-thickness: 0.15em; 1032 | } 1033 | -------------------------------------------------------------------------------- /src/css/pickr.css: -------------------------------------------------------------------------------- 1 | /*! Pickr 1.7.2 MIT | https://github.com/Simonwep/pickr */ 2 | .pickr { 3 | position: relative; 4 | overflow: visible; 5 | transform: translateY(0); 6 | } 7 | .pickr * { 8 | box-sizing: border-box; 9 | outline: none; 10 | border: none; 11 | -webkit-appearance: none; 12 | -moz-appearance: none; 13 | appearance: none; 14 | } 15 | .pickr .pcr-button { 16 | position: relative; 17 | height: 3em; 18 | width: 3em; 19 | padding: 0.5em; 20 | cursor: pointer; 21 | border: 2px solid var(--secondary-text-color); 22 | /* font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, sans-serif; */ 23 | border-radius: 0.15em; 24 | background: url('data:image/svg+xml;utf8, ') 25 | no-repeat 50%; 26 | color: var(--pcr-color); 27 | background-size: 0; 28 | transition: all 0.3s; 29 | } 30 | .pickr .pcr-button:before { 31 | background: url('data:image/svg+xml;utf8, '); 32 | background-size: 0.5em; 33 | z-index: -1; 34 | z-index: auto; 35 | } 36 | .pickr .pcr-button:after, 37 | .pickr .pcr-button:before { 38 | position: absolute; 39 | content: ""; 40 | top: 0; 41 | left: 0; 42 | width: 100%; 43 | height: 100%; 44 | border-radius: 0.15em; 45 | } 46 | .pickr .pcr-button:after { 47 | transition: background 0.3s; 48 | background: currentColor; 49 | } 50 | .pickr .pcr-button.clear { 51 | background-size: 70%; 52 | } 53 | .pickr .pcr-button.clear:before { 54 | opacity: 0; 55 | } 56 | .pickr .pcr-button.clear:focus { 57 | box-shadow: 0 0 0 1px hsla(0, 0%, 100%, 0.85), 0 0 0 3px currentColor; 58 | } 59 | .pickr .pcr-button.disabled { 60 | cursor: not-allowed; 61 | } 62 | .pcr-app *, 63 | .pickr * { 64 | box-sizing: border-box; 65 | outline: none; 66 | border: none; 67 | -webkit-appearance: none; 68 | -moz-appearance: none; 69 | appearance: none; 70 | } 71 | .pcr-app button.pcr-active, 72 | .pcr-app button:focus, 73 | .pcr-app input.pcr-active, 74 | .pcr-app input:focus, 75 | .pickr button.pcr-active, 76 | .pickr button:focus, 77 | .pickr input.pcr-active, 78 | .pickr input:focus { 79 | box-shadow: 0 0 0 1px hsla(0, 0%, 100%, 0.85), 0 0 0 3px currentColor; 80 | } 81 | .pcr-app .pcr-palette, 82 | .pcr-app .pcr-slider, 83 | .pickr .pcr-palette, 84 | .pickr .pcr-slider { 85 | transition: box-shadow 0.3s; 86 | } 87 | .pcr-app .pcr-palette:focus, 88 | .pcr-app .pcr-slider:focus, 89 | .pickr .pcr-palette:focus, 90 | .pickr .pcr-slider:focus { 91 | box-shadow: 0 0 0 1px hsla(0, 0%, 100%, 0.85), 0 0 0 3px rgba(0, 0, 0, 0.25); 92 | } 93 | .pcr-app { 94 | position: fixed; 95 | display: flex; 96 | flex-direction: column; 97 | z-index: 10000; 98 | border-radius: 0.1em; 99 | background: #fff; 100 | opacity: 0; 101 | visibility: hidden; 102 | transition: opacity 0.3s, visibility 0s 0.3s; 103 | font-family: inherit; 104 | /* font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, sans-serif; */ 105 | box-shadow: 0 0.15em 1.5em 0 rgba(0, 0, 0, 0.1), 0 0 1em 0 rgba(0, 0, 0, 0.03); 106 | left: 0; 107 | top: 0; 108 | } 109 | .pcr-app.visible { 110 | transition: opacity 0.3s; 111 | visibility: visible; 112 | opacity: 1; 113 | } 114 | .pcr-app .pcr-swatches { 115 | display: flex; 116 | flex-wrap: wrap; 117 | margin-top: 0.75em; 118 | } 119 | .pcr-app .pcr-swatches.pcr-last { 120 | margin: 0; 121 | } 122 | @supports (display: grid) { 123 | .pcr-app .pcr-swatches { 124 | display: grid; 125 | align-items: center; 126 | grid-template-columns: repeat(auto-fit, 1.75em); 127 | } 128 | } 129 | .pcr-app .pcr-swatches > button { 130 | font-size: 1em; 131 | position: relative; 132 | width: calc(1.75em - 5px); 133 | height: calc(1.75em - 5px); 134 | border-radius: 0.15em; 135 | /* cursor: pointer; */ 136 | padding: 0; 137 | margin: 2.5px; 138 | flex-shrink: 0; 139 | justify-self: center; 140 | transition: all 0.15s; 141 | overflow: hidden; 142 | background: transparent; 143 | z-index: 1; 144 | } 145 | .pcr-app .pcr-swatches > button:before { 146 | position: absolute; 147 | content: ""; 148 | top: 0; 149 | left: 0; 150 | width: 100%; 151 | height: 100%; 152 | background: url('data:image/svg+xml;utf8, '); 153 | background-size: 6px; 154 | border-radius: 0.15em; 155 | z-index: -1; 156 | } 157 | .pcr-app .pcr-swatches > button:after { 158 | content: ""; 159 | position: absolute; 160 | top: 0; 161 | left: 0; 162 | width: 100%; 163 | height: 100%; 164 | /* background: currentColor; */ 165 | background-color: var(--pcr-color); 166 | border: 1px solid rgba(0, 0, 0, 0.05); 167 | border-radius: 0.15em; 168 | box-sizing: border-box; 169 | } 170 | .pcr-app .pcr-swatches > button:hover { 171 | -webkit-filter: brightness(1.05); 172 | filter: brightness(1.05); 173 | } 174 | .pcr-app .pcr-swatches > button:not(.pcr-active) { 175 | box-shadow: none; 176 | } 177 | .pcr-app .pcr-interaction { 178 | display: flex; 179 | flex-wrap: wrap; 180 | align-items: center; 181 | margin: 0 -0.2em; 182 | } 183 | .pcr-app .pcr-interaction > * { 184 | margin: 0 0.2em; 185 | } 186 | .pcr-app .pcr-interaction input { 187 | letter-spacing: 0.07em; 188 | font-size: 0.75em; 189 | text-align: center; 190 | cursor: pointer; 191 | color: #75797e; 192 | background: #f1f3f4; 193 | border-radius: 0.15em; 194 | transition: all 0.15s; 195 | padding: 0.45em 0.5em; 196 | margin-top: 0.75em; 197 | } 198 | .pcr-app .pcr-interaction input:hover { 199 | -webkit-filter: brightness(0.975); 200 | filter: brightness(0.975); 201 | } 202 | .pcr-app .pcr-interaction input:focus { 203 | box-shadow: 0 0 0 1px hsla(0, 0%, 100%, 0.85), 0 0 0 3px rgba(66, 133, 244, 0.75); 204 | } 205 | .pcr-app .pcr-interaction .pcr-result { 206 | color: #75797e; 207 | text-align: left; 208 | flex: 1 1 8em; 209 | min-width: 8em; 210 | width: 100%; 211 | transition: all 0.2s; 212 | border-radius: 0.15em; 213 | background: #f1f3f4; 214 | cursor: text; 215 | } 216 | .pcr-app .pcr-interaction .pcr-result::-moz-selection { 217 | background: #4285f4; 218 | color: #fff; 219 | } 220 | .pcr-app .pcr-interaction .pcr-result::selection { 221 | background: #4285f4; 222 | color: #fff; 223 | } 224 | .pcr-app .pcr-interaction .pcr-type.active { 225 | color: #fff; 226 | background: #4285f4; 227 | } 228 | .pcr-app .pcr-interaction .pcr-cancel, 229 | .pcr-app .pcr-interaction .pcr-clear, 230 | .pcr-app .pcr-interaction .pcr-save { 231 | width: auto; 232 | color: #fff; 233 | } 234 | .pcr-app .pcr-interaction .pcr-cancel:hover, 235 | .pcr-app .pcr-interaction .pcr-clear:hover, 236 | .pcr-app .pcr-interaction .pcr-save:hover { 237 | -webkit-filter: brightness(0.925); 238 | filter: brightness(0.925); 239 | } 240 | .pcr-app .pcr-interaction .pcr-save { 241 | background: #4285f4; 242 | } 243 | .pcr-app .pcr-interaction .pcr-cancel, 244 | .pcr-app .pcr-interaction .pcr-clear { 245 | background: #f44250; 246 | } 247 | .pcr-app .pcr-interaction .pcr-cancel:focus, 248 | .pcr-app .pcr-interaction .pcr-clear:focus { 249 | box-shadow: 0 0 0 1px hsla(0, 0%, 100%, 0.85), 0 0 0 3px rgba(244, 66, 80, 0.75); 250 | } 251 | .pcr-interaction:first-child { 252 | width: 100%; 253 | } 254 | 255 | .pcr-interaction:not(:first-child) { 256 | flex: 1; 257 | } 258 | .pcr-app .pcr-selection .pcr-picker { 259 | position: absolute; 260 | height: 18px; 261 | width: 18px; 262 | border: 2px solid #fff; 263 | border-radius: 100%; 264 | -webkit-user-select: none; 265 | -moz-user-select: none; 266 | -ms-user-select: none; 267 | user-select: none; 268 | } 269 | .pcr-app .pcr-selection .pcr-color-chooser, 270 | .pcr-app .pcr-selection .pcr-color-opacity, 271 | .pcr-app .pcr-selection .pcr-color-palette { 272 | position: relative; 273 | -webkit-user-select: none; 274 | -moz-user-select: none; 275 | -ms-user-select: none; 276 | user-select: none; 277 | display: flex; 278 | flex-direction: column; 279 | cursor: -webkit-grab; 280 | cursor: grab; 281 | } 282 | .pcr-app .pcr-selection .pcr-color-chooser:active, 283 | .pcr-app .pcr-selection .pcr-color-opacity:active, 284 | .pcr-app .pcr-selection .pcr-color-palette:active { 285 | cursor: -webkit-grabbing; 286 | cursor: grabbing; 287 | } 288 | .pcr-app[data-theme="monolith"] { 289 | width: 14.25em; 290 | max-width: 95vw; 291 | padding: 0.8em; 292 | } 293 | .pcr-app[data-theme="monolith"] .pcr-selection { 294 | display: flex; 295 | flex-direction: column; 296 | justify-content: space-between; 297 | flex-grow: 1; 298 | } 299 | .pcr-app[data-theme="monolith"] .pcr-selection .pcr-color-preview { 300 | position: relative; 301 | z-index: 1; 302 | width: 100%; 303 | height: 1em; 304 | display: flex; 305 | flex-direction: row; 306 | justify-content: space-between; 307 | margin-bottom: 0.5em; 308 | } 309 | .pcr-app[data-theme="monolith"] .pcr-selection .pcr-color-preview:before { 310 | position: absolute; 311 | content: ""; 312 | top: 0; 313 | left: 0; 314 | width: 100%; 315 | height: 100%; 316 | background: url('data:image/svg+xml;utf8, '); 317 | background-size: 0.5em; 318 | border-radius: 0.15em; 319 | z-index: -1; 320 | } 321 | .pcr-app[data-theme="monolith"] .pcr-selection .pcr-color-preview .pcr-last-color { 322 | cursor: pointer; 323 | transition: background-color 0.3s, box-shadow 0.3s; 324 | border-radius: 0.15em 0 0 0.15em; 325 | z-index: 2; 326 | } 327 | .pcr-app[data-theme="monolith"] .pcr-selection .pcr-color-preview .pcr-current-color { 328 | border-radius: 0 0.15em 0.15em 0; 329 | } 330 | .pcr-app[data-theme="monolith"] .pcr-selection .pcr-color-preview .pcr-current-color, 331 | .pcr-app[data-theme="monolith"] .pcr-selection .pcr-color-preview .pcr-last-color { 332 | background: currentColor; 333 | width: 50%; 334 | height: 100%; 335 | } 336 | .pcr-app[data-theme="monolith"] .pcr-selection .pcr-color-palette { 337 | width: 100%; 338 | height: 8em; 339 | z-index: 1; 340 | } 341 | .pcr-app[data-theme="monolith"] .pcr-selection .pcr-color-palette .pcr-palette { 342 | border-radius: 0.15em; 343 | width: 100%; 344 | height: 100%; 345 | } 346 | .pcr-app[data-theme="monolith"] .pcr-selection .pcr-color-palette .pcr-palette:before { 347 | position: absolute; 348 | content: ""; 349 | top: 0; 350 | left: 0; 351 | width: 100%; 352 | height: 100%; 353 | background: url('data:image/svg+xml;utf8, '); 354 | background-size: 0.5em; 355 | border-radius: 0.15em; 356 | z-index: -1; 357 | } 358 | .pcr-app[data-theme="monolith"] .pcr-selection .pcr-color-chooser, 359 | .pcr-app[data-theme="monolith"] .pcr-selection .pcr-color-opacity { 360 | height: 0.5em; 361 | margin-top: 0.75em; 362 | } 363 | .pcr-app[data-theme="monolith"] .pcr-selection .pcr-color-chooser .pcr-picker, 364 | .pcr-app[data-theme="monolith"] .pcr-selection .pcr-color-opacity .pcr-picker { 365 | top: 50%; 366 | transform: translateY(-50%); 367 | } 368 | .pcr-app[data-theme="monolith"] .pcr-selection .pcr-color-chooser .pcr-slider, 369 | .pcr-app[data-theme="monolith"] .pcr-selection .pcr-color-opacity .pcr-slider { 370 | flex-grow: 1; 371 | border-radius: 50em; 372 | } 373 | .pcr-app[data-theme="monolith"] .pcr-selection .pcr-color-chooser .pcr-slider { 374 | background: linear-gradient(90deg, red, #ff0, #0f0, #0ff, #00f, #f0f, red); 375 | } 376 | .pcr-app[data-theme="monolith"] .pcr-selection .pcr-color-opacity .pcr-slider { 377 | background: linear-gradient(90deg, transparent, #000), 378 | url('data:image/svg+xml;utf8, '); 379 | background-size: 100%, 0.25em; 380 | } 381 | -------------------------------------------------------------------------------- /src/routes/[slug].json.js: -------------------------------------------------------------------------------- 1 | import patterns from './_index.js'; 2 | 3 | const lookup = new Map(); 4 | patterns.forEach(post => { 5 | lookup.set(post.slug, JSON.stringify(post)); 6 | }); 7 | 8 | export function get(req, res, next) { 9 | // the `slug` parameter is available because 10 | // this file is called [slug].json.js 11 | const { slug } = req.params; 12 | 13 | if (lookup.has(slug)) { 14 | res.writeHead(200, { 15 | 'Content-Type': 'application/json' 16 | }); 17 | 18 | res.end(lookup.get(slug)); 19 | } else { 20 | res.writeHead(404, { 21 | 'Content-Type': 'application/json' 22 | }); 23 | 24 | res.end(JSON.stringify({ 25 | message: `Not found` 26 | })); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/routes/_constants.js: -------------------------------------------------------------------------------- 1 | const strings = { 2 | website: "https://pattern.monster", 3 | title: "Pattern Monster", 4 | description: 5 | "A simple online pattern generator to create repeatable SVG patterns.", 6 | description2: "Speed up your website without compromising on image quality.", 7 | description3: 8 | "Perfect for website backgrounds, apparel, branding, packaging design and more.", 9 | keywords: 10 | "svg patterns, patterns, svg backgrounds, vector wallpaper, pattern generator, pattern maker", 11 | pages: [ 12 | { 13 | page: "index", 14 | title: "SVG Pattern Generator", 15 | keywords: "", 16 | description: "", 17 | image: "", 18 | }, 19 | { 20 | page: "changelog", 21 | title: "Changelog", 22 | keywords: "changelog", 23 | description: "Changelog for Pattern Monster.", 24 | image: "", 25 | }, 26 | { 27 | page: "downloads", 28 | title: "Downloads", 29 | keywords: "downloads", 30 | description: "Downloads for Pattern Monster.", 31 | image: "", 32 | }, 33 | { 34 | page: "features", 35 | title: "Features", 36 | keywords: "features", 37 | description: "Features for Pattern Monster.", 38 | image: "", 39 | }, 40 | { 41 | page: "privacy-policy", 42 | title: "Privacy Policy", 43 | keywords: "privacy policy", 44 | description: "Privacy Policy for Pattern Monster.", 45 | image: "", 46 | }, 47 | { 48 | page: "api", 49 | title: "API", 50 | keywords: "api", 51 | description: "API for Pattern Monster.", 52 | image: "", 53 | }, 54 | ], 55 | versions: [{"lang":"en","name":"English","website":"https://pattern.monster"},{"lang":"de","name":"Deutsch","website":"https://de.pattern.monster"},{"lang":"pl","name":"Polski","website":"https://pl.pattern.monster"},{"lang":"tr","name":"Türkçe","website":"https://tr.pattern.monster"},{"lang":"es","name":"Español","website":"https://es.pattern.monster"},{"lang":"it","name":"Italiano","website":"https://it.pattern.monster"},{"lang":"ro","name":"Română","website":"https://ro.pattern.monster"},{"lang":"fr","name":"Français","website":"https://fr.pattern.monster"},{"lang":"ar","name":"العربية","website":"https://ar.pattern.monster"},{"lang":"pt","name":"Português","website":"https://pt.pattern.monster"},{"lang":"zh-cn","name":"中文(简体)","website":"https://cn.pattern.monster"},{"lang":"nl","name":"Nederlands","website":"https://nl.pattern.monster"},{"lang":"sv","name":"Svenska","website":"https://sv.pattern.monster"},{"lang":"uk","name":"Українська","website":"https://uk.pattern.monster"},{"lang":"ru","name":"Русский","website":"https://ru.pattern.monster"},{"lang":"hu","name":"Magyar","website":"https://hu.pattern.monster"},{"lang":"af","name":"Afrikaans","website":"https://af.pattern.monster"},{"lang":"ca","name":"Català","website":"https://ca.pattern.monster"},{"lang":"zh-tw","name":"中文 (繁體)","website":"https://tw.pattern.monster"},{"lang":"cs","name":"Čeština","website":"https://cs.pattern.monster"},{"lang":"da","name":"Dansk","website":"https://da.pattern.monster"},{"lang":"fi","name":"Suomi","website":"https://fi.pattern.monster"},{"lang":"ja","name":"日本語","website":"https://ja.pattern.monster"},{"lang":"ko","name":"한국어","website":"https://ko.pattern.monster"}], 56 | langs:[{"id":"af","name":"Afrikaans","code":"af","translation":100,"approval":100},{"id":"ar","name":"Arabic","code":"ar","translation":100,"approval":100},{"id":"ca","name":"Catalan","code":"ca","translation":100,"approval":100},{"id":"zh-CN","name":"Chinese Simplified","code":"zh-cn","translation":100,"approval":100},{"id":"zh-TW","name":"Chinese Traditional","code":"zh-tw","translation":100,"approval":100},{"id":"cs","name":"Czech","code":"cs","translation":100,"approval":100},{"id":"da","name":"Danish","code":"da","translation":100,"approval":100},{"id":"nl","name":"Dutch","code":"nl","translation":100,"approval":100},{"id":"fi","name":"Finnish","code":"fi","translation":100,"approval":100},{"id":"fr","name":"French","code":"fr","translation":100,"approval":100},{"id":"de","name":"German","code":"de","translation":100,"approval":100},{"id":"el","name":"Greek","code":"el","translation":100,"approval":100},{"id":"he","name":"Hebrew","code":"he","translation":100,"approval":100},{"id":"hu","name":"Hungarian","code":"hu","translation":100,"approval":100},{"id":"id","name":"Indonesian","code":"id","translation":78,"approval":78},{"id":"it","name":"Italian","code":"it","translation":100,"approval":100},{"id":"ja","name":"Japanese","code":"ja","translation":100,"approval":100},{"id":"ko","name":"Korean","code":"ko","translation":100,"approval":100},{"id":"nb","name":"Norwegian Bokmal","code":"nb","translation":2,"approval":2},{"id":"nn-NO","name":"Norwegian Nynorsk","code":"nn-no","translation":2,"approval":2},{"id":"pl","name":"Polish","code":"pl","translation":100,"approval":100},{"id":"pt-PT","name":"Portuguese","code":"pt","translation":9,"approval":5},{"id":"pt-BR","name":"Portuguese, Brazilian","code":"pt-br","translation":100,"approval":100},{"id":"ro","name":"Romanian","code":"ro","translation":100,"approval":100},{"id":"ru","name":"Russian","code":"ru","translation":100,"approval":100},{"id":"sr","name":"Serbian (Cyrillic)","code":"sr","translation":2,"approval":2},{"id":"es-ES","name":"Spanish","code":"es","translation":100,"approval":100},{"id":"sv-SE","name":"Swedish","code":"sv","translation":100,"approval":100},{"id":"tr","name":"Turkish","code":"tr","translation":100,"approval":100},{"id":"uk","name":"Ukrainian","code":"uk","translation":100,"approval":100},{"id":"vi","name":"Vietnamese","code":"vi","translation":78,"approval":78}] 57 | }; 58 | 59 | const pageDetails = (page) => { 60 | let imagePrefix = "https://giguom.com/pattern.monster/images/"; 61 | let pageValues = 62 | strings.pages.filter((currentPage) => currentPage.page === page)[0] || 63 | strings.pages.filter((currentPage) => currentPage.page === "index")[0]; 64 | 65 | let website = strings.website; 66 | let title = strings.title + " - " + strings.pages[0].title; 67 | let url = website; 68 | let keywords = strings.keywords; 69 | let desc = strings.description + " " + strings.description3; 70 | let image = 71 | pageValues.image == "" ? imagePrefix + "/TwitterBG2.png" : pageValues.image; 72 | 73 | let versions = strings.versions.map((version) => { 74 | return { 75 | lang: version.lang, 76 | website: version.website + (page === "index" ? "" : "/" + page + "/"), 77 | }; 78 | }); 79 | 80 | if (page != "index") { 81 | title = 82 | pageValues.title + " - " + strings.title + " | " + strings.pages[0].title; 83 | url = website + "/" + page + "/"; 84 | desc = 85 | pageValues.description + 86 | " " + 87 | strings.description + 88 | " " + 89 | strings.description3; 90 | keywords = pageValues.keywords + ", " + strings.keywords; 91 | } 92 | 93 | return { title, url, keywords, desc, image, versions }; 94 | }; 95 | 96 | let lightColors = [ 97 | "hsla(0,0%,100%,1)", 98 | "hsla(258.5,59.4%,59.4%,1)", 99 | "hsla(339.6,82.2%,51.6%,1)", 100 | "hsla(198.7,97.6%,48.4%,1)", 101 | "hsla(47,80.9%,61%,1)", 102 | ]; 103 | let darkColors = [ 104 | "hsla(240,6.7%,17.6%,1)", 105 | "hsla(47,80.9%,61%,1)", 106 | "hsla(4.1,89.6%,58.4%,1)", 107 | "hsla(186.8,100%,41.6%,1)", 108 | "hsla(258.5,59.4%,59.4%,1)", 109 | ]; 110 | 111 | export default { strings, pageDetails, lightColors, darkColors }; 112 | -------------------------------------------------------------------------------- /src/routes/_error.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 | 30 | 31 | 32 | {status} 33 | 34 | 35 |

{status}

36 | 37 |

{error.message}

38 | 39 | {#if dev && error.stack} 40 |
{error.stack}
41 | {/if} 42 | -------------------------------------------------------------------------------- /src/routes/_lang.js: -------------------------------------------------------------------------------- 1 | const strings = {"searchPattern":"Search for patterns","pressFocus":"Press '/' to focus","title":"SVG Pattern Generator","heading":"Customizable SVG patterns for your projects","keywords":"svg patterns, patterns, svg backgrounds, vector wallpaper, pattern generator, pattern maker","patterns":"patterns","license":"MIT License","free":"Free","description":"A simple online pattern generator to create repeatable SVG patterns.","description2":"Speed up your website without compromising on image quality.","description3":"Perfect for website backgrounds, apparel, branding, packaging design and more.","filter":"Filter","sort":"Sort","filterMode":"Filter by Mode","filterColors":"Filter by Colors","allModes":"All modes","stroke":"Stroke","fill":"Fill","allColors":"All colors","colors":"colors","latest":"Latest","oldest":"Oldest","alphabetical":"Alphabetical","updateDate":"Updated Date","changeTheme":"Change Theme","changelog":"Changelog","features":"Features","downloads":"Downloads","translate":"Translate","privacy":"Privacy Policy","privacyFull":"This app does not collect or store any user data","signUp":"Sign up for project updates and get free patterns delivered monthly to your inbox","email":"Your email address","sendPatterns":"Send me the patterns","zoom":"Zoom","hSpacing":"Horizontal Spacing","vSpacing":"Vertical Spacing","hPosition":"Horizontal Position","vPosition":"Vertical Position","angle":"Angle","inspire":"Inspire Me","random":"Random Pattern","reset":"Reset","copy":"Copy","copyCSS":"Copy CSS","copySVG":"Copy SVG","download":"Download","downloadSVG":"Download as SVG file","downloadPNG":"Download as PNG file","dimensions":"Dimensions","width":"Width","height":"Height","hide":"Hide UI","lock":"Lock","unlock":"Unlock","checkOut":"If you love creating SVG patterns and backgrounds, you should check this out.","generate":"Generate fully customizable SVG patterns for free.","patternsCount":"300+ patterns available at https://pattern.monster","square":"Square","rounded":"Rounded","join":"Join Mode","tweet":"Share your tweet","waves":"Waves","chevron":"Chevron","straightLines":"Straight Lines","crossSection":"Cross Section","brickWall":"Brick Wall","herringbone":"Herringbone","flower":"Flower","plus":"Plus","circles":"Circles","concentricCircles":"Concentric Circles","adjointedCircles":"Adjointed Circles","adjointedDiamonds":"Adjointed Diamonds","diamonds":"Diamonds","hexagon":"Hexagon","overlappingHexagons":"Overlapping Hexagons","squaresSquares":"Squares & Squares","squaresDiamonds":"Squares & Diamonds","squaresCircles":"Squares & Circles","squaresPlus":"Squares & Plus","squaresStars":"Squares & Stars","starsLines":"Stars & Lines","triangles":"Triangles","invertedTriangles":"Inverted Triangles","checkerboard":"Checkerboard","japanesePattern":"Japanese Pattern","eyes":"Eyes","jigsaw":"Jigsaw","railroad":"Railroad","octagons":"Octagons","lines":"Lines","scales":"Scales","leaves":"Leaves","pipes":"Pipes","zebra":"Zebra","memphisPattern":"Memphis Pattern","greekKey":"Greek Key","chinesePattern":"Chinese Pattern","newPattern":"New Pattern","doubleBubble":"Double Bubble","stars":"Stars","semicircles":"Semicircles","songketPattern":"Songket Pattern","cubes":"Cubes","stainedGlass":"Stained Glass","tiles":"Tiles","rectanglesSquares":"Rectangles & Squares","mexicanPattern":"Mexican Pattern","ethnicPattern":"Ethnic Pattern","plaidPattern":"Plaid Pattern","doodlePattern":"Doodle Pattern","batikPattern":"Batik Pattern","curves":"Curves","rhombus":"Rhombus","stripes":"Stripes","squares":"Squares","clouds":"Clouds","africanPattern":"African Pattern","arabicPattern":"Arabic Pattern","abstractPattern":"Abstract Pattern","geometricPattern":"Geometric Pattern","tribalPattern":"Tribal Pattern","apiAccess":"Are you looking to integrate patterns with your new or existing projects? Be the first to know when API access opens up!","firstName":"First name","email2":"Email address","waitlist":"Join the waitlist","buyCoffee":"Buy me a coffee","openSource":"Open Source","feature1":"Create amazing SVG patterns in seconds","explore":"Explore patterns","feature2":"Handy tool for developers and designers.","feature3":"Unleash your creativity to produce visually stunning patterns.","tweak":"Tweak Colors","feature4":"Customize foreground and background colors easily","modify":"Modify Stroke","feature5":"Adjust the stroke width on supported patterns","alterAngle":"Alter Angle","feature6":"Change the angle to generate unique images","copyCode":"Copy Code","feature7":"Copy CSS and SVG code directly to your clipboard for web projects","downloadOptions":"Download Options","feature8":"Download a tileable SVG or a high resolution seamless PNG image for print","feature9":"Copy the pattern to set the website background with great results.","feature10":"Choose from a variety of patterns and shapes which cover a host of styles, from the cool, quirky and edgy, to the more luxurious designs.","feature11":"Make vector patterns like a pro","feature12":"A pattern maker app to create abstract and cool patterns.","feature13":"Save time by making royalty free SVG backgrounds for your projects.","feature14":"Easy to use tool to generate your desired image.","feature15":"Ideal for branding and logo design projects, business cards, creating custom tees and apparel, posters, flyers, web design projects, or your social media posts, Instagram stories and blogs.","knowMore":"Know more","feature16":"Create beautiful print assets from a wealth of versatile and useful patterns without any design skills.","feature17":"Ideal for branding projects, fabrics, packaging, fashion apparel, posters, wrapping paper, posters or calendars.","christmasTree":"Christmas Tree","candyCane":"Candy Cane","christmasBells":"Christmas Bells","christmasPattern":"Christmas Pattern","snowflakes":"Snowflakes","christmasTreeBalls":"Christmas Tree Balls","santaClaus":"Santa Claus","christmasGift":"Christmas Gift","blobs":"Blobs","viewMore":"View More","shop":"Shop","halloweenPattern":"Halloween Pattern","terrazzo":"Terrazzo","sprinkles":"Sprinkles","squiggle":"Squiggle","moroccanPattern":"Moroccan Pattern","interlockedHexagons":"Interlocked Hexagons","lanterns":"Lanterns","circlesDiamonds":"Circles & Diamonds","egyptianPattern":"Egyptian Pattern","squaresTriangles":"Squares & Triangles","rope":"Rope","circlesHexagons":"Circles & Hexagons","login":"Sign In","logout":"Sign Out","signInEmail":"Sign in with your email below","signInUpgrade":"Sign in to upgrade","checkEmail":"Check your email for the magic link","sendLink":"Send magic link","sending":"Sending","saving":"Saving","save":"Save","unlockPotential":"Unlock Your Potential","choosePlan":"Choose Your Plan","pricing":"Pricing","pricingPlan":"Pricing Plan","monthly":"Monthly","yearly":"Yearly","lifetime":"Lifetime","month":"month","year":"year","shortTermCommitment":"Short Term Commitment.","renewsMonthly":"Renews monthly.","getFreeMonths":"Get 4 months free.","renewsYearly":"Renews yearly.","onetimePurchase":"One-time Purchase.","lifetimeAccess":"Lifetime Access.","termsOfService":"Terms of Service","refundPolicy":"Refund Policy","allFutureUpdates":"All future updates","supportMyWork":"Support my work","settings":"Settings","welcome":"Welcome to Pattern Monster Pro!","purchaseSuccessful":"Your purchase was successful and your account has been upgraded.","readyExplore":"Ready to explore your new features?","clickBelow":"Click the button below to return to the home page and start creating.","done":"Done","loggedIn":"You are already logged in","name":"Name","or":"OR","signInGoogle":"Sign in with Google","currentBillingCycle":"Current billing cycle","updatePaymentMethod":"Update Payment Method","cancelSubscription":"Cancel Subscription","startProPlan":"Start Pro Plan","whatsIncluded":"What's Included","noAds":"Remove ads","premiumPatterns":"Premium Patterns","upgradePro":"Upgrade to Pro"};export default { strings }; -------------------------------------------------------------------------------- /src/routes/_layout.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 |