mirror of
https://github.com/locomotivemtl/locomotive-boilerplate.git
synced 2026-01-15 00:55:08 +08:00
Merge pull request #95 from locomotivemtl/mcaskill-refactor-build
Refactor build tasks and config file
This commit is contained in:
57
README.md
57
README.md
@@ -10,25 +10,45 @@
|
||||
|
||||
| Name | Version |
|
||||
| ---------- | -------- |
|
||||
| [Node] | > 14.15 |
|
||||
| [Node] | > 14.17 |
|
||||
|
||||
[Node]: https://nodejs.org/en/
|
||||
[Node]: https://nodejs.org/en/
|
||||
|
||||
You can use [nvm](https://github.com/nvm-sh/nvm) to install the node version in `.nvmrc`.
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
npm i
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```sh
|
||||
# start it
|
||||
npm start
|
||||
```
|
||||
|
||||
## Configuration
|
||||
Change the mentions of `locomotive-boilerplate` for your project's name in `mconfig.json`. Legacy from [modularBP](https://github.com/modularorg/modularbp).
|
||||
|
||||
There are a few occurrences that should be renamed for your project:
|
||||
|
||||
* [package.json](package.json):
|
||||
* Package name: `@locomotivemtl/boilerplate`
|
||||
* Package title: `Locomotive Boilerplate`
|
||||
* [package-lock.json](package-lock.json):
|
||||
* Package name: `@locomotivemtl/boilerplate`
|
||||
* [loconfig.json](loconfig.json):
|
||||
* Browser Sync proxy URL: `locomotive-boilerplate.test`
|
||||
Remove `paths.url` to use Browser Sync's built-in server which uses `paths.dest`.
|
||||
* View path: `./views/boilerplate/template`
|
||||
* [environment.js](assets/scripts/utils/environment.js):
|
||||
* Application name: `Boilerplate`
|
||||
* [site.webmanifest](www/site.webmanifest):
|
||||
* Manifest name: `Locomotive Boilerplate`
|
||||
* Manifest short name: `Boilerplate`
|
||||
* HTML files:
|
||||
* Page title: `Locomotive Boilerplate`
|
||||
|
||||
## Build
|
||||
|
||||
@@ -41,11 +61,12 @@ npm start
|
||||
npm run build
|
||||
```
|
||||
|
||||
|
||||
## Styles
|
||||
|
||||
[Sass](https://github.com/sass/node-sass) is our CSS preprocessor. [Autoprefixer](https://github.com/postcss/autoprefixer) is also included.
|
||||
|
||||
#### Architecture
|
||||
|
||||
[ITCSS](https://github.com/itcss) is our CSS architecture.
|
||||
|
||||
* `settings`: Global variables, site-wide settings, config switches, etc.
|
||||
@@ -60,11 +81,15 @@ npm run build
|
||||
[_source_](https://github.com/inuitcss/inuitcss#css-directory-structure)
|
||||
|
||||
#### Naming
|
||||
|
||||
We use a simplified [BEM](https://github.com/bem) syntax.
|
||||
|
||||
`.block .block_element -modifier`
|
||||
```
|
||||
.block .block_element -modifier
|
||||
```
|
||||
|
||||
#### Namespaces
|
||||
|
||||
We namespace our classes for more [transparency](https://csswizardry.com/2015/03/more-transparent-ui-code-with-namespaces/).
|
||||
|
||||
* `o-`: Object that it may be used in any number of unrelated contexts to the one you can currently see it in. Making modifications to these types of class could potentially have knock-on effects in a lot of other unrelated places.
|
||||
@@ -76,6 +101,7 @@ We namespace our classes for more [transparency](https://csswizardry.com/2015/03
|
||||
[_source_](https://csswizardry.com/2015/03/more-transparent-ui-code-with-namespaces/#the-namespaces)
|
||||
|
||||
#### Example
|
||||
|
||||
```html
|
||||
<div class="c-block -large">
|
||||
<div class="c-block_layout o-layout">
|
||||
@@ -105,17 +131,20 @@ We namespace our classes for more [transparency](https://csswizardry.com/2015/03
|
||||
```
|
||||
|
||||
## Scripts
|
||||
|
||||
[modularJS](https://github.com/modularorg/modularjs) is a small framework we use on top of ES modules. It compiles with [Rollup](https://github.com/rollup/rollup) and [Babel](https://github.com/babel/babel).
|
||||
|
||||
#### Why
|
||||
- Automatically init visible modules.
|
||||
- Easily call other modules methods.
|
||||
- Quickly set scoped events with delegation.
|
||||
- Simply select DOM elements scoped in their module.
|
||||
|
||||
* Automatically init visible modules.
|
||||
* Easily call other modules methods.
|
||||
* Quickly set scoped events with delegation.
|
||||
* Simply select DOM elements scoped in their module.
|
||||
|
||||
[_source_](https://github.com/modularorg/modularjs#why)
|
||||
|
||||
#### Example
|
||||
|
||||
```html
|
||||
<div data-module-example>
|
||||
<div data-example="main">
|
||||
@@ -124,8 +153,9 @@ We namespace our classes for more [transparency](https://csswizardry.com/2015/03
|
||||
<button data-example="load">More</button>
|
||||
</div>
|
||||
```
|
||||
|
||||
```js
|
||||
import { module } from 'modujs';
|
||||
import { module } from 'modujs';
|
||||
|
||||
export default class extends module {
|
||||
constructor(m) {
|
||||
@@ -147,9 +177,11 @@ export default class extends module {
|
||||
[Learn more](https://github.com/modularorg/modularjs)
|
||||
|
||||
## Page transitions
|
||||
|
||||
[modularLoad](https://github.com/modularorg/modularload) is used for page transitions and lazy loading.
|
||||
|
||||
#### Example
|
||||
|
||||
```html
|
||||
<nav>
|
||||
<a href="/">Home</a>
|
||||
@@ -175,15 +207,18 @@ this.load = new modularLoad({
|
||||
[Learn more](https://github.com/modularorg/modularload)
|
||||
|
||||
## Scroll detection
|
||||
[Locomotive Scroll](https://github.com/locomotivemtl/locomotive-scroll) is used for elements in viewport detection and smooth scrolling with parallax.
|
||||
|
||||
[Locomotive Scroll](https://github.com/locomotivemtl/locomotive-scroll) is used for elements in viewport detection and smooth scrolling with parallax.
|
||||
|
||||
#### Example
|
||||
|
||||
```html
|
||||
<div data-module-scroll>
|
||||
<div data-scroll>Trigger</div>
|
||||
<div data-scroll data-scroll-speed="1">Parallax</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
```js
|
||||
import LocomotiveScroll from 'locomotive-scroll';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { module } from 'modujs';
|
||||
import { module } from 'modujs';
|
||||
|
||||
export default class extends module {
|
||||
constructor(m) {
|
||||
@@ -6,6 +6,5 @@ export default class extends module {
|
||||
}
|
||||
|
||||
init() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { module } from 'modujs';
|
||||
import { module } from 'modujs';
|
||||
import modularLoad from 'modularload';
|
||||
|
||||
export default class extends module {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { buildScripts } from './scripts.js';
|
||||
import { concatVendors } from './concat.js';
|
||||
import { compileStyles } from './styles.js' ;
|
||||
import { generateSpriteSVG } from './svgs.js' ;
|
||||
import concatFiles from './tasks/concats.js';
|
||||
import compileScripts from './tasks/scripts.js';
|
||||
import compileStyles from './tasks/styles.js' ;
|
||||
import compileSVGs from './tasks/svgs.js' ;
|
||||
|
||||
buildScripts();
|
||||
concatVendors();
|
||||
concatFiles();
|
||||
compileScripts();
|
||||
compileStyles();
|
||||
generateSpriteSVG();
|
||||
compileSVGs();
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
import paths from '../mconfig.json';
|
||||
import message from './utils/message.js';
|
||||
import fs from 'fs';
|
||||
import concat from 'concat';
|
||||
|
||||
export function concatVendors() {
|
||||
console.time('Concat in');
|
||||
|
||||
// Get all files in scripts/vendors/
|
||||
const files = fs.readdirSync(paths.scripts.vendors.src);
|
||||
|
||||
// Exclude files that are not JavaScript
|
||||
var jsFiles = files.filter((file) => {
|
||||
return file.includes('.js');
|
||||
});
|
||||
|
||||
// Prepend absolute path
|
||||
jsFiles = jsFiles.map((file) => {
|
||||
return `${paths.scripts.vendors.src + file}`;
|
||||
});
|
||||
// add files in node_modules example:
|
||||
// jsFiles.push('node_modules/gsap/dist/gsap.min.js');
|
||||
|
||||
concat(jsFiles, paths.scripts.dest + paths.scripts.vendors.main + '.js').then(() => {
|
||||
message('Vendors concatenated', 'success', 'Concat in');
|
||||
})
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import notifier from 'node-notifier';
|
||||
|
||||
export default function notification({ title, message }) {
|
||||
notifier.notify({
|
||||
title: title,
|
||||
message: message,
|
||||
icon: 'https://user-images.githubusercontent.com/4596862/54868065-c2aea200-4d5e-11e9-9ce3-e0013c15f48c.png'
|
||||
});
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
import esbuild from 'esbuild';
|
||||
import paths from '../mconfig.json';
|
||||
import message from './utils/message.js';
|
||||
import notification from './notification.js';
|
||||
|
||||
export function buildScripts() {
|
||||
console.time('JS built in');
|
||||
|
||||
esbuild.build({
|
||||
entryPoints: [ paths.scripts.src + paths.scripts.main + '.js' ],
|
||||
bundle: true,
|
||||
minify: true,
|
||||
sourcemap: true,
|
||||
color: true,
|
||||
logLevel: 'error',
|
||||
target: [ 'es2015' ],
|
||||
outfile: paths.scripts.dest + paths.scripts.main + '.js'
|
||||
}).catch((e) => {
|
||||
// errors managments (already done in esbuild)
|
||||
|
||||
notification({
|
||||
title: 'Javascript built failed 🚨',
|
||||
message: `${e.errors[0].text} in ${e.errors[0].location.file} line ${e.errors[0].location.line}`
|
||||
});
|
||||
|
||||
}).then(() => {
|
||||
message('Javascript built','success', 'JS built in')
|
||||
})
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
import sass from 'node-sass';
|
||||
import paths from '../mconfig.json';
|
||||
import fs from 'fs';
|
||||
import message from './utils/message.js';
|
||||
import notification from './notification.js';
|
||||
|
||||
export function compileStyles() {
|
||||
console.time('Styles built in');
|
||||
|
||||
// Compile main scss
|
||||
sass.render({
|
||||
file: paths.styles.src + paths.styles.main + '.scss',
|
||||
outFile: paths.styles.dest + paths.styles.main + '.css',
|
||||
outputStyle: 'compressed',
|
||||
sourceMap: true
|
||||
}, (error, result) => {
|
||||
if (error) {
|
||||
message('Error compiling main.scss', 'error');
|
||||
console.log(error.formatted);
|
||||
|
||||
notification({
|
||||
title: 'main.scss compilation failed 🚨',
|
||||
message: `${error.formatted}`
|
||||
});
|
||||
} else {
|
||||
message('Styles built', 'success', 'Styles built in');
|
||||
}
|
||||
|
||||
if (!error){
|
||||
// No errors during the compilation, write this result on the disk
|
||||
fs.writeFile(paths.styles.dest + paths.styles.main + '.css', result.css, (err) => {});
|
||||
}
|
||||
});
|
||||
|
||||
console.time('Critical style built in');
|
||||
|
||||
// Compile critical scss
|
||||
sass.render({
|
||||
file: paths.styles.src + paths.styles.critical + '.scss',
|
||||
outFile: paths.styles.dest + paths.styles.critical + '.css',
|
||||
outputStyle: 'compressed',
|
||||
sourceMap: true
|
||||
}, (error, result) => {
|
||||
if (error) {
|
||||
message('Error compiling critical.scss', 'error');
|
||||
console.log(error);
|
||||
} else {
|
||||
message('Critical style built', 'success', 'Critical style built in');
|
||||
}
|
||||
|
||||
if (!error){
|
||||
// No errors during the compilation, write this result on the disk
|
||||
fs.writeFile(paths.styles.dest + paths.styles.critical + '.css', result.css, (err) => {});
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
import mixer from 'svg-mixer';
|
||||
import paths from '../mconfig.json';
|
||||
import message from './utils/message.js';
|
||||
|
||||
export function generateSpriteSVG() {
|
||||
console.time('Sprite generated in');
|
||||
|
||||
// Write sprite content on disk
|
||||
mixer([
|
||||
paths.svgs.src + '*.svg'
|
||||
], {
|
||||
spriteConfig: {
|
||||
usages: false
|
||||
}
|
||||
}).then((result) => {
|
||||
result.write(paths.svgs.dest + 'sprite.svg');
|
||||
message('SVG Sprite generated', 'success', 'Sprite generated in');
|
||||
});
|
||||
}
|
||||
48
build/tasks/concats.js
Normal file
48
build/tasks/concats.js
Normal file
@@ -0,0 +1,48 @@
|
||||
import loconfig from '../../loconfig.json';
|
||||
import glob from '../utils/glob.js';
|
||||
import message from '../utils/message.js';
|
||||
import notification from '../utils/notification.js';
|
||||
import template from '../utils/template.js';
|
||||
import concat from 'concat';
|
||||
import { basename } from 'node:path';
|
||||
|
||||
/**
|
||||
* Concatenates groups of files.
|
||||
*
|
||||
* @async
|
||||
* @return {Promise}
|
||||
*/
|
||||
export default async function concatFiles() {
|
||||
loconfig.tasks.concats.forEach(async ({
|
||||
includes,
|
||||
outfile
|
||||
}) => {
|
||||
const filename = basename(outfile || 'undefined');
|
||||
|
||||
const timeLabel = `${filename} concatenated in`;
|
||||
console.time(timeLabel);
|
||||
|
||||
try {
|
||||
includes = includes.map((path) => template(path));
|
||||
outfile = template(outfile);
|
||||
|
||||
const files = await glob(includes);
|
||||
|
||||
await concat(files, outfile);
|
||||
|
||||
if (files.length) {
|
||||
message(`${filename} concatenated`, 'success', timeLabel);
|
||||
} else {
|
||||
message(`${filename} is empty`, 'notice', timeLabel);
|
||||
}
|
||||
} catch (err) {
|
||||
message(`Error concatenating ${filename}`, 'error');
|
||||
message(err);
|
||||
|
||||
notification({
|
||||
title: `${filename} concatenation failed 🚨`,
|
||||
message: `${err.name}: ${err.message}`
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
61
build/tasks/scripts.js
Normal file
61
build/tasks/scripts.js
Normal file
@@ -0,0 +1,61 @@
|
||||
import loconfig from '../../loconfig.json';
|
||||
import message from '../utils/message.js';
|
||||
import notification from '../utils/notification.js';
|
||||
import template from '../utils/template.js';
|
||||
import esbuild from 'esbuild';
|
||||
import { basename } from 'node:path';
|
||||
|
||||
/**
|
||||
* Bundles and minifies main JavaScript files.
|
||||
*
|
||||
* @async
|
||||
* @return {Promise}
|
||||
*/
|
||||
export default async function compileScripts() {
|
||||
loconfig.tasks.scripts.forEach(async ({
|
||||
includes,
|
||||
outdir = '',
|
||||
outfile = ''
|
||||
}) => {
|
||||
const filename = basename(outdir || outfile || 'undefined');
|
||||
|
||||
const timeLabel = `${filename} compiled in`;
|
||||
console.time(timeLabel);
|
||||
|
||||
try {
|
||||
includes = includes.map((path) => template(path));
|
||||
|
||||
if (outdir) {
|
||||
outdir = template(outdir);
|
||||
} else if (outfile) {
|
||||
outfile = template(outfile);
|
||||
} else {
|
||||
throw new TypeError(
|
||||
'Expected \'outdir\' or \'outfile\''
|
||||
);
|
||||
}
|
||||
|
||||
await esbuild.build({
|
||||
entryPoints: includes,
|
||||
bundle: true,
|
||||
minify: true,
|
||||
sourcemap: true,
|
||||
color: true,
|
||||
logLevel: 'error',
|
||||
target: [
|
||||
'es2015',
|
||||
],
|
||||
outdir,
|
||||
outfile
|
||||
});
|
||||
|
||||
message(`${filename} compiled`, 'success', timeLabel);
|
||||
} catch (err) {
|
||||
// errors managments (already done in esbuild)
|
||||
notification({
|
||||
title: `${filename} compilation failed 🚨`,
|
||||
message: `${err.errors[0].text} in ${err.errors[0].location.file} line ${err.errors[0].location.line}`
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
101
build/tasks/styles.js
Normal file
101
build/tasks/styles.js
Normal file
@@ -0,0 +1,101 @@
|
||||
import loconfig from '../../loconfig.json';
|
||||
import message from '../utils/message.js';
|
||||
import notification from '../utils/notification.js';
|
||||
import postcss from '../utils/postcss.js';
|
||||
import template from '../utils/template.js';
|
||||
import { writeFile } from 'node:fs/promises';
|
||||
import { basename } from 'node:path';
|
||||
import { promisify } from 'node:util';
|
||||
import sass from 'node-sass';
|
||||
|
||||
const sassRender = promisify(sass.render);
|
||||
|
||||
/**
|
||||
* Compiles and minifies main Sass files to CSS.
|
||||
*
|
||||
* @async
|
||||
* @return {Promise}
|
||||
*/
|
||||
export default async function compileStyles() {
|
||||
loconfig.tasks.styles.forEach(async ({
|
||||
infile,
|
||||
outfile
|
||||
}) => {
|
||||
const name = basename((outfile || 'undefined'), '.css');
|
||||
|
||||
const timeLabel = `${name}.css compiled in`;
|
||||
console.time(timeLabel);
|
||||
|
||||
try {
|
||||
infile = template(infile);
|
||||
outfile = template(outfile);
|
||||
|
||||
let result = await sassRender({
|
||||
file: infile,
|
||||
omitSourceMapUrl: true,
|
||||
outFile: outfile,
|
||||
outputStyle: 'compressed',
|
||||
sourceMap: true,
|
||||
sourceMapContents: true
|
||||
});
|
||||
|
||||
if (postcss) {
|
||||
result = await postcss.process(result.css, {
|
||||
from: outfile,
|
||||
to: outfile,
|
||||
map: {
|
||||
annotation: false,
|
||||
inline: false,
|
||||
sourcesContent: true
|
||||
}
|
||||
});
|
||||
|
||||
if (result.warnings) {
|
||||
const warnings = result.warnings();
|
||||
if (warnings.length) {
|
||||
message(`Error processing ${name}.css`, 'warning');
|
||||
warnings.forEach((warn) => {
|
||||
message(warn.toString());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writeFile(outfile, result.css).then(() => {
|
||||
if (result.css) {
|
||||
message(`${name}.css compiled`, 'success', timeLabel);
|
||||
} else {
|
||||
message(`${name}.css is empty`, 'notice', timeLabel);
|
||||
}
|
||||
}).catch((err) => {
|
||||
message(`Error compiling ${name}.css`, 'error');
|
||||
message(err);
|
||||
|
||||
notification({
|
||||
title: `${name}.css save failed 🚨`,
|
||||
message: `Could not save stylesheet to ${name}.css`
|
||||
});
|
||||
});
|
||||
|
||||
if (result.map) {
|
||||
writeFile(outfile + '.map', result.map.toString()).catch((err) => {
|
||||
message(`Error compiling ${name}.css.map`, 'error');
|
||||
message(err);
|
||||
|
||||
notification({
|
||||
title: `${name}.css.map save failed 🚨`,
|
||||
message: `Could not save sourcemap to ${name}.css.map`
|
||||
});
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
message(`Error compiling ${name}.scss`, 'error');
|
||||
message(err.formatted || err);
|
||||
|
||||
notification({
|
||||
title: `${name}.scss compilation failed 🚨`,
|
||||
message: (err.formatted || `${err.name}: ${err.message}`)
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
47
build/tasks/svgs.js
Normal file
47
build/tasks/svgs.js
Normal file
@@ -0,0 +1,47 @@
|
||||
import loconfig from '../../loconfig.json';
|
||||
import message from '../utils/message.js';
|
||||
import notification from '../utils/notification.js';
|
||||
import template from '../utils/template.js';
|
||||
import { basename } from 'node:path';
|
||||
import mixer from 'svg-mixer';
|
||||
|
||||
/**
|
||||
* Generates and transforms SVG spritesheets.
|
||||
*
|
||||
* @async
|
||||
* @return {Promise}
|
||||
*/
|
||||
export default async function compileSVGs() {
|
||||
loconfig.tasks.svgs.forEach(async ({
|
||||
includes,
|
||||
outfile
|
||||
}) => {
|
||||
const filename = basename(outfile || 'undefined');
|
||||
|
||||
const timeLabel = `${filename} compiled in`;
|
||||
console.time(timeLabel);
|
||||
|
||||
try {
|
||||
includes = includes.map((path) => template(path));
|
||||
outfile = template(outfile);
|
||||
|
||||
const result = await mixer(includes, {
|
||||
spriteConfig: {
|
||||
usages: false
|
||||
}
|
||||
});
|
||||
|
||||
await result.write(outfile);
|
||||
|
||||
message(`${filename} compiled`, 'success', timeLabel);
|
||||
} catch (err) {
|
||||
message(`Error compiling ${filename}`, 'error');
|
||||
message(err);
|
||||
|
||||
notification({
|
||||
title: `${filename} compilation failed 🚨`,
|
||||
message: `${err.name}: ${err.message}`
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
86
build/utils/glob.js
Normal file
86
build/utils/glob.js
Normal file
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* @file Retrieve the first available glob library.
|
||||
*
|
||||
* Note that options vary between libraries.
|
||||
*
|
||||
* Candidates:
|
||||
* - {@link https://npmjs.com/package/tiny-glob tiny-glob}
|
||||
* - {@link https://npmjs.com/package/globby}
|
||||
* - {@link https://npmjs.com/package/fast-glob fast-glob}
|
||||
* - {@link https://npmjs.com/package/glob glob}
|
||||
*/
|
||||
|
||||
import { promisify } from 'node:util';
|
||||
|
||||
/**
|
||||
* @type {string[]} A list of packages to attempt import.
|
||||
*/
|
||||
const candidates = [
|
||||
'tiny-glob',
|
||||
'globby',
|
||||
'fast-glob',
|
||||
'glob',
|
||||
];
|
||||
|
||||
export default await importGlob();
|
||||
|
||||
/**
|
||||
* Imports the first available glob function.
|
||||
*
|
||||
* @throws {TypeError} If no glob library was found.
|
||||
* @return {function}
|
||||
*/
|
||||
async function importGlob() {
|
||||
let glob, module;
|
||||
|
||||
for (let name of candidates) {
|
||||
try {
|
||||
module = await import(name);
|
||||
|
||||
if (typeof module.default !== 'function') {
|
||||
throw new TypeError(`Expected ${name} to be a function`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the function to ensure
|
||||
* a common pattern.
|
||||
*/
|
||||
switch (name) {
|
||||
case 'tiny-glob':
|
||||
return createArrayableGlob(module.default, {
|
||||
filesOnly: true
|
||||
});
|
||||
|
||||
case 'glob':
|
||||
return promisify(module.default);
|
||||
|
||||
default:
|
||||
return module.default;
|
||||
}
|
||||
} catch (err) {
|
||||
// swallow this error; skip to the next candidate.
|
||||
}
|
||||
}
|
||||
|
||||
throw new TypeError(
|
||||
`No glob library was found, expected one of: ${modules.join(', ')}`
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a wrapper function for the glob function
|
||||
* to provide support for arrays of patterns.
|
||||
*
|
||||
* @param {function} glob - The glob function.
|
||||
* @param {object} options - The glob options.
|
||||
* @return {function}
|
||||
*/
|
||||
function createArrayableGlob(glob, options) {
|
||||
return (patterns, options) => {
|
||||
const globs = patterns.map((pattern) => glob(pattern, options));
|
||||
|
||||
return Promise.all(globs).then((files) => {
|
||||
return [].concat.apply([], files);
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -1,19 +1,51 @@
|
||||
/**
|
||||
* @file Provides a decorator for console messages.
|
||||
*/
|
||||
|
||||
import kleur from 'kleur';
|
||||
|
||||
export default function message(text, type, timerId) {
|
||||
if (type === 'success') {
|
||||
console.log(kleur.bgGreen().black(`${text} ✅`));
|
||||
/**
|
||||
* Outputs a message to the console.
|
||||
*
|
||||
* @param {string} text - The message to output.
|
||||
* @param {string} [type] - The type of message.
|
||||
* @param {string} [timerID] - The console time label to output.
|
||||
*/
|
||||
export default function message(text, type, timerID) {
|
||||
switch (type) {
|
||||
case 'success':
|
||||
console.log('✅ ', kleur.bgGreen().black(text));
|
||||
break;
|
||||
|
||||
if (timerId !== undefined) {
|
||||
console.timeEnd(timerId)
|
||||
}
|
||||
} else if (type === 'error') {
|
||||
console.log(kleur.red().underline(`${text} ❌`));
|
||||
} else if (type === 'waiting') {
|
||||
console.log(kleur.blue().italic(`${text} ⏱`));
|
||||
} else {
|
||||
console.log(text);
|
||||
case 'notice':
|
||||
console.log('ℹ️ ', kleur.bgBlue().black(text));
|
||||
break;
|
||||
|
||||
case 'error':
|
||||
console.log('❌ ', kleur.bgRed().black(text));
|
||||
break;
|
||||
|
||||
case 'warning':
|
||||
console.log('⚠️ ', kleur.bgYellow().black(text));
|
||||
break;
|
||||
|
||||
case 'waiting':
|
||||
console.log('⏱ ', kleur.blue().italic(text));
|
||||
|
||||
if (timerID != null) {
|
||||
console.timeLog(timerID);
|
||||
timerID = null;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
console.log(text);
|
||||
break;
|
||||
}
|
||||
|
||||
if (timerID != null) {
|
||||
console.timeEnd(timerID);
|
||||
}
|
||||
|
||||
console.log('');
|
||||
}
|
||||
};
|
||||
|
||||
29
build/utils/notification.js
Normal file
29
build/utils/notification.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import notifier from 'node-notifier';
|
||||
|
||||
/**
|
||||
* Sends a cross-platform native notification.
|
||||
*
|
||||
* Wraps around node-notifier to assign default values.
|
||||
*
|
||||
* @param {string|object} options - The notification options or a message.
|
||||
* @param {string} options.title - The notification title.
|
||||
* @param {string} options.message - The notification message.
|
||||
* @param {string} options.icon - The notification icon.
|
||||
*/
|
||||
export default function notification(options) {
|
||||
if (typeof options === 'string') {
|
||||
options = {
|
||||
message: options
|
||||
};
|
||||
} else if (!options.title && !options.message) {
|
||||
throw new TypeError(
|
||||
'Notification expects at least a \'message\' parameter'
|
||||
);
|
||||
}
|
||||
|
||||
if (typeof options.icon === 'undefined') {
|
||||
options.icon = 'https://user-images.githubusercontent.com/4596862/54868065-c2aea200-4d5e-11e9-9ce3-e0013c15f48c.png';
|
||||
}
|
||||
|
||||
notifier.notify(options);
|
||||
};
|
||||
14
build/utils/postcss.js
Normal file
14
build/utils/postcss.js
Normal file
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* @file If available, returns the PostCSS processor with any plugins.
|
||||
*/
|
||||
|
||||
try {
|
||||
var { default: postcss } = await import('postcss');
|
||||
let { default: autoprefixer } = await import('autoprefixer');
|
||||
|
||||
postcss = postcss([ autoprefixer ]);
|
||||
} catch (err) {
|
||||
postcss = null;
|
||||
}
|
||||
|
||||
export default postcss;
|
||||
111
build/utils/template.js
Normal file
111
build/utils/template.js
Normal file
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* @file Provides simple template tags.
|
||||
*/
|
||||
|
||||
import loconfig from '../../loconfig.json';
|
||||
|
||||
const templateData = flatten({
|
||||
paths: loconfig.paths
|
||||
});
|
||||
|
||||
/**
|
||||
* Replaces all template tags from a map of keys and values.
|
||||
*
|
||||
* If replacement pairs contain a mix of substrings, regular expressions,
|
||||
* and functions, regular expressions are executed last.
|
||||
*
|
||||
* @param {string} input - The string being searched and replaced on.
|
||||
* @param {object} data - An object in the form `{ 'from': 'to', … }`.
|
||||
* @return {string} Returns the translated string.
|
||||
*/
|
||||
export default function template(input, data) {
|
||||
const tags = [];
|
||||
|
||||
if (data) {
|
||||
data = flatten(data);
|
||||
} else {
|
||||
data = templateData;
|
||||
}
|
||||
|
||||
for (let tag in data) {
|
||||
tags.push(escapeRegExp(tag));
|
||||
}
|
||||
|
||||
if (tags.length === 0) {
|
||||
return input;
|
||||
}
|
||||
|
||||
const search = new RegExp('\\{%\\s*(' + tags.join('|') + ')\\s*%\\}', 'g');
|
||||
return input.replace(search, (match, key) => {
|
||||
let value = data[key];
|
||||
|
||||
switch (typeof value) {
|
||||
case 'function':
|
||||
/**
|
||||
* Retrieve the offset of the matched substring `args[0]`
|
||||
* and the whole string being examined `args[1]`.
|
||||
*/
|
||||
let args = Array.prototype.slice.call(arguments, -2);
|
||||
return value.call(data, match, args[0], args[1]);
|
||||
|
||||
case 'string':
|
||||
case 'number':
|
||||
return value;
|
||||
}
|
||||
|
||||
return '';
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new object with all nested object properties
|
||||
* concatenated into it recursively.
|
||||
*
|
||||
* Nested keys are flattened into a property path:
|
||||
*
|
||||
* ```js
|
||||
* {
|
||||
* a: {
|
||||
* b: {
|
||||
* c: 1
|
||||
* }
|
||||
* },
|
||||
* d: 1
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* ```js
|
||||
* {
|
||||
* "a.b.c": 1,
|
||||
* "d": 1
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @param {object} input - The object to flatten.
|
||||
* @param {string} prefix - The parent key prefix.
|
||||
* @param {object} target - The object that will receive the flattened properties.
|
||||
* @return {object} Returns the `target` object.
|
||||
*/
|
||||
function flatten(input, prefix, target = {}) {
|
||||
for (let key in input) {
|
||||
let field = (prefix ? prefix + '.' + key : key);
|
||||
|
||||
if (typeof input[key] === 'object') {
|
||||
flatten(input[key], field, target);
|
||||
} else {
|
||||
target[field] = input[key];
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Quotes regular expression characters.
|
||||
*
|
||||
* @param {string} str - The input string.
|
||||
* @return {string} Returns the quoted (escaped) string.
|
||||
*/
|
||||
function escapeRegExp(str) {
|
||||
return str.replace(/[\[\]\{\}\(\)\-\*\+\?\.\,\\\^\$\|\#\s]/g, '\\$&');
|
||||
}
|
||||
@@ -1,9 +1,13 @@
|
||||
import { buildScripts } from './scripts.js';
|
||||
import { concatVendors } from './concat.js';
|
||||
import { compileStyles } from './styles.js' ;
|
||||
import { generateSpriteSVG } from './svgs.js';
|
||||
import paths from '../mconfig.json';
|
||||
import loconfig from '../loconfig.json';
|
||||
import concatFiles from './tasks/concats.js';
|
||||
import compileScripts from './tasks/scripts.js';
|
||||
import compileStyles from './tasks/styles.js' ;
|
||||
import compileSVGs from './tasks/svgs.js';
|
||||
import template from './utils/template.js';
|
||||
import server from 'browser-sync';
|
||||
import { join } from 'node:path';
|
||||
|
||||
const { paths, tasks } = loconfig;
|
||||
|
||||
const serverConfig = {
|
||||
open: false,
|
||||
@@ -23,45 +27,46 @@ if (typeof paths.url === 'string' && paths.url.length > 0) {
|
||||
// Start the Browsersync server
|
||||
server.init(serverConfig);
|
||||
|
||||
// Build scripts, compile styles, concat vendors and generate the svgs sprite on first hit
|
||||
buildScripts();
|
||||
concatVendors();
|
||||
// Build scripts, compile styles, concat files,
|
||||
// and generate spritesheets on first hit
|
||||
concatFiles();
|
||||
compileScripts();
|
||||
compileStyles();
|
||||
generateSpriteSVG();
|
||||
compileSVGs();
|
||||
|
||||
// and call any methods on it.
|
||||
server.watch(
|
||||
[
|
||||
paths.views.src,
|
||||
paths.scripts.dest + paths.scripts.main + '.js',
|
||||
paths.scripts.dest + paths.scripts.vendors.main + '.js',
|
||||
paths.styles.dest + paths.styles.main + '.css',
|
||||
paths.svgs.dest + 'sprite.svg'
|
||||
join(paths.scripts.dest, '*.js'),
|
||||
join(paths.styles.dest, '*.css'),
|
||||
join(paths.svgs.dest, '*.svg'),
|
||||
]
|
||||
).on('change', server.reload);
|
||||
|
||||
// Watch scripts
|
||||
server.watch(
|
||||
[
|
||||
paths.scripts.src + '**/*.js'
|
||||
join(paths.scripts.src, '**/*.js'),
|
||||
]
|
||||
).on('change', () => {
|
||||
buildScripts();
|
||||
compileScripts();
|
||||
});
|
||||
|
||||
// Watch scripts vendors
|
||||
// Watch concats
|
||||
server.watch(
|
||||
[
|
||||
paths.scripts.vendors.src + '*.js'
|
||||
]
|
||||
tasks.concats.reduce(
|
||||
(patterns, { includes }) => patterns.concat(includes),
|
||||
[]
|
||||
).map((path) => template(path))
|
||||
).on('change', () => {
|
||||
concatVendors();
|
||||
concatFiles();
|
||||
});
|
||||
|
||||
// Watch styles
|
||||
server.watch(
|
||||
[
|
||||
paths.styles.src + '**/*.scss'
|
||||
join(paths.styles.src, '**/*.scss'),
|
||||
]
|
||||
).on('change', () => {
|
||||
compileStyles();
|
||||
@@ -70,8 +75,8 @@ server.watch(
|
||||
// Watch svgs
|
||||
server.watch(
|
||||
[
|
||||
paths.svgs.src + '*.svg'
|
||||
join(paths.svgs.src, '*.svg'),
|
||||
]
|
||||
).on('change', () => {
|
||||
generateSpriteSVG();
|
||||
compileSVGs();
|
||||
});
|
||||
|
||||
61
loconfig.json
Executable file
61
loconfig.json
Executable file
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"paths": {
|
||||
"url": "locomotive-boilerplate.test",
|
||||
"src": "./assets",
|
||||
"dest": "./www",
|
||||
"images": {
|
||||
"src": "./assets/images"
|
||||
},
|
||||
"styles": {
|
||||
"src": "./assets/styles",
|
||||
"dest": "./www/assets/styles"
|
||||
},
|
||||
"scripts": {
|
||||
"src": "./assets/scripts",
|
||||
"dest": "./www/assets/scripts"
|
||||
},
|
||||
"svgs": {
|
||||
"src": "./assets/images/sprite",
|
||||
"dest": "./www/assets/images"
|
||||
},
|
||||
"views": {
|
||||
"src": "./views/boilerplate/template"
|
||||
}
|
||||
},
|
||||
"tasks": {
|
||||
"concats": [
|
||||
{
|
||||
"includes": [
|
||||
"{% paths.scripts.src %}/vendors/*.js"
|
||||
],
|
||||
"outfile": "{% paths.scripts.dest %}/vendors.js"
|
||||
}
|
||||
],
|
||||
"scripts": [
|
||||
{
|
||||
"includes": [
|
||||
"{% paths.scripts.src %}/app.js"
|
||||
],
|
||||
"outfile": "{% paths.scripts.dest %}/app.js"
|
||||
}
|
||||
],
|
||||
"styles": [
|
||||
{
|
||||
"infile": "{% paths.styles.src %}/critical.scss",
|
||||
"outfile": "{% paths.styles.dest %}/critical.css"
|
||||
},
|
||||
{
|
||||
"infile": "{% paths.styles.src %}/main.scss",
|
||||
"outfile": "{% paths.styles.dest %}/main.css"
|
||||
}
|
||||
],
|
||||
"svgs": [
|
||||
{
|
||||
"includes": [
|
||||
"{% paths.svgs.src %}/*.svg"
|
||||
],
|
||||
"outfile": "{% paths.svgs.dest %}/sprite.svg"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
28
mconfig.json
28
mconfig.json
@@ -1,28 +0,0 @@
|
||||
{
|
||||
"url": "locomotive-boilerplate.test",
|
||||
"src": "./assets/",
|
||||
"dest": "./www/",
|
||||
"build": "./build/",
|
||||
"styles": {
|
||||
"src": "./assets/styles/",
|
||||
"dest": "./www/assets/styles/",
|
||||
"main": "main",
|
||||
"critical": "critical"
|
||||
},
|
||||
"scripts": {
|
||||
"src": "./assets/scripts/",
|
||||
"dest": "./www/assets/scripts/",
|
||||
"main": "app",
|
||||
"vendors": {
|
||||
"src": "./assets/scripts/vendors/",
|
||||
"main": "vendors"
|
||||
}
|
||||
},
|
||||
"svgs": {
|
||||
"src": "./assets/images/sprite/",
|
||||
"dest": "./www/assets/images/"
|
||||
},
|
||||
"views": {
|
||||
"src": "./views/boilerplate/template/"
|
||||
}
|
||||
}
|
||||
336
package-lock.json
generated
336
package-lock.json
generated
@@ -15,13 +15,16 @@
|
||||
"svg4everybody": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^10.3.4",
|
||||
"browser-sync": "^2.26.13",
|
||||
"concat": "^1.0.3",
|
||||
"esbuild": "^0.12.28",
|
||||
"kleur": "^4.1.4",
|
||||
"node-notifier": "^10.0.0",
|
||||
"node-sass": "^6.0.1",
|
||||
"svg-mixer": "^2.3.14"
|
||||
"postcss": "^8.3.6",
|
||||
"svg-mixer": "^2.3.14",
|
||||
"tiny-glob": "^0.2.9"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
@@ -291,6 +294,33 @@
|
||||
"node": ">= 4.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/autoprefixer": {
|
||||
"version": "10.3.4",
|
||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.3.4.tgz",
|
||||
"integrity": "sha512-EKjKDXOq7ug+jagLzmnoTRpTT0q1KVzEJqrJd0hCBa7FiG0WbFOBCcJCy2QkW1OckpO3qgttA1aWjVbeIPAecw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"browserslist": "^4.16.8",
|
||||
"caniuse-lite": "^1.0.30001252",
|
||||
"colorette": "^1.3.0",
|
||||
"fraction.js": "^4.1.1",
|
||||
"normalize-range": "^0.1.2",
|
||||
"postcss-value-parser": "^4.1.0"
|
||||
},
|
||||
"bin": {
|
||||
"autoprefixer": "bin/autoprefixer"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || >=14"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/postcss/"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"postcss": "^8.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/aws-sign2": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
|
||||
@@ -945,6 +975,29 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/browserslist": {
|
||||
"version": "4.17.0",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.0.tgz",
|
||||
"integrity": "sha512-g2BJ2a0nEYvEFQC208q8mVAhfNwpZ5Mu8BwgtCdZKO3qx98HChmeg448fPdUzld8aFmfLgVh7yymqV+q1lJZ5g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"caniuse-lite": "^1.0.30001254",
|
||||
"colorette": "^1.3.0",
|
||||
"electron-to-chromium": "^1.3.830",
|
||||
"escalade": "^3.1.1",
|
||||
"node-releases": "^1.1.75"
|
||||
},
|
||||
"bin": {
|
||||
"browserslist": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/browserslist"
|
||||
}
|
||||
},
|
||||
"node_modules/bs-recipes": {
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/bs-recipes/-/bs-recipes-1.3.4.tgz",
|
||||
@@ -1012,6 +1065,16 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001257",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001257.tgz",
|
||||
"integrity": "sha512-JN49KplOgHSXpIsVSF+LUyhD8PUp6xPpAXeRrrcBh4KBeP7W864jHn6RvzJgDlrReyeVjMFJL3PLpPvKIxlIHA==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/browserslist"
|
||||
}
|
||||
},
|
||||
"node_modules/caseless": {
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
|
||||
@@ -1114,6 +1177,12 @@
|
||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/colorette": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz",
|
||||
"integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
@@ -1561,6 +1630,12 @@
|
||||
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.3.838",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.838.tgz",
|
||||
"integrity": "sha512-65O6UJiyohFAdX/nc6KJ0xG/4zOn7XCO03kQNNbCeMRGxlWTLzc6Uyi0tFNQuuGWqySZJi8CD2KXPXySVYmzMA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
|
||||
@@ -2014,6 +2089,19 @@
|
||||
"node": ">= 0.12"
|
||||
}
|
||||
},
|
||||
"node_modules/fraction.js": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.1.tgz",
|
||||
"integrity": "sha512-MHOhvvxHTfRFpF1geTK9czMIZ6xclsEor2wkIGYYq+PxcQqT7vStJqjhe6S1TenZrMZzo+wlqOufBDVepUEgPg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "*"
|
||||
},
|
||||
"funding": {
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/infusion"
|
||||
}
|
||||
},
|
||||
"node_modules/fragment-cache": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
|
||||
@@ -2418,6 +2506,18 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/globalyzer": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz",
|
||||
"integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/globrex": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz",
|
||||
"integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/globule": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/globule/-/globule-1.3.2.tgz",
|
||||
@@ -3835,6 +3935,18 @@
|
||||
"integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.1.25",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz",
|
||||
"integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"nanoid": "bin/nanoid.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/nanomatch": {
|
||||
"version": "1.2.13",
|
||||
"resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
|
||||
@@ -4000,6 +4112,12 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/node-releases": {
|
||||
"version": "1.1.75",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.75.tgz",
|
||||
"integrity": "sha512-Qe5OUajvqrqDSy6wrWFmMwfJ0jVgwiw4T3KqmbTcZ62qW0gQkheXYhcFM1+lOVcGUoRxcEcfyvFMAnDgaF1VWw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/node-sass": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/node-sass/-/node-sass-6.0.1.tgz",
|
||||
@@ -4103,6 +4221,15 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/normalize-range": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
|
||||
"integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/normalize.css": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-8.0.1.tgz",
|
||||
@@ -4385,17 +4512,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "7.0.36",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz",
|
||||
"integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==",
|
||||
"version": "8.3.6",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.6.tgz",
|
||||
"integrity": "sha512-wG1cc/JhRgdqB6WHEuyLTedf3KIRuD0hG6ldkFEZNCjRxiC+3i6kkWUUbiJQayP28iwG35cEmAbe98585BYV0A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"chalk": "^2.4.2",
|
||||
"source-map": "^0.6.1",
|
||||
"supports-color": "^6.1.0"
|
||||
"colorette": "^1.2.2",
|
||||
"nanoid": "^3.1.23",
|
||||
"source-map-js": "^0.6.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
"node": "^10 || ^12 || >=14"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
@@ -4423,7 +4550,25 @@
|
||||
"postcss": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss/node_modules/supports-color": {
|
||||
"node_modules/postcss-prefix-selector/node_modules/postcss": {
|
||||
"version": "7.0.36",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz",
|
||||
"integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"chalk": "^2.4.2",
|
||||
"source-map": "^0.6.1",
|
||||
"supports-color": "^6.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/postcss/"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-prefix-selector/node_modules/supports-color": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
|
||||
"integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
|
||||
@@ -4435,6 +4580,12 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-value-parser": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz",
|
||||
"integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/posthtml": {
|
||||
"version": "0.11.6",
|
||||
"resolved": "https://registry.npmjs.org/posthtml/-/posthtml-0.11.6.tgz",
|
||||
@@ -5454,6 +5605,15 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz",
|
||||
"integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-resolve": {
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz",
|
||||
@@ -5986,6 +6146,16 @@
|
||||
"resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-1.2.0.tgz",
|
||||
"integrity": "sha1-bchFBSywjr78GHRyO1jySmSMO28="
|
||||
},
|
||||
"node_modules/tiny-glob": {
|
||||
"version": "0.2.9",
|
||||
"resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz",
|
||||
"integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"globalyzer": "0.1.0",
|
||||
"globrex": "^0.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/to-array": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",
|
||||
@@ -6617,6 +6787,20 @@
|
||||
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
|
||||
"dev": true
|
||||
},
|
||||
"autoprefixer": {
|
||||
"version": "10.3.4",
|
||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.3.4.tgz",
|
||||
"integrity": "sha512-EKjKDXOq7ug+jagLzmnoTRpTT0q1KVzEJqrJd0hCBa7FiG0WbFOBCcJCy2QkW1OckpO3qgttA1aWjVbeIPAecw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"browserslist": "^4.16.8",
|
||||
"caniuse-lite": "^1.0.30001252",
|
||||
"colorette": "^1.3.0",
|
||||
"fraction.js": "^4.1.1",
|
||||
"normalize-range": "^0.1.2",
|
||||
"postcss-value-parser": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"aws-sign2": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
|
||||
@@ -7145,6 +7329,19 @@
|
||||
"stream-throttle": "^0.1.3"
|
||||
}
|
||||
},
|
||||
"browserslist": {
|
||||
"version": "4.17.0",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.0.tgz",
|
||||
"integrity": "sha512-g2BJ2a0nEYvEFQC208q8mVAhfNwpZ5Mu8BwgtCdZKO3qx98HChmeg448fPdUzld8aFmfLgVh7yymqV+q1lJZ5g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"caniuse-lite": "^1.0.30001254",
|
||||
"colorette": "^1.3.0",
|
||||
"electron-to-chromium": "^1.3.830",
|
||||
"escalade": "^3.1.1",
|
||||
"node-releases": "^1.1.75"
|
||||
}
|
||||
},
|
||||
"bs-recipes": {
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/bs-recipes/-/bs-recipes-1.3.4.tgz",
|
||||
@@ -7199,6 +7396,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"caniuse-lite": {
|
||||
"version": "1.0.30001257",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001257.tgz",
|
||||
"integrity": "sha512-JN49KplOgHSXpIsVSF+LUyhD8PUp6xPpAXeRrrcBh4KBeP7W864jHn6RvzJgDlrReyeVjMFJL3PLpPvKIxlIHA==",
|
||||
"dev": true
|
||||
},
|
||||
"caseless": {
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
|
||||
@@ -7282,6 +7485,12 @@
|
||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
|
||||
"dev": true
|
||||
},
|
||||
"colorette": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz",
|
||||
"integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==",
|
||||
"dev": true
|
||||
},
|
||||
"combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
@@ -7647,6 +7856,12 @@
|
||||
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=",
|
||||
"dev": true
|
||||
},
|
||||
"electron-to-chromium": {
|
||||
"version": "1.3.838",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.838.tgz",
|
||||
"integrity": "sha512-65O6UJiyohFAdX/nc6KJ0xG/4zOn7XCO03kQNNbCeMRGxlWTLzc6Uyi0tFNQuuGWqySZJi8CD2KXPXySVYmzMA==",
|
||||
"dev": true
|
||||
},
|
||||
"emoji-regex": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
|
||||
@@ -8020,6 +8235,12 @@
|
||||
"mime-types": "^2.1.12"
|
||||
}
|
||||
},
|
||||
"fraction.js": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.1.tgz",
|
||||
"integrity": "sha512-MHOhvvxHTfRFpF1geTK9czMIZ6xclsEor2wkIGYYq+PxcQqT7vStJqjhe6S1TenZrMZzo+wlqOufBDVepUEgPg==",
|
||||
"dev": true
|
||||
},
|
||||
"fragment-cache": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
|
||||
@@ -8347,6 +8568,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"globalyzer": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz",
|
||||
"integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==",
|
||||
"dev": true
|
||||
},
|
||||
"globrex": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz",
|
||||
"integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==",
|
||||
"dev": true
|
||||
},
|
||||
"globule": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/globule/-/globule-1.3.2.tgz",
|
||||
@@ -9487,6 +9720,12 @@
|
||||
"integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==",
|
||||
"dev": true
|
||||
},
|
||||
"nanoid": {
|
||||
"version": "3.1.25",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz",
|
||||
"integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==",
|
||||
"dev": true
|
||||
},
|
||||
"nanomatch": {
|
||||
"version": "1.2.13",
|
||||
"resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
|
||||
@@ -9611,6 +9850,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node-releases": {
|
||||
"version": "1.1.75",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.75.tgz",
|
||||
"integrity": "sha512-Qe5OUajvqrqDSy6wrWFmMwfJ0jVgwiw4T3KqmbTcZ62qW0gQkheXYhcFM1+lOVcGUoRxcEcfyvFMAnDgaF1VWw==",
|
||||
"dev": true
|
||||
},
|
||||
"node-sass": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/node-sass/-/node-sass-6.0.1.tgz",
|
||||
@@ -9688,6 +9933,12 @@
|
||||
"remove-trailing-separator": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"normalize-range": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
|
||||
"integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=",
|
||||
"dev": true
|
||||
},
|
||||
"normalize.css": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-8.0.1.tgz",
|
||||
@@ -9905,25 +10156,14 @@
|
||||
"dev": true
|
||||
},
|
||||
"postcss": {
|
||||
"version": "7.0.36",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz",
|
||||
"integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==",
|
||||
"version": "8.3.6",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.6.tgz",
|
||||
"integrity": "sha512-wG1cc/JhRgdqB6WHEuyLTedf3KIRuD0hG6ldkFEZNCjRxiC+3i6kkWUUbiJQayP28iwG35cEmAbe98585BYV0A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "^2.4.2",
|
||||
"source-map": "^0.6.1",
|
||||
"supports-color": "^6.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"supports-color": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
|
||||
"integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
}
|
||||
"colorette": "^1.2.2",
|
||||
"nanoid": "^3.1.23",
|
||||
"source-map-js": "^0.6.2"
|
||||
}
|
||||
},
|
||||
"postcss-helpers": {
|
||||
@@ -9942,8 +10182,36 @@
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"postcss": "^7.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"postcss": {
|
||||
"version": "7.0.36",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz",
|
||||
"integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "^2.4.2",
|
||||
"source-map": "^0.6.1",
|
||||
"supports-color": "^6.1.0"
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
|
||||
"integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"postcss-value-parser": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz",
|
||||
"integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==",
|
||||
"dev": true
|
||||
},
|
||||
"posthtml": {
|
||||
"version": "0.11.6",
|
||||
"resolved": "https://registry.npmjs.org/posthtml/-/posthtml-0.11.6.tgz",
|
||||
@@ -10826,6 +11094,12 @@
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"dev": true
|
||||
},
|
||||
"source-map-js": {
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz",
|
||||
"integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==",
|
||||
"dev": true
|
||||
},
|
||||
"source-map-resolve": {
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz",
|
||||
@@ -11267,6 +11541,16 @@
|
||||
"resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-1.2.0.tgz",
|
||||
"integrity": "sha1-bchFBSywjr78GHRyO1jySmSMO28="
|
||||
},
|
||||
"tiny-glob": {
|
||||
"version": "0.2.9",
|
||||
"resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz",
|
||||
"integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"globalyzer": "0.1.0",
|
||||
"globrex": "^0.1.2"
|
||||
}
|
||||
},
|
||||
"to-array": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",
|
||||
|
||||
@@ -20,12 +20,15 @@
|
||||
"svg4everybody": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^10.3.4",
|
||||
"browser-sync": "^2.26.13",
|
||||
"concat": "^1.0.3",
|
||||
"esbuild": "^0.12.28",
|
||||
"kleur": "^4.1.4",
|
||||
"node-notifier": "^10.0.0",
|
||||
"node-sass": "^6.0.1",
|
||||
"svg-mixer": "^2.3.14"
|
||||
"postcss": "^8.3.6",
|
||||
"svg-mixer": "^2.3.14",
|
||||
"tiny-glob": "^0.2.9"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>Boilerplate</title>
|
||||
<title>Email | Locomotive Boilerplate</title>
|
||||
</head>
|
||||
<body leftmargin="0" marginwidth="0" topmargin="0" marginheight="0" offset="0">
|
||||
<center>
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,2 +0,0 @@
|
||||
|
||||
/*# sourceMappingURL=critical.css.map */
|
||||
1
www/assets/styles/critical.css.map
Normal file
1
www/assets/styles/critical.css.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":[],"names":[],"mappings":"","file":"critical.css"}
|
||||
File diff suppressed because one or more lines are too long
1
www/assets/styles/main.css.map
Normal file
1
www/assets/styles/main.css.map
Normal file
File diff suppressed because one or more lines are too long
@@ -2,7 +2,7 @@
|
||||
<html class="is-loading" lang="en" data-page="page">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Form | Boilerplate</title>
|
||||
<title>Form | Locomotive Boilerplate</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<div data-load-container>
|
||||
<div class="o-scroll" data-module-scroll="main">
|
||||
<header data-scroll-section>
|
||||
<a href="/"><h1>Boilerplate</h1></a>
|
||||
<a href="/"><h1>Locomotive Boilerplate</h1></a>
|
||||
<nav>
|
||||
<ul>
|
||||
<li><a href="images.html">Images</a></li>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<html class="is-loading" lang="en" data-page="home">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Images | Boilerplate</title>
|
||||
<title>Images | Locomotive Boilerplate</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<div data-load-container>
|
||||
<div class="o-scroll" data-module-scroll="main">
|
||||
<header data-scroll-section>
|
||||
<a href="/"><h1>Boilerplate</h1></a>
|
||||
<a href="/"><h1>Locomotive Boilerplate</h1></a>
|
||||
<nav>
|
||||
<ul>
|
||||
<li><a href="images.html">Images</a></li>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Boilerplate</title>
|
||||
<title>Locomotive Boilerplate</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
<div class="o-scroll" data-module-scroll="main">
|
||||
<header data-scroll-section>
|
||||
<a href="/">
|
||||
<h1>Boilerplate</h1>
|
||||
<h1>Locomotive Boilerplate</h1>
|
||||
</a>
|
||||
<nav>
|
||||
<ul>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "Boilerplate",
|
||||
"name": "Locomotive Boilerplate",
|
||||
"short_name": "Boilerplate",
|
||||
"icons": [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user