mirror of
https://github.com/locomotivemtl/locomotive-boilerplate.git
synced 2026-01-15 00:55:08 +08:00
Compare commits
37 Commits
mcaskill/b
...
feature/ba
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c19d14765 | ||
|
|
f1544d24f9 | ||
|
|
26f261ce47 | ||
|
|
ce0788bdc9 | ||
|
|
32ba1c0eeb | ||
|
|
5199ee2025 | ||
|
|
d6c8fdac23 | ||
|
|
15a4f2e64f | ||
|
|
9e35894ef1 | ||
|
|
cabeba55c0 | ||
|
|
47974a77a9 | ||
|
|
e8b2a86798 | ||
|
|
53beae26b0 | ||
|
|
9a01c0f17f | ||
|
|
97d9f1ec00 | ||
|
|
8b8b267e9d | ||
|
|
822cf7daa8 | ||
|
|
7f452f1fcc | ||
|
|
5010560ee3 | ||
|
|
0cfb3fbc7d | ||
|
|
86f88c3f14 | ||
|
|
48bd911804 | ||
|
|
d49d3eabb2 | ||
|
|
28aa6c7de6 | ||
|
|
38dd28832e | ||
|
|
757c26c772 | ||
|
|
5e07473396 | ||
|
|
c9056b27d8 | ||
|
|
38a6c73d2f | ||
|
|
9d18205b0f | ||
|
|
1e7e90c8aa | ||
|
|
47007cddaf | ||
|
|
5dd3fa843f | ||
|
|
a5623d3122 | ||
|
|
67e1fae8f4 | ||
|
|
a95fe4523c | ||
|
|
eadc414329 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,3 +1,5 @@
|
||||
node_modules
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
loconfig.*.json
|
||||
!loconfig.example.json
|
||||
|
||||
257
README.md
257
README.md
@@ -4,230 +4,95 @@
|
||||
</a>
|
||||
</p>
|
||||
<h1 align="center">Locomotive Boilerplate</h1>
|
||||
<p align="center">Front-end boilerplate for projects by Locomotive.</p>
|
||||
<p align="center">Front-end boilerplate for projects by <a href="https://locomotive.ca/">Locomotive</a>.</p>
|
||||
|
||||
## Requirements
|
||||
## Features
|
||||
|
||||
| Name | Version |
|
||||
| ---------- | -------- |
|
||||
| [Node] | >= 14.17 |
|
||||
| [NPM] | >= 6.0 |
|
||||
* Uses a custom [task runner](docs/development.md) for handling assets.
|
||||
* Uses [BrowserSync] for fast development and testing in browsers.
|
||||
* Uses [Sass] for a feature rich superset of CSS.
|
||||
* Uses [ESBuild] for extremely fast processing of JS/ES modules.
|
||||
* Uses [SVG Mixer] for processing SVG files and generating spritesheets.
|
||||
* Uses [ITCSS] for a sane and scalable CSS architecture.
|
||||
* Uses [Locomotive Scroll] for smooth scrolling with parallax effects.
|
||||
|
||||
[Node]: https://nodejs.org/
|
||||
[NPM]: https://npmjs.com/
|
||||
Learn more about [languages and technologies](docs/technologies.md).
|
||||
|
||||
You can use [nvm](https://github.com/nvm-sh/nvm) to install the node version in `.nvmrc`.
|
||||
## Getting started
|
||||
|
||||
## Installation
|
||||
Make sure you have the following installed:
|
||||
|
||||
* [Node] — at least 14.17, the latest LTS is recommended.
|
||||
* [NPM] — at least 6.0, the latest LTS is recommended.
|
||||
|
||||
> 💡 You can use [NVM] to install and use different versions of Node via the command-line.
|
||||
|
||||
```sh
|
||||
npm i
|
||||
# Clone the repository.
|
||||
git clone https://github.com/locomotivemtl/locomotive-boilerplate.git my-new-project
|
||||
|
||||
# Enter the newly-cloned directory.
|
||||
cd my-new-project
|
||||
```
|
||||
|
||||
## Usage
|
||||
Then replace the original remote repository with your project's repository.
|
||||
|
||||
```sh
|
||||
# start it
|
||||
npm start
|
||||
```
|
||||
Then update the following files to suit your project:
|
||||
|
||||
## Configuration
|
||||
|
||||
There are a few occurrences that should be renamed for your project:
|
||||
|
||||
* [package.json](package.json):
|
||||
* [`README.md`](README.md):
|
||||
The file you are currently reading.
|
||||
* [`package.json`](package.json):
|
||||
* Package name: `@locomotivemtl/boilerplate`
|
||||
* Package title: `Locomotive Boilerplate`
|
||||
* [package-lock.json](package-lock.json):
|
||||
* [`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`.
|
||||
* [`loconfig.json`](loconfig.json):
|
||||
* BrowserSync proxy URL: `locomotive-boilerplate.test`
|
||||
Remove `paths.url` to use BrowserSync's built-in server which uses `paths.dest`.
|
||||
* View path: `./views/boilerplate/template`
|
||||
* [environment.js](assets/scripts/utils/environment.js):
|
||||
* [`environment.js`](assets/scripts/utils/environment.js):
|
||||
* Application name: `Boilerplate`
|
||||
* [site.webmanifest](www/site.webmanifest):
|
||||
* [`site.webmanifest`](www/site.webmanifest):
|
||||
* Manifest name: `Locomotive Boilerplate`
|
||||
* Manifest short name: `Boilerplate`
|
||||
* HTML files:
|
||||
* Page title: `Locomotive Boilerplate`
|
||||
|
||||
## Build
|
||||
## Installation
|
||||
|
||||
#### Tasks
|
||||
```sh
|
||||
# watch
|
||||
# Switch to recommended Node version from .nvmrc
|
||||
nvm use
|
||||
|
||||
# Install dependencies from package.json
|
||||
npm install
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
```sh
|
||||
# Start development server, watch for changes, and compile assets
|
||||
npm start
|
||||
|
||||
# build
|
||||
# Compile and minify assets
|
||||
npm run build
|
||||
```
|
||||
|
||||
## Styles
|
||||
Learn more about [development and building](docs/development.md).
|
||||
|
||||
[Sass](https://github.com/sass/node-sass) is our CSS preprocessor. [Autoprefixer](https://github.com/postcss/autoprefixer) is also included.
|
||||
## Documentation
|
||||
|
||||
#### Architecture
|
||||
* [Development and building](docs/development.md)
|
||||
* [Languages and technologies](docs/technologies.md)
|
||||
|
||||
[ITCSS](https://github.com/itcss) is our CSS architecture.
|
||||
|
||||
* `settings`: Global variables, site-wide settings, config switches, etc.
|
||||
* `tools`: Site-wide mixins and functions.
|
||||
* `generic`: Low-specificity, far-reaching rulesets (e.g. resets).
|
||||
* `elements`: Unclassed HTML elements (e.g. `a {}`, `blockquote {}`, `address {}`).
|
||||
* `objects`: Objects, abstractions, and design patterns (e.g. `.o-layout {}`).
|
||||
* `components`: Discrete, complete chunks of UI (e.g. `.c-carousel {}`).
|
||||
* `utilities`: High-specificity, very explicit selectors. Overrides and helper
|
||||
classes (e.g. `.u-hidden {}`)
|
||||
|
||||
[_source_](https://github.com/inuitcss/inuitcss#css-directory-structure)
|
||||
|
||||
#### Naming
|
||||
|
||||
We use a simplified [BEM](https://github.com/bem) syntax.
|
||||
|
||||
```
|
||||
.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.
|
||||
* `c-`: Component is a concrete, implementation-specific piece of UI. All of the changes you make to its styles should be detectable in the context you’re currently looking at. Modifying these styles should be safe and have no side effects.
|
||||
* `u-`: Utility has a very specific role (often providing only one declaration) and should not be bound onto or changed. It can be reused and is not tied to any specific piece of UI.
|
||||
* `s-`: Scope creates a new styling context. Similar to a Theme, but not necessarily cosmetic, these should be used sparingly—they can be open to abuse and lead to poor CSS if not used wisely.
|
||||
* `is-`, `has-`: Is currently styled a certain way because of a state or condition. It tells us that the DOM currently has a temporary, optional, or short-lived style applied to it due to a certain state being invoked.
|
||||
|
||||
[_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">
|
||||
<div class="o-layout_item u-1/2@from-medium">
|
||||
<div class="c-block_heading o-h -medium">Heading</div>
|
||||
</div>
|
||||
<div class="o-layout_item u-1/2@from-medium">
|
||||
<a class="c-block_button o-button -outline" href="#">Button</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
```scss
|
||||
.c-block {
|
||||
&.-large {
|
||||
padding: rem(60px);
|
||||
}
|
||||
}
|
||||
|
||||
.c-block_heading {
|
||||
@media (max-width: $to-medium) {
|
||||
.c-block.-large & {
|
||||
margin-bottom: rem(40px);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 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.
|
||||
|
||||
[_source_](https://github.com/modularorg/modularjs#why)
|
||||
|
||||
#### Example
|
||||
|
||||
```html
|
||||
<div data-module-example>
|
||||
<div data-example="main">
|
||||
<h2>Example</h2>
|
||||
</div>
|
||||
<button data-example="load">More</button>
|
||||
</div>
|
||||
```
|
||||
|
||||
```js
|
||||
import { module } from 'modujs';
|
||||
|
||||
export default class extends module {
|
||||
constructor(m) {
|
||||
super(m);
|
||||
|
||||
this.events = {
|
||||
click: {
|
||||
load: 'loadMore'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loadMore() {
|
||||
this.$('main')[0].classList.add('is-loading');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
[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>
|
||||
<a href="/page" data-load="transitionName">Page</a>
|
||||
</nav>
|
||||
<div data-load-container>
|
||||
<img data-load-src="assets/images/hello.jpg">
|
||||
</div>
|
||||
```
|
||||
```js
|
||||
import modularLoad from 'modularload';
|
||||
|
||||
this.load = new modularLoad({
|
||||
enterDelay: 300,
|
||||
transitions: {
|
||||
transitionName: {
|
||||
enterDelay: 450
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
[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.
|
||||
|
||||
#### 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';
|
||||
|
||||
this.scroll = new LocomotiveScroll({
|
||||
el: this.el,
|
||||
smooth: true
|
||||
});
|
||||
````
|
||||
|
||||
[Learn more](https://github.com/locomotivemtl/locomotive-scroll)
|
||||
[BrowserSync]: https://npmjs.com/package/browser-sync
|
||||
[ESBuild]: https://npmjs.com/package/esbuild
|
||||
[ITCSS]: https://itcss.io/
|
||||
[Locomotive Scroll]: https://npmjs.com/package/locomotive-scroll
|
||||
[modularJS]: https://npmjs.com/package/modujs
|
||||
[modularLoad]: https://npmjs.com/package/modularload
|
||||
[Sass]: https://sass-lang.com/
|
||||
[SVG Mixer]: https://npmjs.com/package/svg-mixer
|
||||
[Node]: https://nodejs.org/
|
||||
[NPM]: https://npmjs.com/
|
||||
[NVM]: https://github.com/nvm-sh/nvm
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import modular from 'modujs';
|
||||
import * as modules from './modules';
|
||||
import globals from './globals';
|
||||
import { html } from './utils/environment';
|
||||
import { $html } from './utils/dom';
|
||||
import config from './config';
|
||||
|
||||
const app = new modular({
|
||||
modules: modules
|
||||
@@ -28,8 +29,8 @@ function init() {
|
||||
|
||||
app.init(app);
|
||||
|
||||
html.classList.add('is-loaded');
|
||||
html.classList.add('is-ready');
|
||||
html.classList.remove('is-loading');
|
||||
$html.classList.add(config.CSS_CLASS.LOADED);
|
||||
$html.classList.add(config.CSS_CLASS.READY);
|
||||
$html.classList.remove(config.CSS_CLASS.LOADING);
|
||||
}
|
||||
|
||||
|
||||
15
assets/scripts/config.js
Normal file
15
assets/scripts/config.js
Normal file
@@ -0,0 +1,15 @@
|
||||
const env = process.env.NODE_ENV
|
||||
|
||||
export default config = Object.freeze({
|
||||
// Environments
|
||||
ENV: env,
|
||||
IS_PROD: env === 'production',
|
||||
IS_DEV: env === 'development',
|
||||
|
||||
// CSS class names
|
||||
CSS_CLASS: {
|
||||
LOADING: 'is-loading',
|
||||
READY: 'is-ready',
|
||||
LOADED: 'is-loaded',
|
||||
},
|
||||
})
|
||||
@@ -1,5 +1,6 @@
|
||||
import { module } from 'modujs';
|
||||
import modularLoad from 'modularload';
|
||||
import barba from '@barba/core';
|
||||
import config from '../config'
|
||||
|
||||
export default class extends module {
|
||||
constructor(m) {
|
||||
@@ -7,16 +8,20 @@ export default class extends module {
|
||||
}
|
||||
|
||||
init() {
|
||||
const load = new modularLoad({
|
||||
enterDelay: 0,
|
||||
transitions: {
|
||||
customTransition: {}
|
||||
}
|
||||
});
|
||||
|
||||
load.on('loaded', (transition, oldContainer, newContainer) => {
|
||||
this.call('destroy', oldContainer, 'app');
|
||||
this.call('update', newContainer, 'app');
|
||||
barba.init({
|
||||
debug: config.IS_DEV,
|
||||
schema: {
|
||||
prefix: 'data-load',
|
||||
},
|
||||
transitions: [{
|
||||
name: 'default-transition',
|
||||
leave: (data) => {
|
||||
this.call('destroy', data.current.container, 'app');
|
||||
},
|
||||
enter: (data) => {
|
||||
this.call('update', data.next.container, 'app');
|
||||
}
|
||||
}]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
4
assets/scripts/utils/dom.js
Normal file
4
assets/scripts/utils/dom.js
Normal file
@@ -0,0 +1,4 @@
|
||||
const $html = document.documentElement;
|
||||
const $body = document.body;
|
||||
|
||||
export { $html, $body };
|
||||
@@ -1,8 +0,0 @@
|
||||
const APP_NAME = 'Boilerplate';
|
||||
const DATA_API_KEY = '.data-api';
|
||||
|
||||
const html = document.documentElement;
|
||||
const body = document.body;
|
||||
const isDebug = html.hasAttribute('data-debug');
|
||||
|
||||
export { APP_NAME, DATA_API_KEY, html, body, isDebug };
|
||||
@@ -1,6 +1,5 @@
|
||||
import { isFunction } from './is';
|
||||
import { arrayContains, findByKeyValue, removeFromArray } from './array';
|
||||
import { $document, $window, $html, $body } from './environment';
|
||||
|
||||
const CALLBACKS = {
|
||||
hidden: [],
|
||||
@@ -22,7 +21,7 @@ const PREFIX = 'v-';
|
||||
let UUID = 0;
|
||||
|
||||
// Main event
|
||||
$document.on('visibilitychange', function(event) {
|
||||
document.addEventListener('visibilitychange', function(event) {
|
||||
if (document.hidden) {
|
||||
onDocumentChange('hidden');
|
||||
} else {
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
// ==========================================================================
|
||||
// Components / Buttons
|
||||
// ==========================================================================
|
||||
|
||||
.c-button {
|
||||
padding: rem(15px) rem(20px);
|
||||
background-color: lightgray;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// ==========================================================================
|
||||
// Form
|
||||
// Components / Form
|
||||
// ==========================================================================
|
||||
|
||||
.c-form {
|
||||
|
||||
}
|
||||
@@ -12,6 +13,7 @@
|
||||
|
||||
// Label
|
||||
// ==========================================================================
|
||||
|
||||
.c-form_label {
|
||||
display: block;
|
||||
margin-bottom: rem(10px);
|
||||
@@ -19,6 +21,7 @@
|
||||
|
||||
// Input
|
||||
// ==========================================================================
|
||||
|
||||
$input-icon-color: 424242; // No #
|
||||
|
||||
.c-form_input {
|
||||
@@ -41,6 +44,7 @@ $input-icon-color: 424242; // No #
|
||||
|
||||
// Checkbox
|
||||
// ==========================================================================
|
||||
|
||||
$checkbox: rem(18px);
|
||||
$checkbox-icon-color: $input-icon-color;
|
||||
|
||||
@@ -108,6 +112,7 @@ $checkbox-icon-color: $input-icon-color;
|
||||
|
||||
// Radio
|
||||
// ==========================================================================
|
||||
|
||||
$radio-icon-color: $input-icon-color;
|
||||
|
||||
.c-form_radioLabel {
|
||||
@@ -129,6 +134,7 @@ $radio-icon-color: $input-icon-color;
|
||||
|
||||
// Select
|
||||
// =============================================================================
|
||||
|
||||
$select-icon: rem(40px);
|
||||
$select-icon-color: $input-icon-color;
|
||||
|
||||
@@ -163,6 +169,7 @@ $select-icon-color: $input-icon-color;
|
||||
|
||||
// Textarea
|
||||
// =============================================================================
|
||||
|
||||
.c-form_textarea {
|
||||
@extend .c-form_input;
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
// ==========================================================================
|
||||
// Components / Headings
|
||||
// ==========================================================================
|
||||
|
||||
.c-heading {
|
||||
line-height: $line-height-h;
|
||||
margin-bottom: rem(30px);
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
// ==========================================================================
|
||||
// Components / Scrollbar
|
||||
// ==========================================================================
|
||||
|
||||
.c-scrollbar {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
// ==========================================================================
|
||||
// Critical CSS
|
||||
// ==========================================================================
|
||||
|
||||
$assets-path: "assets/";
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
// ==========================================================================
|
||||
// Base / Page
|
||||
// Elements / Document
|
||||
// ==========================================================================
|
||||
|
||||
//
|
||||
// Simple page-level setup.
|
||||
//
|
||||
// 1. Set the default `font-size` and `line-height` for the entire project,
|
||||
// sourced from our default variables.
|
||||
// 1. Include web fonts
|
||||
// 2. Ensure the page always fills at least the entire height of the viewport.
|
||||
//
|
||||
// 3. Set the default `font-size` and `line-height` for the entire project,
|
||||
// sourced from our default variables.
|
||||
|
||||
@include font-faces($font-faces, $font-dir); // [1]
|
||||
|
||||
html {
|
||||
min-height: 100%; /* [2] */
|
||||
min-height: 100%; // [2]
|
||||
line-height: $line-height;
|
||||
font-family: ff("sans");
|
||||
color: $color;
|
||||
font-family: $font-family;
|
||||
line-height: $line-height; /* [1] */
|
||||
line-height: $line-height; // [3]
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
|
||||
@@ -30,7 +33,7 @@ html {
|
||||
}
|
||||
|
||||
@media (min-width: $from-large) and (max-width: $to-huge) {
|
||||
font-size: $font-size; /* [1] */
|
||||
font-size: $font-size; // [1]
|
||||
}
|
||||
|
||||
@media (min-width: $from-huge) and (max-width: $to-gigantic) {
|
||||
@@ -1,36 +0,0 @@
|
||||
// ==========================================================================
|
||||
// Base / Fonts
|
||||
// ==========================================================================
|
||||
|
||||
// @include font-face(
|
||||
// $font-foobar,
|
||||
// "fonts/Foobar/Regular"
|
||||
// ) {
|
||||
// font-style: normal;
|
||||
// font-weight: 400;
|
||||
// }
|
||||
|
||||
// @include font-face(
|
||||
// $font-foobar,
|
||||
// "fonts/Foobar/Medium"
|
||||
// ) {
|
||||
// font-style: normal;
|
||||
// font-weight: 500;
|
||||
// }
|
||||
|
||||
// @include font-face(
|
||||
// $font-foobar,
|
||||
// "fonts/Foobar/Semibold"
|
||||
// ) {
|
||||
// font-style: normal;
|
||||
// font-weight: 600;
|
||||
// }
|
||||
|
||||
// @include font-face(
|
||||
// $font-bazqux,
|
||||
// "fonts/Bazqux/Regular",
|
||||
// ("eot", "woff2", "woff", "ttf")
|
||||
// ) {
|
||||
// font-style: normal;
|
||||
// font-weight: 400;
|
||||
// }
|
||||
@@ -2,34 +2,33 @@
|
||||
// Generic / Buttons
|
||||
// ==========================================================================
|
||||
|
||||
//
|
||||
// 1. Allow us to style box model properties.
|
||||
// 2. Fixes odd inner spacing in IE7.
|
||||
// 3. Reset/normalize some styles.
|
||||
// 4. Line different sized buttons up a little nicer.
|
||||
// 5. Make buttons inherit font styles (often necessary when styling `input`s as buttons).
|
||||
// 6. Force all button-styled elements to appear clickable.
|
||||
//
|
||||
|
||||
button,
|
||||
.c-button {
|
||||
@include u-hocus {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
display: inline-block; /* [1] */
|
||||
overflow: visible; /* [2] */
|
||||
margin: 0; /* [3] */
|
||||
display: inline-block; // [1]
|
||||
overflow: visible; // [2]
|
||||
margin: 0; // [3]
|
||||
padding: 0;
|
||||
outline: 0;
|
||||
border: 0;
|
||||
background: none transparent;
|
||||
color: inherit;
|
||||
vertical-align: middle; /* [4] */
|
||||
text-align: center; /* [3] */
|
||||
vertical-align: middle; // [4]
|
||||
text-align: center; // [3]
|
||||
text-decoration: none;
|
||||
text-transform: none;
|
||||
font: inherit; /* [5] */
|
||||
font: inherit; // [5]
|
||||
line-height: normal;
|
||||
cursor: pointer; /* [6] */
|
||||
cursor: pointer; // [6]
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
@@ -31,11 +31,11 @@ select {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
// Remove Firefox :focus dotted outline, breaks color inherit
|
||||
// &:-moz-focusring {
|
||||
// color: transparent;
|
||||
// text-shadow: 0 0 0 #000000; // Text :focus color
|
||||
// }
|
||||
// // Remove Firefox :focus dotted outline, breaks color inherit
|
||||
// // &:-moz-focusring {
|
||||
// // color: transparent;
|
||||
// // text-shadow: 0 0 0 #000000; // Text :focus color
|
||||
// // }
|
||||
}
|
||||
|
||||
textarea {
|
||||
|
||||
@@ -6,11 +6,10 @@ html {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
//
|
||||
// Add the correct display in IE 10-.
|
||||
// 1. Add the correct display in IE.
|
||||
//
|
||||
template, /* [1] */
|
||||
|
||||
template, // [1]
|
||||
[hidden] {
|
||||
display: none;
|
||||
}
|
||||
@@ -62,11 +61,10 @@ h1, h2, h3, h4, h5, h6 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Single taps should be dispatched immediately on clickable elements
|
||||
*/
|
||||
// 1. Single taps should be dispatched immediately on clickable elements
|
||||
|
||||
a, area, button, input, label, select, textarea, [tabindex] {
|
||||
-ms-touch-action: manipulation; /* [1] */
|
||||
-ms-touch-action: manipulation; // [1]
|
||||
touch-action: manipulation;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,57 +2,51 @@
|
||||
// Generic / Media
|
||||
// ==========================================================================
|
||||
|
||||
//
|
||||
// 1. Setting `vertical-align` removes the whitespace that appears under `img`
|
||||
// elements when they are dropped into a page as-is. Safer alternative to
|
||||
// using `display: block;`.
|
||||
//
|
||||
|
||||
audio,
|
||||
canvas,
|
||||
iframe,
|
||||
img,
|
||||
svg,
|
||||
video {
|
||||
vertical-align: middle; /* [1] */
|
||||
vertical-align: middle; // [1]
|
||||
}
|
||||
|
||||
//
|
||||
// Add the correct display in iOS 4-7.
|
||||
//
|
||||
|
||||
audio:not([controls]) {
|
||||
display: none;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
//
|
||||
// 2. Fluid media for responsive purposes.
|
||||
//
|
||||
|
||||
img,
|
||||
svg {
|
||||
max-width: 100%; /* [2] */
|
||||
max-width: 100%; // [2]
|
||||
height: auto;
|
||||
|
||||
//
|
||||
// 4. If a `width` and/or `height` attribute have been explicitly defined, let’s
|
||||
// not make the image fluid.
|
||||
//
|
||||
&[width], /* [4] */
|
||||
// 4. If a `width` and/or `height` attribute have been explicitly defined,
|
||||
// let’s not make the image fluid.
|
||||
|
||||
&[width], // [4]
|
||||
&[height] {
|
||||
/* [4] */
|
||||
// [4]
|
||||
max-width: none;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// 4. Offset `alt` text from surrounding copy.
|
||||
//
|
||||
|
||||
img {
|
||||
font-style: italic; /* [4] */
|
||||
font-style: italic; // [4]
|
||||
}
|
||||
|
||||
//
|
||||
// 5. SVG elements should fallback to their surrounding text color.
|
||||
//
|
||||
|
||||
svg {
|
||||
fill: currentColor; /* [5] */
|
||||
fill: currentColor; // [5]
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
// Settings
|
||||
// ==========================================================================
|
||||
|
||||
@import "settings/config.eases";
|
||||
@import "settings/config.colors";
|
||||
@import "settings/config";
|
||||
@@ -11,6 +12,7 @@
|
||||
// ==========================================================================
|
||||
// Tools
|
||||
// ==========================================================================
|
||||
|
||||
@import "tools/functions";
|
||||
@import "tools/mixins";
|
||||
@import "tools/fonts";
|
||||
@@ -20,6 +22,7 @@
|
||||
|
||||
// Generic
|
||||
// ==========================================================================
|
||||
|
||||
@import "node_modules/normalize.css/normalize";
|
||||
@import "generic/generic";
|
||||
@import "generic/media";
|
||||
@@ -28,11 +31,12 @@
|
||||
|
||||
// Elements
|
||||
// ==========================================================================
|
||||
@import "elements/fonts";
|
||||
@import "elements/page";
|
||||
|
||||
@import "elements/document";
|
||||
|
||||
// Objects
|
||||
// ==========================================================================
|
||||
|
||||
@import "objects/scroll";
|
||||
@import "objects/container";
|
||||
@import "objects/ratio";
|
||||
@@ -46,6 +50,7 @@
|
||||
|
||||
// Components
|
||||
// ==========================================================================
|
||||
|
||||
@import "components/scrollbar";
|
||||
@import "components/heading";
|
||||
@import "components/button";
|
||||
@@ -57,6 +62,7 @@
|
||||
|
||||
// Utilities
|
||||
// ==========================================================================
|
||||
|
||||
@import "utilities/ratio";
|
||||
@import "utilities/widths";
|
||||
// @import "utilities/align";
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// Objects / Container
|
||||
// ==========================================================================
|
||||
|
||||
//
|
||||
// Page-level constraining and wrapping elements.
|
||||
//
|
||||
// > In programming languages the word *container* is generally used for structures
|
||||
@@ -10,7 +9,6 @@
|
||||
// > A *wrapper* instead is something that wraps around a single object to provide
|
||||
// more functionalities and interfaces to it.
|
||||
// @link http://stackoverflow.com/a/13202141/140357
|
||||
//
|
||||
|
||||
.o-container {
|
||||
margin-right: auto;
|
||||
|
||||
@@ -2,45 +2,42 @@
|
||||
// Objects / Crop
|
||||
// ==========================================================================
|
||||
|
||||
//
|
||||
// @link https://github.com/inuitcss/inuitcss/blob/19d0c7e/objects/_objects.crop.scss
|
||||
//
|
||||
|
||||
|
||||
// A list of cropping ratios that get generated as modifier classes.
|
||||
|
||||
$crop-ratios: (
|
||||
(2:1),
|
||||
(4:3),
|
||||
(16:9),
|
||||
) !default;
|
||||
|
||||
/**
|
||||
* Provide a cropping container in order to display media (usually images)
|
||||
* cropped to certain ratios.
|
||||
*
|
||||
* 1. Set up a positioning context in which the image can sit.
|
||||
* 2. This is the crucial part: where the cropping happens.
|
||||
*/
|
||||
// Provide a cropping container in order to display media (usually images)
|
||||
// cropped to certain ratios.
|
||||
//
|
||||
// 1. Set up a positioning context in which the image can sit.
|
||||
// 2. This is the crucial part: where the cropping happens.
|
||||
|
||||
.o-crop {
|
||||
position: relative; /* [1] */
|
||||
position: relative; // [1]
|
||||
display: block;
|
||||
overflow: hidden; /* [2] */
|
||||
overflow: hidden; // [2]
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply this class to the content (usually `img`) that needs cropping.
|
||||
*
|
||||
* 1. Image’s default positioning is top-left in the cropping box.
|
||||
* 2. Make sure the media doesn’t stop itself too soon.
|
||||
*/
|
||||
// Apply this class to the content (usually `img`) that needs cropping.
|
||||
//
|
||||
// 1. Image’s default positioning is top-left in the cropping box.
|
||||
// 2. Make sure the media doesn’t stop itself too soon.
|
||||
|
||||
.o-crop_content {
|
||||
position: absolute;
|
||||
top: 0; /* [1] */
|
||||
left: 0; /* [1] */
|
||||
max-width: none; /* [2] */
|
||||
top: 0; // [1]
|
||||
left: 0; // [1]
|
||||
max-width: none; // [2]
|
||||
|
||||
// We can position the media in different locations within the cropping area.
|
||||
|
||||
/**
|
||||
* We can position the media in different locations within the cropping area.
|
||||
*/
|
||||
&.-right {
|
||||
right: 0;
|
||||
left: auto;
|
||||
@@ -60,22 +57,20 @@ $crop-ratios: (
|
||||
|
||||
/* stylelint-disable */
|
||||
|
||||
//
|
||||
// Generate a series of crop classes to be used like so:
|
||||
//
|
||||
// @example
|
||||
// <div class="o-crop -16:9">
|
||||
//
|
||||
//
|
||||
|
||||
.o-crop {
|
||||
@each $crop in $crop-ratios {
|
||||
@each $antecedent, $consequent in $crop {
|
||||
@if (type-of($antecedent) != number) {
|
||||
@error "`#{$antecedent}` needs to be a number."
|
||||
@error "`#{$antecedent}` needs to be a number.";
|
||||
}
|
||||
|
||||
@if (type-of($consequent) != number) {
|
||||
@error "`#{$consequent}` needs to be a number."
|
||||
@error "`#{$consequent}` needs to be a number.";
|
||||
}
|
||||
|
||||
&.-#{$antecedent}\:#{$consequent} {
|
||||
|
||||
@@ -2,41 +2,41 @@
|
||||
// Objects / Layout
|
||||
// ==========================================================================
|
||||
|
||||
//
|
||||
// Grid-like layout system.
|
||||
//
|
||||
// The layout object provides us with a column-style layout system. This file
|
||||
// contains the basic structural elements, but classes should be complemented
|
||||
// with width utilities, for example:
|
||||
//
|
||||
// @example
|
||||
// <div class="o-layout">
|
||||
// <div class="o-layout_item u-1/1 u-1/3@medium">
|
||||
// </div>
|
||||
// <div class="o-layout_item u-1/2 u-1/3@medium">
|
||||
// </div>
|
||||
// <div class="o-layout_item u-1/2 u-1/3@medium">
|
||||
// </div>
|
||||
// </div>
|
||||
//
|
||||
// We can also manipulate entire layout systems by adding a series of modifiers
|
||||
// to the `.o-layout` block. For example:
|
||||
//
|
||||
// @example
|
||||
// <div class="o-layout -reverse">
|
||||
//
|
||||
// This will reverse the displayed order of the system so that it runs in the
|
||||
// opposite order to our source, effectively flipping the system over.
|
||||
//
|
||||
// @example
|
||||
// <div class="o-layout -[right|center]">
|
||||
//
|
||||
// This will cause the system to fill up from either the centre or the right
|
||||
// hand side. Default behaviour is to fill up the layout system from the left.
|
||||
//
|
||||
// @requires tools/layout
|
||||
// @link https://github.com/inuitcss/inuitcss/blob/0420ba8/objects/_objects.layout.scss
|
||||
//
|
||||
////
|
||||
/// Grid-like layout system.
|
||||
///
|
||||
/// The layout object provides us with a column-style layout system. This file
|
||||
/// contains the basic structural elements, but classes should be complemented
|
||||
/// with width utilities, for example:
|
||||
///
|
||||
/// @example
|
||||
/// <div class="o-layout">
|
||||
/// <div class="o-layout_item u-1/1 u-1/3@medium">
|
||||
/// </div>
|
||||
/// <div class="o-layout_item u-1/2 u-1/3@medium">
|
||||
/// </div>
|
||||
/// <div class="o-layout_item u-1/2 u-1/3@medium">
|
||||
/// </div>
|
||||
/// </div>
|
||||
///
|
||||
/// We can also manipulate entire layout systems by adding a series of modifiers
|
||||
/// to the `.o-layout` block. For example:
|
||||
///
|
||||
/// @example
|
||||
/// <div class="o-layout -reverse">
|
||||
///
|
||||
/// This will reverse the displayed order of the system so that it runs in the
|
||||
/// opposite order to our source, effectively flipping the system over.
|
||||
///
|
||||
/// @example
|
||||
/// <div class="o-layout -[right|center]">
|
||||
///
|
||||
/// This will cause the system to fill up from either the centre or the right
|
||||
/// hand side. Default behaviour is to fill up the layout system from the left.
|
||||
///
|
||||
/// @requires tools/layout
|
||||
/// @link https://github.com/inuitcss/inuitcss/blob/0420ba8/objects/_objects.layout.scss
|
||||
////
|
||||
|
||||
.o-layout {
|
||||
@include o-layout;
|
||||
|
||||
@@ -2,14 +2,13 @@
|
||||
// Objects / Ratio
|
||||
// ==========================================================================
|
||||
|
||||
/**
|
||||
* Create ratio-bound content blocks, to keep media (e.g. images, videos) in
|
||||
* their correct aspect ratios.
|
||||
*
|
||||
* http://alistapart.com/article/creating-intrinsic-ratios-for-video
|
||||
*
|
||||
* 1. Default cropping is a 1:1 ratio (i.e. a perfect square).
|
||||
*/
|
||||
// Create ratio-bound content blocks, to keep media (e.g. images, videos) in
|
||||
// their correct aspect ratios.
|
||||
//
|
||||
// http://alistapart.com/article/creating-intrinsic-ratios-for-video
|
||||
//
|
||||
// 1. Default cropping is a 1:1 ratio (i.e. a perfect square).
|
||||
|
||||
.o-ratio {
|
||||
position: relative;
|
||||
display: block;
|
||||
@@ -17,7 +16,7 @@
|
||||
|
||||
&:before {
|
||||
display: block;
|
||||
padding-bottom: 100%; /* [1] */
|
||||
padding-bottom: 100%; // [1]
|
||||
width: 100%;
|
||||
content: "";
|
||||
}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
// ==========================================================================
|
||||
// Objects / Scroll
|
||||
// ==========================================================================
|
||||
|
||||
.o-scroll {
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
// ==========================================================================
|
||||
// Objects / Tables
|
||||
// ==========================================================================
|
||||
|
||||
.o-table {
|
||||
width: 100%;
|
||||
|
||||
/**
|
||||
* Force all cells within a table to occupy the same width as each other.
|
||||
*
|
||||
* @link https://developer.mozilla.org/en-US/docs/Web/CSS/table-layout#Values
|
||||
*/
|
||||
// Force all cells within a table to occupy the same width as each other.
|
||||
//
|
||||
// @link https://developer.mozilla.org/en-US/docs/Web/CSS/table-layout#Values
|
||||
|
||||
&.-fixed {
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
@@ -4,21 +4,25 @@
|
||||
|
||||
// Palette
|
||||
// =============================================================================
|
||||
|
||||
$white: #FFFFFF;
|
||||
$black: #000000;
|
||||
|
||||
// Specific
|
||||
// =============================================================================
|
||||
|
||||
// Link
|
||||
$link-color: #1A0DAB;
|
||||
$link-focus-color: #1A0DAB;
|
||||
$link-hover-color: darken(#1A0DAB, 10%);
|
||||
|
||||
// Selection
|
||||
$selection-text-color: #3297FD;
|
||||
$selection-background-color: #FFFFFF;
|
||||
|
||||
// Social Colors
|
||||
// =============================================================================
|
||||
|
||||
$facebook-color: #3B5998;
|
||||
$instagram-color: #E1306C;
|
||||
$youtube-color: #CD201F;
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
// ==========================================================================
|
||||
// Settings / Config / Eases
|
||||
// ==========================================================================
|
||||
|
||||
$Power1EaseOut: cubic-bezier(0.250, 0.460, 0.450, 0.940);
|
||||
$Power2EaseOut: cubic-bezier(0.215, 0.610, 0.355, 1.000);
|
||||
$Power3EaseOut: cubic-bezier(0.165, 0.840, 0.440, 1.000);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
// Context
|
||||
// =============================================================================
|
||||
|
||||
// The current stylesheet context. Available values: frontend, editor.
|
||||
$context: frontend !default;
|
||||
|
||||
@@ -12,15 +13,28 @@ $assets-path: "../" !default;
|
||||
|
||||
// Typefaces
|
||||
// =============================================================================
|
||||
$font-sans-serif: sans-serif;
|
||||
|
||||
$font-dir: "../fonts/";
|
||||
|
||||
$font-families: (
|
||||
"sans": ("Webfont Sans", "Helvetica Neue", Arial, sans-serif),
|
||||
// "serif": ("Webfont Serif", Georgia, serif)
|
||||
);
|
||||
|
||||
$font-faces: (
|
||||
// "Webfont Sans" "webfont-sans_regular" 400 normal,
|
||||
// "Webfont Sans" "webfont-sans_regular-italic" 400 italic,
|
||||
// "Webfont Serif" "webfont-sans_bold" 700 normal,
|
||||
);
|
||||
|
||||
// Typography
|
||||
// =============================================================================
|
||||
|
||||
// Base
|
||||
$font-size: 16px;
|
||||
$line-height: 24px / $font-size;
|
||||
$font-family: $font-sans-serif;
|
||||
$color: #222222;
|
||||
|
||||
// Headings
|
||||
$font-size-h1: 36px !default;
|
||||
$font-size-h2: 28px !default;
|
||||
@@ -29,6 +43,7 @@ $font-size-h4: 20px !default;
|
||||
$font-size-h5: 18px !default;
|
||||
$font-size-h6: 16px !default;
|
||||
$line-height-h: $line-height;
|
||||
|
||||
// Weights
|
||||
$light: 300;
|
||||
$normal: 400;
|
||||
@@ -37,21 +52,25 @@ $bold: 700;
|
||||
|
||||
// Transitions
|
||||
// =============================================================================
|
||||
|
||||
$speed: 0.3s;
|
||||
$easing: $Power2EaseOut;
|
||||
|
||||
// Spacing Units
|
||||
// =============================================================================
|
||||
|
||||
$unit: 60px;
|
||||
$unit-small: 30px;
|
||||
|
||||
// Container
|
||||
// ==========================================================================
|
||||
// =============================================================================
|
||||
|
||||
$container-width: 2000px;
|
||||
$padding: $unit;
|
||||
|
||||
// Breakpoints
|
||||
// =============================================================================
|
||||
|
||||
$from-tiny: 500px !default;
|
||||
$to-tiny: $from-tiny - 1 !default;
|
||||
$from-small: 700px !default;
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
//
|
||||
//
|
||||
// ==========================================================================
|
||||
// Tools / Family
|
||||
// ==========================================================================
|
||||
|
||||
// DOCS : https://lukyvj.github.io/family.scss/
|
||||
//
|
||||
//
|
||||
/// Select all children from the first to `$num`.
|
||||
/// @group with-arguments
|
||||
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
/// @param {number} $num - id of the child
|
||||
// Select all children from the first to `$num`.
|
||||
// @group with-arguments
|
||||
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
// @param {number} $num - id of the child
|
||||
|
||||
@mixin first($num) {
|
||||
@if $num == 1 {
|
||||
&:first-child {
|
||||
@@ -19,108 +21,118 @@
|
||||
}
|
||||
}
|
||||
|
||||
/// Select all children from the last to `$num`.
|
||||
/// @group with-arguments
|
||||
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
/// @param {number} $num - id of the child
|
||||
// Select all children from the last to `$num`.
|
||||
// @group with-arguments
|
||||
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
// @param {number} $num - id of the child
|
||||
|
||||
@mixin last($num) {
|
||||
&:nth-last-child(-n + #{$num}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
/// Select all children after the first to `$num`.
|
||||
/// @group with-arguments
|
||||
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
/// @param {number} $num - id of the child
|
||||
// Select all children after the first to `$num`.
|
||||
// @group with-arguments
|
||||
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
// @param {number} $num - id of the child
|
||||
|
||||
@mixin after-first($num) {
|
||||
&:nth-child(n + #{$num + 1}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
/// Select all children before `$num` from the last.
|
||||
/// @group with-arguments
|
||||
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
/// @param {number} $num - id of the child
|
||||
// Select all children before `$num` from the last.
|
||||
// @group with-arguments
|
||||
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
// @param {number} $num - id of the child
|
||||
|
||||
@mixin from-end($num) {
|
||||
&:nth-last-child(#{$num}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
/// Select all children between `$first` and `$last`.
|
||||
/// @group with-arguments
|
||||
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
// Select all children between `$first` and `$last`.
|
||||
// @group with-arguments
|
||||
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
|
||||
@mixin between($first, $last) {
|
||||
&:nth-child(n + #{$first}):nth-child(-n + #{$last}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
/// Select all even children between `$first` and `$last`.
|
||||
/// @group with-arguments
|
||||
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
// Select all even children between `$first` and `$last`.
|
||||
// @group with-arguments
|
||||
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
|
||||
@mixin even-between($first, $last) {
|
||||
&:nth-child(even):nth-child(n + #{$first}):nth-child(-n + #{$last}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
/// Select all odd children between `$first` and `$last`.
|
||||
/// @group with-arguments
|
||||
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
// Select all odd children between `$first` and `$last`.
|
||||
// @group with-arguments
|
||||
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
|
||||
@mixin odd-between($first, $last) {
|
||||
&:nth-child(odd):nth-child(n + #{$first}):nth-child(-n + #{$last}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
/// Select all `$num` children between `$first` and `$last`.
|
||||
/// @group with-arguments
|
||||
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
// Select all `$num` children between `$first` and `$last`.
|
||||
// @group with-arguments
|
||||
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
|
||||
@mixin n-between($num, $first, $last) {
|
||||
&:nth-child(#{$num}n):nth-child(n + #{$first}):nth-child(-n + #{$last}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
// Select all children but `$num`.
|
||||
// @group with-arguments
|
||||
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
// @param {number} $num - id of the child
|
||||
|
||||
/// Select all children but `$num`.
|
||||
/// @group with-arguments
|
||||
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
/// @param {number} $num - id of the child
|
||||
@mixin all-but($num) {
|
||||
&:not(:nth-child(#{$num})) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
/// Select children each `$num`.
|
||||
/// @group with-arguments
|
||||
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
/// @param {number} $num - id of the child
|
||||
/// @alias every
|
||||
// Select children each `$num`.
|
||||
// @group with-arguments
|
||||
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
// @param {number} $num - id of the child
|
||||
// @alias every
|
||||
|
||||
@mixin each($num) {
|
||||
&:nth-child(#{$num}n) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
/// Select children each `$num`.
|
||||
/// @group with-arguments
|
||||
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
/// @param {number} $num - id of the child
|
||||
// Select children each `$num`.
|
||||
// @group with-arguments
|
||||
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
// @param {number} $num - id of the child
|
||||
|
||||
@mixin every($num) {
|
||||
&:nth-child(#{$num}n) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
/// Select the `$num` child from the start and the `$num` child from the last.
|
||||
/// @group with-arguments
|
||||
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
/// @param {number} $num - id of the child
|
||||
// Select the `$num` child from the start and the `$num` child from the last.
|
||||
// @group with-arguments
|
||||
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
// @param {number} $num - id of the child
|
||||
|
||||
@mixin from-first-last($num) {
|
||||
&:nth-child(#{$num}),
|
||||
&:nth-last-child(#{$num}) {
|
||||
@@ -128,57 +140,59 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Select the item in the middle of `$num` child. Only works with odd number
|
||||
// chain.
|
||||
// @group with-arguments
|
||||
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
// @param {number} $num - id of the child
|
||||
|
||||
/// Select the item in the middle of `$num` child. Only works with odd number
|
||||
/// chain.
|
||||
/// @group with-arguments
|
||||
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
/// @param {number} $num - id of the child
|
||||
@mixin middle($num) {
|
||||
&:nth-child(#{round($num / 2)}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
// Select all children between the `$num` first and the `$num` last.
|
||||
// @group with-arguments
|
||||
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
// @param {number} $num - id of the child
|
||||
|
||||
/// Select all children between the `$num` first and the `$num` last.
|
||||
/// @group with-arguments
|
||||
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
/// @param {number} $num - id of the child
|
||||
@mixin all-but-first-last($num) {
|
||||
&:nth-child(n + #{$num}):nth-last-child(n + #{$num}) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
// This quantity-query mixin will only select the first of `$limit` items. It will not
|
||||
// work if there is not as much as item as you set in `$limit`.
|
||||
// @group Quantity queries
|
||||
// @param {number} $limit
|
||||
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
|
||||
/// This quantity-query mixin will only select the first of `$limit` items. It will not
|
||||
/// work if there is not as much as item as you set in `$limit`.
|
||||
/// @group Quantity queries
|
||||
/// @param {number} $limit
|
||||
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
@mixin first-of($limit) {
|
||||
&:nth-last-child(#{$limit}):first-child {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
/// This quantity-query mixin will only select the last of `$limit` items. It will not
|
||||
/// if there is not as much as item as you set in `$limit`.
|
||||
/// @group Quantity queries
|
||||
/// @param {number} $limit
|
||||
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
// This quantity-query mixin will only select the last of `$limit` items. It will not
|
||||
// if there is not as much as item as you set in `$limit`.
|
||||
// @group Quantity queries
|
||||
// @param {number} $limit
|
||||
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
|
||||
@mixin last-of($limit) {
|
||||
&:nth-of-type(#{$limit}):nth-last-of-type(1) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
/// This quantity-query mixin will select every items if there is at least `$num` items. It will not
|
||||
/// if there is not as much as item as you set in `$num`.
|
||||
/// @group Quantity queries
|
||||
/// @param {number} $limit
|
||||
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
// This quantity-query mixin will select every items if there is at least `$num` items. It will not
|
||||
// if there is not as much as item as you set in `$num`.
|
||||
// @group Quantity queries
|
||||
// @param {number} $limit
|
||||
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
|
||||
@mixin at-least($num) {
|
||||
$selector: &;
|
||||
$child: nth(nth($selector, -1), -1);
|
||||
@@ -189,11 +203,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
/// This quantity-query mixin will select every items if there is at most `$num` items. It will not
|
||||
/// if there is not as much as item as you set in `$num`.
|
||||
/// @group Quantity queries
|
||||
/// @param {number} $limit
|
||||
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
// This quantity-query mixin will select every items if there is at most `$num` items. It will not
|
||||
// if there is not as much as item as you set in `$num`.
|
||||
// @group Quantity queries
|
||||
// @param {number} $limit
|
||||
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
|
||||
@mixin at-most($num) {
|
||||
$selector: &;
|
||||
$child: nth(nth($selector, -1), -1);
|
||||
@@ -204,10 +219,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
/// This quantity-query mixin will select every items only if there is between `$min` and `$max` items.
|
||||
/// @group Quantity queries
|
||||
/// @param {number} $limit
|
||||
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
// This quantity-query mixin will select every items only if there is between `$min` and `$max` items.
|
||||
// @group Quantity queries
|
||||
// @param {number} $limit
|
||||
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
|
||||
@mixin in-between($min, $max) {
|
||||
$selector: &;
|
||||
$child: nth(nth($selector, -1), -1);
|
||||
@@ -218,45 +234,50 @@
|
||||
}
|
||||
}
|
||||
|
||||
/// Select the first exact child
|
||||
/// @group no-arguments
|
||||
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
// Select the first exact child
|
||||
// @group no-arguments
|
||||
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
|
||||
@mixin first-child() {
|
||||
&:first-of-type {
|
||||
@content
|
||||
}
|
||||
}
|
||||
|
||||
/// Select the last exact child
|
||||
/// @group no-arguments
|
||||
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
// Select the last exact child
|
||||
// @group no-arguments
|
||||
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
|
||||
@mixin last-child() {
|
||||
&:last-of-type {
|
||||
@content
|
||||
}
|
||||
}
|
||||
|
||||
/// Select all even children.
|
||||
/// @group no-arguments
|
||||
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
// Select all even children.
|
||||
// @group no-arguments
|
||||
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
|
||||
@mixin even() {
|
||||
&:nth-child(even) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
/// Select all odd children.
|
||||
/// @group no-arguments
|
||||
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
// Select all odd children.
|
||||
// @group no-arguments
|
||||
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
|
||||
@mixin odd() {
|
||||
&:nth-child(odd) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
/// Select only the first and last child.
|
||||
/// @group no-arguments
|
||||
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
// Select only the first and last child.
|
||||
// @group no-arguments
|
||||
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
|
||||
@mixin first-last() {
|
||||
&:first-child,
|
||||
&:last-child {
|
||||
@@ -264,43 +285,46 @@
|
||||
}
|
||||
}
|
||||
|
||||
/// Will only select the child if it’s unique.
|
||||
/// @group no-arguments
|
||||
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
/// @alias only
|
||||
// Will only select the child if it’s unique.
|
||||
// @group no-arguments
|
||||
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
// @alias only
|
||||
|
||||
@mixin unique() {
|
||||
&:only-child {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
/// Will only select the child if it’s unique.
|
||||
/// @group no-arguments
|
||||
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
// Will only select the child if it’s unique.
|
||||
// @group no-arguments
|
||||
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
|
||||
@mixin only() {
|
||||
&:only-child {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
/// Will only select children if they are not unique. Meaning if there is at
|
||||
/// least 2 children, the style is applied.
|
||||
/// @group no-arguments
|
||||
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
// Will only select children if they are not unique. Meaning if there is at
|
||||
// least 2 children, the style is applied.
|
||||
// @group no-arguments
|
||||
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
|
||||
@mixin not-unique() {
|
||||
&:not(:only-child) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
// This mixin is used to automatically sort z-index in numerical order. But it
|
||||
// can also sort them in anti-numerical order, depending the parameters you use.
|
||||
// @group using functions
|
||||
// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
// @param {number} $num - Number of children
|
||||
// @param {string} $direction [forward] - Direction of the sort
|
||||
// @param {number} $index [0] - Index of the sorting
|
||||
|
||||
/// This mixin is used to automatically sort z-index in numerical order. But it
|
||||
/// can also sort them in anti-numerical order, depending the parameters you use.
|
||||
/// @group using functions
|
||||
/// @content [Write the style you want to apply to the children, and it will be added within the @content directive]
|
||||
/// @param {number} $num - Number of children
|
||||
/// @param {string} $direction [forward] - Direction of the sort
|
||||
/// @param {number} $index [0] - Index of the sorting
|
||||
@mixin child-index($num, $direction: 'forward', $index: 0) {
|
||||
@for $i from 1 through $num {
|
||||
@if ($direction == 'forward') {
|
||||
@@ -317,11 +341,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
/// Used by the child-index mixin. It will returned the proper sorted numbers
|
||||
/// depending on the `$index` value.
|
||||
/// @access private
|
||||
/// @param {number} $num - Number of children
|
||||
/// @param {number} $index - Index of the sorting
|
||||
// Used by the child-index mixin. It will returned the proper sorted numbers
|
||||
// depending on the `$index` value.
|
||||
// @access private
|
||||
// @param {number} $num - Number of children
|
||||
// @param {number} $index - Index of the sorting
|
||||
|
||||
@function order-index($i, $index) {
|
||||
@return ($index + $i);
|
||||
}
|
||||
|
||||
@@ -2,97 +2,45 @@
|
||||
// Tools / Font Faces
|
||||
// ==========================================================================
|
||||
|
||||
$global-font-file-formats: "woff2", "woff" !default;
|
||||
// Import the webfont with font-face as woff and woff2
|
||||
//
|
||||
// @param {List} $webfont (font name, filename, font-weight, font-style) - Each webfont to import.
|
||||
// @param {String} $dir - The webfont directory path
|
||||
// @output void
|
||||
|
||||
//
|
||||
// Builds the `src` list for an `@font-face` declaration.
|
||||
//
|
||||
// @link https://github.com/thoughtbot/bourbon/blob/master/core/bourbon/utilities/_font-source-declaration.scss
|
||||
// @link http://goo.gl/Ru1bKP
|
||||
//
|
||||
// @param {String} $font-family - The font family name.
|
||||
// @param {String} $file-path - The path to the font family.
|
||||
// @param {List} $file-formats - The file formats to request.
|
||||
// @return {List}
|
||||
//
|
||||
// @require {function} list-contains
|
||||
//
|
||||
// @access private
|
||||
//
|
||||
@function font-source-declaration(
|
||||
$font-family,
|
||||
$file-path,
|
||||
$file-formats
|
||||
) {
|
||||
$src: ();
|
||||
$formats-map: (
|
||||
eot: "#{$file-path}.eot?#iefix" format("embedded-opentype"),
|
||||
woff2: "#{$file-path}.woff2" format("woff2"),
|
||||
woff: "#{$file-path}.woff" format("woff"),
|
||||
ttf: "#{$file-path}.ttf" format("truetype"),
|
||||
svg: "#{$file-path}.svg##{$font-family}" format("svg"),
|
||||
);
|
||||
|
||||
@each $key, $values in $formats-map {
|
||||
@if list-contains($file-formats, $key) {
|
||||
$file-path: nth($values, 1);
|
||||
$font-format: nth($values, 2);
|
||||
$src: append($src, url("#{$assets-path}#{$file-path}") $font-format, comma);
|
||||
}
|
||||
}
|
||||
|
||||
@return $src;
|
||||
}
|
||||
|
||||
//
|
||||
// Generates an `@font-face` declaration.
|
||||
//
|
||||
// You can choose the specific file formats you need to output; the mixin supports
|
||||
// `eot`, `ttf`, `svg`, `woff2` and `woff`.
|
||||
//
|
||||
// @link https://github.com/thoughtbot/bourbon/blob/master/core/bourbon/library/_font-face.scss
|
||||
//
|
||||
// @param {String} $font-family - The font family name.
|
||||
// @param {String} $file-path - The path to the font family.
|
||||
// @param {String|List} $file-formats [("ttf", "woff2", "woff")]
|
||||
// A list of file formats to support,
|
||||
// for example ("eot", "ttf", "svg", "woff2", "woff").
|
||||
//
|
||||
// @content
|
||||
// Any additional CSS properties that are included in the `@include`
|
||||
// directive will be output within the `@font-face` declaration, e.g.
|
||||
// you can pass in `font-weight`, `font-style` and/or `unicode-range`.
|
||||
//
|
||||
// @example scss
|
||||
// @include font-face(
|
||||
// "source-sans-pro",
|
||||
// "fonts/source-sans-pro-regular",
|
||||
// ("woff2", "woff")
|
||||
// ) {
|
||||
// font-style: normal;
|
||||
// font-weight: 400;
|
||||
// }
|
||||
//
|
||||
// // CSS Output
|
||||
// @font-face {
|
||||
// font-family: "source-sans-pro";
|
||||
// src: url("fonts/source-sans-pro-regular.woff2") format("woff2"),
|
||||
// url("fonts/source-sans-pro-regular.woff") format("woff");
|
||||
// font-style: normal;
|
||||
// font-weight: 400;
|
||||
// }
|
||||
//
|
||||
// @require {function} _font-source-declaration
|
||||
// @require {function} _retrieve-bourbon-setting
|
||||
//
|
||||
@mixin font-face(
|
||||
$font-family,
|
||||
$file-path,
|
||||
$file-formats: $global-font-file-formats
|
||||
) {
|
||||
@mixin font-face($webfont, $dir) {
|
||||
@font-face {
|
||||
font-family: $font-family;
|
||||
src: font-source-declaration( $font-family, $file-path, $file-formats);
|
||||
@content;
|
||||
font-display: swap;
|
||||
font-family: nth($webfont, 1);
|
||||
src: url("#{$dir}#{nth($webfont, 2)}.woff2") format("woff2"),
|
||||
url("#{$dir}#{nth($webfont, 2)}.woff") format("woff");
|
||||
font-weight: #{nth($webfont, 3)};
|
||||
font-style: #{nth($webfont, 4)};
|
||||
}
|
||||
}
|
||||
|
||||
// Loops through a list of local fonts and import each font-face as woff and woff2
|
||||
//
|
||||
// @param {List} $webfonts [(font name, filename, font-weight, font-style)] - Each webfont to import.
|
||||
// @param {String} $dir - The webfont directory path
|
||||
// @output void
|
||||
|
||||
@mixin font-faces($webfonts, $dir) {
|
||||
@each $webfont in $webfonts {
|
||||
@include font-face($webfont, $dir);
|
||||
}
|
||||
}
|
||||
|
||||
// Map the font-family requires with the existing imported font-families
|
||||
//
|
||||
// @param {String} $font-family - The name of the webfont.
|
||||
// @return {String} The webfont and it's fallbacks.
|
||||
|
||||
@function ff($font-family) {
|
||||
@if not map-has-key($font-families, $font-family) {
|
||||
@error "No font-family found in $font-families map for `#{$font-family}`. Property omitted.";
|
||||
}
|
||||
|
||||
$value: map-get($font-families, $font-family);
|
||||
@return $value;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
// ==========================================================================
|
||||
// Tools / Functions
|
||||
// ==========================================================================
|
||||
|
||||
//
|
||||
// Converts the given pixel value to its EM quivalent.
|
||||
//
|
||||
// @param {Number} $size - The pixel value to convert.
|
||||
// @param {Number} $base [$font-size] - The assumed base font size.
|
||||
// @return {Number} Scalable pixel value in EMs.
|
||||
//
|
||||
|
||||
@function em($size, $base: $font-size) {
|
||||
@if (type-of($size) == number) {
|
||||
@if (unit($size) != "px") {
|
||||
@@ -28,13 +28,12 @@
|
||||
@return ($size / $base) * 1em;
|
||||
}
|
||||
|
||||
//
|
||||
// Converts the given pixel value to its REM quivalent.
|
||||
//
|
||||
// @param {Number} $size - The pixel value to convert.
|
||||
// @param {Number} $base [$font-size] - The assumed base font size.
|
||||
// @return {Number} Scalable pixel value in REMs.
|
||||
//
|
||||
|
||||
@function rem($size, $base: $font-size) {
|
||||
@if (type-of($size) == number) {
|
||||
@if (unit($size) != "px") {
|
||||
@@ -55,19 +54,17 @@
|
||||
@return ($size / $base) * 1rem;
|
||||
}
|
||||
|
||||
//
|
||||
// Converts a number to a percentage.
|
||||
//
|
||||
// @alias percentage()
|
||||
// @link http://sassdoc.com/annotations/#alias
|
||||
// @param {Number} $number - The value to convert.
|
||||
// @return {Number} A percentage.
|
||||
//
|
||||
|
||||
@function span($number) {
|
||||
@return percentage($number);
|
||||
}
|
||||
|
||||
//
|
||||
// Checks if a list contains a value(s).
|
||||
//
|
||||
// @link https://github.com/thoughtbot/bourbon/blob/master/core/bourbon/validators/_contains.scss
|
||||
@@ -75,7 +72,7 @@
|
||||
// @param {List} $values - A single value or list of values to check for.
|
||||
// @return {Boolean}
|
||||
// @access private
|
||||
//
|
||||
|
||||
@function list-contains(
|
||||
$list,
|
||||
$values...
|
||||
@@ -89,38 +86,35 @@
|
||||
@return true;
|
||||
}
|
||||
|
||||
//
|
||||
// Resolve whether a rule is important or not.
|
||||
//
|
||||
// @param {Boolean} $flag - Whether a rule is important (TRUE) or not (FALSE).
|
||||
// @return {String|Null} Returns `!important` or NULL.
|
||||
//
|
||||
|
||||
@function important($flag: false) {
|
||||
@if ($flag == true) {
|
||||
@return !important;
|
||||
} @elseif ($important == false) {
|
||||
@return null;
|
||||
} @else {
|
||||
@error "`#{$flag}` needs to be `true` or `false`."
|
||||
@error "`#{$flag}` needs to be `true` or `false`.";
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Determine if the current context is for a WYSIWYG editor.
|
||||
//
|
||||
// @requires {String} $context - The global context of the stylesheet.
|
||||
// @return {Boolean} If the $context is set to "editor".
|
||||
//
|
||||
|
||||
@function is-editor() {
|
||||
@return ('editor' == $context);
|
||||
}
|
||||
|
||||
//
|
||||
// Determine if the current context is for the front-end.
|
||||
//
|
||||
// @requires {String} $context - The global context of the stylesheet.
|
||||
// @return {Boolean} If the $context is set to "frontend".
|
||||
//
|
||||
|
||||
@function is-frontend() {
|
||||
@return ('frontend' == $context);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// Tools / Layout
|
||||
// ==========================================================================
|
||||
|
||||
//
|
||||
// Grid-like layout system.
|
||||
//
|
||||
// The layout tools provide a column-style layout system. This file contains
|
||||
@@ -10,7 +9,6 @@
|
||||
//
|
||||
// @link https://github.com/inuitcss/inuitcss/blob/0420ba8/objects/_objects.layout.scss
|
||||
//
|
||||
|
||||
//
|
||||
// Generate the layout container.
|
||||
//
|
||||
@@ -19,7 +17,7 @@
|
||||
//
|
||||
// @requires {function} u-list-reset
|
||||
// @output `font-size`, `margin`, `padding`, `list-style`
|
||||
//
|
||||
|
||||
@mixin o-layout($gutter: 0, $fix-whitespace: true) {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@@ -34,7 +32,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Generate the layout item.
|
||||
//
|
||||
// 1. Required in order to combine fluid widths with fixed gutters.
|
||||
@@ -45,7 +42,7 @@
|
||||
// 4. By default, all layout items are full-width (mobile first).
|
||||
// 5. Gutters provided by left padding:
|
||||
// http://csswizardry.com/2011/08/building-better-grid-systems/
|
||||
//
|
||||
|
||||
@mixin o-layout_item($gutter: 0, $fix-whitespace: true) {
|
||||
display: inline-block; // [2]
|
||||
width: 100%; // [4]
|
||||
|
||||
@@ -2,37 +2,34 @@
|
||||
// Tools / Mixins
|
||||
// ==========================================================================
|
||||
|
||||
//
|
||||
// Set the color of the highlight that appears over a link while it's being tapped.
|
||||
//
|
||||
// By default, the highlight is suppressed.
|
||||
//
|
||||
// @param {Color} $value [rgba(0, 0, 0, 0)] - The value of the highlight.
|
||||
// @output `-webkit-tap-highlight-color`
|
||||
//
|
||||
|
||||
@mixin tap-highlight-color($value: rgba(0, 0, 0, 0)) {
|
||||
-webkit-tap-highlight-color: $value;
|
||||
}
|
||||
|
||||
//
|
||||
// Set whether or not touch devices use momentum-based scrolling for the given element.
|
||||
//
|
||||
// By default, applies momentum-based scrolling for the current element.
|
||||
//
|
||||
// @param {String} $value [rgba(0, 0, 0, 0)] - The type of scrolling.
|
||||
// @output `-webkit-overflow-scrolling`
|
||||
//
|
||||
|
||||
@mixin overflow-scrolling($value: touch) {
|
||||
-webkit-overflow-scrolling: $value;
|
||||
}
|
||||
|
||||
//
|
||||
// Micro clearfix rules for containing floats.
|
||||
//
|
||||
// @link http://www.cssmojo.com/the-very-latest-clearfix-reloaded/
|
||||
// @param {List} $supports The type of clearfix to generate.
|
||||
// @output Injects `:::after` pseudo-element.
|
||||
//
|
||||
|
||||
@mixin u-clearfix($supports...) {
|
||||
&::after {
|
||||
display: if(list-contains($supports, table), table, block);
|
||||
@@ -41,7 +38,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Generate a font-size and baseline-compatible line-height.
|
||||
//
|
||||
// @link https://github.com/inuitcss/inuitcss/c14029c/tools/_tools.font-size.scss
|
||||
@@ -49,7 +45,7 @@
|
||||
// @param {Number} $line-height [auto] - The line box height.
|
||||
// @param {Boolean} $important [false] - Whether the font-size is important.
|
||||
// @output `font-size`, `line-height`
|
||||
//
|
||||
|
||||
@mixin font-size($font-size, $line-height: auto, $important: false) {
|
||||
$important: important($important);
|
||||
font-size: rem($font-size) $important;
|
||||
@@ -62,12 +58,11 @@
|
||||
line-height: $line-height $important;
|
||||
}
|
||||
@elseif ($line-height != "none" and $line-height != false) {
|
||||
@error "D’oh! `#{$line-height}` is not a valid value for `$line-height`."
|
||||
@error "D’oh! `#{$line-height}` is not a valid value for `$line-height`.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Vertically-center the direct descendants of the current element.
|
||||
//
|
||||
// Centering is achieved by displaying children as inline-blocks. Any whitespace
|
||||
@@ -75,7 +70,7 @@
|
||||
// and its children.
|
||||
//
|
||||
// @output `font-size`, `display`, `vertical-align`
|
||||
//
|
||||
|
||||
@mixin o-vertical-center {
|
||||
font-size: 0;
|
||||
|
||||
@@ -93,13 +88,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Generate `:hover` and `:focus` styles in one go.
|
||||
//
|
||||
// @link https://github.com/inuitcss/inuitcss/blob/master/tools/_tools.mixins.scss
|
||||
// @content Wrapped in `:focus` and `:hover` pseudo-classes.
|
||||
// @output Wraps the given content in `:focus` and `:hover` pseudo-classes.
|
||||
//
|
||||
|
||||
@mixin u-hocus {
|
||||
&:focus,
|
||||
&:hover {
|
||||
@@ -107,13 +101,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Generate `:active` and `:focus` styles in one go.
|
||||
//
|
||||
// @see {Mixin} u-hocus
|
||||
// @content Wrapped in `:focus` and `:active` pseudo-classes.
|
||||
// @output Wraps the given content in `:focus` and `:hover` pseudo-classes.
|
||||
//
|
||||
|
||||
@mixin u-actus {
|
||||
&:focus,
|
||||
&:active {
|
||||
@@ -121,7 +114,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Prevent text from wrapping onto multiple lines for the current element.
|
||||
//
|
||||
// An ellipsis is appended to the end of the line.
|
||||
@@ -131,7 +123,7 @@
|
||||
//
|
||||
// @param {Number} $width [100%] - The maximum width of element.
|
||||
// @output `max-width`, `word-wrap`, `white-space`, `overflow`, `text-overflow`
|
||||
//
|
||||
|
||||
@mixin u-truncate($width: 100%) {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@@ -142,12 +134,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Applies accessible hiding to the current element.
|
||||
//
|
||||
// @param {Boolean} $important [true] - Whether the visibility is important.
|
||||
// @output Properties for removing the element from the document flow.
|
||||
//
|
||||
|
||||
@mixin u-accessibly-hidden($important: true) {
|
||||
$important: important($important);
|
||||
position: absolute $important;
|
||||
@@ -160,12 +151,11 @@
|
||||
border: 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Allows an accessibly hidden element to be focusable via keyboard navigation.
|
||||
//
|
||||
// @content For styling the now visible element.
|
||||
// @output Injects `:focus`, `:active` pseudo-classes.
|
||||
//
|
||||
|
||||
@mixin u-accessibly-focusable {
|
||||
@include u-actus {
|
||||
clip: auto;
|
||||
@@ -176,7 +166,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Hide the current element from all.
|
||||
//
|
||||
// The element will be hidden from screen readers and removed from the document flow.
|
||||
@@ -184,14 +173,13 @@
|
||||
// @link http://juicystudio.com/article/screen-readers-display-none.php
|
||||
// @param {Boolean} $important [true] - Whether the visibility is important.
|
||||
// @output `display`, `visibility`
|
||||
//
|
||||
|
||||
@mixin u-hidden($important: true) {
|
||||
$important: important($important);
|
||||
display: none $important;
|
||||
visibility: hidden $important;
|
||||
}
|
||||
|
||||
//
|
||||
// Show the current element for all.
|
||||
//
|
||||
// The element will be accessible from screen readers and visible in the document flow.
|
||||
@@ -199,7 +187,7 @@
|
||||
// @param {String} $display [block] - The rendering box used for the element.
|
||||
// @param {Boolean} $important [true] - Whether the visibility is important.
|
||||
// @output `display`, `visibility`
|
||||
//
|
||||
|
||||
@mixin u-shown($display: block, $important: true) {
|
||||
$important: important($important);
|
||||
display: $display $important;
|
||||
|
||||
@@ -10,19 +10,21 @@
|
||||
// .u-pull-2/4
|
||||
// .u-pull-1/5
|
||||
// .u-push-2/3
|
||||
|
||||
$widths-offsets: false !default;
|
||||
|
||||
// By default, the boilerplate uses fractions-like classes like `<div class="u-1/4">`.
|
||||
// You can change the `/` to whatever you fancy with this variable.
|
||||
|
||||
$fractions-delimiter: \/ !default;
|
||||
|
||||
// When using Sass-MQ, this defines the separator for the breakpoints suffix
|
||||
// in the class name. By default, we are generating the responsive suffixes
|
||||
// for the classes with a `@` symbol so you get classes like:
|
||||
// <div class="u-3/12@mobile">
|
||||
|
||||
$breakpoint-delimiter: \@ !default;
|
||||
|
||||
//
|
||||
// Generate a series of width helper classes
|
||||
//
|
||||
// @example scss
|
||||
@@ -45,7 +47,7 @@ $breakpoint-delimiter: \@ !default;
|
||||
// @param {List} $colums - The columns we want the widths to have.
|
||||
// @param {String} $breakpoint - Optional suffix for responsive widths.
|
||||
// @output `width`, `position`, `right`, `left`
|
||||
//
|
||||
|
||||
@mixin widths($columns, $breakpoint: null, $important: true) {
|
||||
$important: important($important);
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
// Floats
|
||||
// ==========================================================================
|
||||
|
||||
.u-float-left {
|
||||
float: left !important;
|
||||
}
|
||||
@@ -14,6 +15,7 @@
|
||||
|
||||
// Horizontal Text
|
||||
// ==========================================================================
|
||||
|
||||
.u-text-center {
|
||||
text-align: center !important;
|
||||
}
|
||||
@@ -28,6 +30,7 @@
|
||||
|
||||
// Vertical Text
|
||||
// ==========================================================================
|
||||
|
||||
.u-align-baseline {
|
||||
vertical-align: baseline !important;
|
||||
}
|
||||
|
||||
@@ -4,18 +4,21 @@
|
||||
|
||||
// Layout
|
||||
// ==========================================================================
|
||||
|
||||
.u-clearfix {
|
||||
@include u-clearfix;
|
||||
}
|
||||
|
||||
// Decorative
|
||||
// =============================================================================
|
||||
|
||||
.u-truncate {
|
||||
@include u-truncate;
|
||||
}
|
||||
|
||||
// Visibility / Display
|
||||
// ==========================================================================
|
||||
|
||||
[hidden][aria-hidden="false"] {
|
||||
position: absolute;
|
||||
display: inherit;
|
||||
@@ -30,35 +33,33 @@
|
||||
// display: block;
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * 1. Fix for Firefox bug: an image styled `max-width:100%` within an
|
||||
// * inline-block will display at its default size, and not limit its width to
|
||||
// * 100% of an ancestral container.
|
||||
// */
|
||||
// // 1. Fix for Firefox bug: an image styled `max-width:100%` within an
|
||||
// // inline-block will display at its default size, and not limit its width to
|
||||
// // 100% of an ancestral container.
|
||||
//
|
||||
// .u-inline-block {
|
||||
// display: inline-block !important;
|
||||
// max-width: 100%; /* 1 */
|
||||
// }
|
||||
|
||||
//
|
||||
// .u-inline {
|
||||
// display: inline !important;
|
||||
// }
|
||||
|
||||
//
|
||||
// .u-table {
|
||||
// display: table !important;
|
||||
// }
|
||||
|
||||
//
|
||||
// .u-tableCell {
|
||||
// display: table-cell !important;
|
||||
// }
|
||||
|
||||
//
|
||||
// .u-tableRow {
|
||||
// display: table-row !important;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Completely remove from the flow but leave available to screen readers.
|
||||
*/
|
||||
// Completely remove from the flow but leave available to screen readers.
|
||||
|
||||
.u-screen-reader-text {
|
||||
@include u-accessibly-hidden;
|
||||
}
|
||||
@@ -69,13 +70,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Extends the `.screen-reader-text` class to allow the element
|
||||
* to be focusable when navigated to via the keyboard.
|
||||
*
|
||||
* @link https://www.drupal.org/node/897638
|
||||
* @todo Define styles when focused.
|
||||
*/
|
||||
// Extends the `.screen-reader-text` class to allow the element
|
||||
// to be focusable when navigated to via the keyboard.
|
||||
//
|
||||
// @link https://www.drupal.org/node/897638
|
||||
// @todo Define styles when focused.
|
||||
|
||||
.u-screen-reader-text.-focusable {
|
||||
@include u-accessibly-focusable;
|
||||
}
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
////
|
||||
|
||||
@media print {
|
||||
/**
|
||||
* 1. Black prints faster: http://www.sanbeiji.com/archives/953
|
||||
*/
|
||||
|
||||
// 1. Black prints faster: http://www.sanbeiji.com/archives/953
|
||||
|
||||
*,
|
||||
*:before,
|
||||
*:after,
|
||||
@@ -21,7 +21,7 @@
|
||||
*:first-line {
|
||||
background: transparent !important;
|
||||
box-shadow: none !important;
|
||||
color: #000000 !important; /* [1] */
|
||||
color: #000000 !important; // [1]
|
||||
text-shadow: none !important;
|
||||
}
|
||||
|
||||
@@ -38,10 +38,9 @@
|
||||
content: " (" attr(title) ")";
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't show links that are fragment identifiers, or use the `javascript:`
|
||||
* pseudo protocol.
|
||||
*/
|
||||
// Don't show links that are fragment identifiers, or use the `javascript:`
|
||||
// pseudo protocol.
|
||||
|
||||
a[href^="#"]:after,
|
||||
a[href^="javascript:"]:after {
|
||||
content: "";
|
||||
@@ -53,9 +52,8 @@
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Printing Tables: http://css-discuss.incutio.com/wiki/Printing_Tables
|
||||
*/
|
||||
// Printing Tables: http://css-discuss.incutio.com/wiki/Printing_Tables
|
||||
|
||||
thead {
|
||||
display: table-header-group;
|
||||
}
|
||||
|
||||
@@ -2,12 +2,9 @@
|
||||
// Utilities / Ratio
|
||||
// ==========================================================================
|
||||
|
||||
//
|
||||
// @link https://github.com/inuitcss/inuitcss/blob/19d0c7e/objects/_objects.ratio.scss
|
||||
//
|
||||
|
||||
// A list of aspect ratios that get generated as modifier classes.
|
||||
|
||||
$aspect-ratios: (
|
||||
(2:1),
|
||||
(4:3),
|
||||
@@ -16,13 +13,11 @@ $aspect-ratios: (
|
||||
|
||||
/* stylelint-disable */
|
||||
|
||||
//
|
||||
// Generate a series of ratio classes to be used like so:
|
||||
//
|
||||
// @example
|
||||
// <div class="o-ratio u-16:9">
|
||||
//
|
||||
//
|
||||
|
||||
@each $ratio in $aspect-ratios {
|
||||
@each $antecedent, $consequent in $ratio {
|
||||
@if (type-of($antecedent) != number) {
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
// Utilities / States
|
||||
// ==========================================================================
|
||||
|
||||
/**
|
||||
* ARIA roles display visual cursor hints
|
||||
*/
|
||||
// ARIA roles display visual cursor hints
|
||||
|
||||
[aria-busy="true"] {
|
||||
cursor: progress;
|
||||
}
|
||||
@@ -17,9 +16,7 @@
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Control visibility without affecting flow.
|
||||
*/
|
||||
// Control visibility without affecting flow.
|
||||
|
||||
.is-visible {
|
||||
visibility: visible !important;
|
||||
@@ -31,9 +28,7 @@
|
||||
opacity: 0 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* Completely remove from the flow and screen readers.
|
||||
*/
|
||||
// Completely remove from the flow and screen readers.
|
||||
|
||||
.is-hidden {
|
||||
@include u-hidden;
|
||||
@@ -56,29 +51,27 @@
|
||||
// display: none;
|
||||
// }
|
||||
// }
|
||||
|
||||
//
|
||||
// .is-hidden\@from-large {
|
||||
// @media (min-width: $from-large) {
|
||||
// display: none;
|
||||
// }
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Display a hidden-by-default element.
|
||||
// */
|
||||
|
||||
// // Display a hidden-by-default element.
|
||||
//
|
||||
// .is-shown {
|
||||
// @include u-shown;
|
||||
// }
|
||||
|
||||
//
|
||||
// table.is-shown {
|
||||
// display: table !important;
|
||||
// }
|
||||
|
||||
//
|
||||
// tr.is-shown {
|
||||
// display: table-row !important;
|
||||
// }
|
||||
|
||||
//
|
||||
// td.is-shown,
|
||||
// th.is-shown {
|
||||
// display: table-cell !important;
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
////
|
||||
/// @link https://github.com/inuitcss/inuitcss/blob/6eb574f/utilities/_utilities.widths.scss
|
||||
////
|
||||
|
||||
///
|
||||
///
|
||||
/// Which fractions would you like in your grid system(s)?
|
||||
/// By default, the boilerplate provides fractions of one whole, halves, thirds,
|
||||
/// quarters, and fifths, e.g.:
|
||||
@@ -15,6 +15,8 @@
|
||||
/// .u-2/5
|
||||
/// .u-3/4
|
||||
/// .u-2/3
|
||||
////
|
||||
|
||||
$widths-fractions: 1 2 3 4 5 !default;
|
||||
|
||||
@include widths($widths-fractions);
|
||||
|
||||
@@ -1,10 +1,54 @@
|
||||
import loconfig from '../../loconfig.json';
|
||||
import loconfig from '../utils/config.js';
|
||||
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 resolve from '../utils/template.js';
|
||||
import concat from 'concat';
|
||||
import { basename } from 'node:path';
|
||||
import {
|
||||
basename,
|
||||
normalize,
|
||||
} from 'node:path';
|
||||
|
||||
/**
|
||||
* @const {object} defaultGlobOptions - The default shared glob options.
|
||||
* @const {object} developmentGlobOptions - The predefined glob options for development.
|
||||
* @const {object} productionGlobOptions - The predefined glob options for production.
|
||||
*/
|
||||
export const defaultGlobOptions = {
|
||||
};
|
||||
export const developmentGlobOptions = Object.assign({}, defaultGlobOptions);
|
||||
export const productionGlobOptions = Object.assign({}, defaultGlobOptions);
|
||||
|
||||
/**
|
||||
* @typedef {object} ConcatOptions
|
||||
* @property {boolean} removeDuplicates - Removes duplicate paths from
|
||||
* the array of matching files and folders.
|
||||
* Only the first occurrence of each path is kept.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @const {ConcatOptions} defaultConcatOptions - The default shared concatenation options.
|
||||
* @const {ConcatOptions} developmentConcatOptions - The predefined concatenation options for development.
|
||||
* @const {ConcatOptions} productionConcatOptions - The predefined concatenation options for production.
|
||||
*/
|
||||
export const defaultConcatOptions = {
|
||||
removeDuplicates: true,
|
||||
};
|
||||
export const developmentConcatOptions = Object.assign({}, defaultConcatOptions);
|
||||
export const productionConcatOptions = Object.assign({}, defaultConcatOptions);
|
||||
|
||||
/**
|
||||
* @const {object} developmentConcatFilesArgs - The predefined `concatFiles()` options for development.
|
||||
* @const {object} productionConcatFilesArgs - The predefined `concatFiles()` options for production.
|
||||
*/
|
||||
export const developmentConcatFilesArgs = [
|
||||
developmentGlobOptions,
|
||||
developmentConcatOptions,
|
||||
];
|
||||
export const productionConcatFilesArgs = [
|
||||
productionGlobOptions,
|
||||
productionConcatOptions,
|
||||
];
|
||||
|
||||
/**
|
||||
* Concatenates groups of files.
|
||||
@@ -12,37 +56,77 @@ import { basename } from 'node:path';
|
||||
* @todo Add support for minification.
|
||||
*
|
||||
* @async
|
||||
* @param {object|boolean} [globOptions=null] - Customize the glob options.
|
||||
* If `null`, default production options are used.
|
||||
* If `false`, the glob function will be ignored.
|
||||
* @param {object} [concatOptions=null] - Customize the concatenation options.
|
||||
* If `null`, default production options are used.
|
||||
* @return {Promise}
|
||||
*/
|
||||
export default async function concatFiles() {
|
||||
export default async function concatFiles(globOptions = null, concatOptions = null) {
|
||||
if (glob) {
|
||||
if (globOptions == null) {
|
||||
globOptions = productionGlobOptions;
|
||||
} else if (
|
||||
globOptions !== false &&
|
||||
globOptions !== developmentGlobOptions &&
|
||||
globOptions !== productionGlobOptions
|
||||
) {
|
||||
globOptions = Object.assign({}, defaultGlobOptions, globOptions);
|
||||
}
|
||||
}
|
||||
|
||||
if (concatOptions == null) {
|
||||
concatOptions = productionConcatOptions;
|
||||
} else if (
|
||||
concatOptions !== developmentConcatOptions &&
|
||||
concatOptions !== productionConcatOptions
|
||||
) {
|
||||
concatOptions = Object.assign({}, defaultConcatOptions, concatOptions);
|
||||
}
|
||||
|
||||
loconfig.tasks.concats.forEach(async ({
|
||||
includes,
|
||||
outfile
|
||||
outfile,
|
||||
label = null
|
||||
}) => {
|
||||
const filename = basename(outfile || 'undefined');
|
||||
if (!label) {
|
||||
label = basename(outfile || 'undefined');
|
||||
}
|
||||
|
||||
const timeLabel = `${filename} concatenated in`;
|
||||
const timeLabel = `${label} concatenated in`;
|
||||
console.time(timeLabel);
|
||||
|
||||
try {
|
||||
includes = includes.map((path) => template(path));
|
||||
outfile = template(outfile);
|
||||
includes = resolve(includes);
|
||||
outfile = resolve(outfile);
|
||||
|
||||
const files = await glob(includes);
|
||||
let files;
|
||||
|
||||
if (glob && globOptions) {
|
||||
files = await glob(includes, globOptions);
|
||||
} else {
|
||||
files = includes;
|
||||
}
|
||||
|
||||
if (concatOptions.removeDuplicates) {
|
||||
files = files.map((path) => normalize(path));
|
||||
files = [ ...new Set(files) ];
|
||||
}
|
||||
|
||||
await concat(files, outfile);
|
||||
|
||||
if (files.length) {
|
||||
message(`${filename} concatenated`, 'success', timeLabel);
|
||||
message(`${label} concatenated`, 'success', timeLabel);
|
||||
} else {
|
||||
message(`${filename} is empty`, 'notice', timeLabel);
|
||||
message(`${label} is empty`, 'notice', timeLabel);
|
||||
}
|
||||
} catch (err) {
|
||||
message(`Error concatenating ${filename}`, 'error');
|
||||
message(`Error concatenating ${label}`, 'error');
|
||||
message(err);
|
||||
|
||||
notification({
|
||||
title: `${filename} concatenation failed 🚨`,
|
||||
title: `${label} concatenation failed 🚨`,
|
||||
message: `${err.name}: ${err.message}`
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import loconfig from '../../loconfig.json';
|
||||
import loconfig from '../utils/config.js';
|
||||
import message from '../utils/message.js';
|
||||
import notification from '../utils/notification.js';
|
||||
import template from '../utils/template.js';
|
||||
import resolve from '../utils/template.js';
|
||||
import esbuild from 'esbuild';
|
||||
import { basename } from 'node:path';
|
||||
|
||||
@@ -56,20 +56,23 @@ export default async function compileScripts(esBuildOptions = null) {
|
||||
loconfig.tasks.scripts.forEach(async ({
|
||||
includes,
|
||||
outdir = '',
|
||||
outfile = ''
|
||||
outfile = '',
|
||||
label = null
|
||||
}) => {
|
||||
const filename = basename(outdir || outfile || 'undefined');
|
||||
if (!label) {
|
||||
label = basename(outdir || outfile || 'undefined');
|
||||
}
|
||||
|
||||
const timeLabel = `${filename} compiled in`;
|
||||
const timeLabel = `${label} compiled in`;
|
||||
console.time(timeLabel);
|
||||
|
||||
try {
|
||||
includes = includes.map((path) => template(path));
|
||||
includes = resolve(includes);
|
||||
|
||||
if (outdir) {
|
||||
outdir = template(outdir);
|
||||
outdir = resolve(outdir);
|
||||
} else if (outfile) {
|
||||
outfile = template(outfile);
|
||||
outfile = resolve(outfile);
|
||||
} else {
|
||||
throw new TypeError(
|
||||
'Expected \'outdir\' or \'outfile\''
|
||||
@@ -82,11 +85,11 @@ export default async function compileScripts(esBuildOptions = null) {
|
||||
outfile,
|
||||
}));
|
||||
|
||||
message(`${filename} compiled`, 'success', timeLabel);
|
||||
message(`${label} compiled`, 'success', timeLabel);
|
||||
} catch (err) {
|
||||
// errors managments (already done in esbuild)
|
||||
notification({
|
||||
title: `${filename} compilation failed 🚨`,
|
||||
title: `${label} compilation failed 🚨`,
|
||||
message: `${err.errors[0].text} in ${err.errors[0].location.file} line ${err.errors[0].location.line}`
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import loconfig from '../../loconfig.json';
|
||||
import loconfig from '../utils/config.js';
|
||||
import message from '../utils/message.js';
|
||||
import notification from '../utils/notification.js';
|
||||
import postcss, { pluginsMap as postcssPluginsMap } from '../utils/postcss.js';
|
||||
import template from '../utils/template.js';
|
||||
import resolve from '../utils/template.js';
|
||||
import { writeFile } from 'node:fs/promises';
|
||||
import { basename } from 'node:path';
|
||||
import { promisify } from 'node:util';
|
||||
@@ -47,8 +47,8 @@ export const developmentPostCSSOptions = Object.assign({}, defaultPostCSSOptions
|
||||
export const productionPostCSSOptions = Object.assign({}, defaultPostCSSOptions);
|
||||
|
||||
/**
|
||||
* @const {object} developmentStylesArgs - The predefined `compileStyles()` options for development.
|
||||
* @const {object} productionStylesArgs - The predefined `compileStyles()` options for production.
|
||||
* @const {object|boolean} developmentStylesArgs - The predefined `compileStyles()` options for development.
|
||||
* @const {object|boolean} productionStylesArgs - The predefined `compileStyles()` options for production.
|
||||
*/
|
||||
export const developmentStylesArgs = [
|
||||
developmentSassOptions,
|
||||
@@ -88,8 +88,8 @@ export default async function compileStyles(sassOptions = null, postcssOptions =
|
||||
postcssOptions = productionPostCSSOptions;
|
||||
} else if (
|
||||
postcssOptions !== false &&
|
||||
postcssOptions !== developmentSassOptions &&
|
||||
postcssOptions !== productionSassOptions
|
||||
postcssOptions !== developmentPostCSSOptions &&
|
||||
postcssOptions !== productionPostCSSOptions
|
||||
) {
|
||||
postcssOptions = Object.assign({}, defaultPostCSSOptions, postcssOptions);
|
||||
}
|
||||
@@ -97,16 +97,17 @@ export default async function compileStyles(sassOptions = null, postcssOptions =
|
||||
|
||||
loconfig.tasks.styles.forEach(async ({
|
||||
infile,
|
||||
outfile
|
||||
outfile,
|
||||
label = null
|
||||
}) => {
|
||||
const name = basename((outfile || 'undefined'), '.css');
|
||||
const filestem = basename((outfile || 'undefined'), '.css');
|
||||
|
||||
const timeLabel = `${name}.css compiled in`;
|
||||
const timeLabel = `${label || `${filestem}.css`} compiled in`;
|
||||
console.time(timeLabel);
|
||||
|
||||
try {
|
||||
infile = template(infile);
|
||||
outfile = template(outfile);
|
||||
infile = resolve(infile);
|
||||
outfile = resolve(outfile);
|
||||
|
||||
let result = await sassRender(Object.assign({}, sassOptions, {
|
||||
file: infile,
|
||||
@@ -132,7 +133,7 @@ export default async function compileStyles(sassOptions = null, postcssOptions =
|
||||
if (result.warnings) {
|
||||
const warnings = result.warnings();
|
||||
if (warnings.length) {
|
||||
message(`Error processing ${name}.css`, 'warning');
|
||||
message(`Error processing ${label || `${filestem}.css`}`, 'warning');
|
||||
warnings.forEach((warn) => {
|
||||
message(warn.toString());
|
||||
});
|
||||
@@ -144,17 +145,17 @@ export default async function compileStyles(sassOptions = null, postcssOptions =
|
||||
await writeFile(outfile, result.css);
|
||||
|
||||
if (result.css) {
|
||||
message(`${name}.css compiled`, 'success', timeLabel);
|
||||
message(`${label || `${filestem}.css`} compiled`, 'success', timeLabel);
|
||||
} else {
|
||||
message(`${name}.css is empty`, 'notice', timeLabel);
|
||||
message(`${label || `${filestem}.css`} is empty`, 'notice', timeLabel);
|
||||
}
|
||||
} catch (err) {
|
||||
message(`Error compiling ${name}.css`, 'error');
|
||||
message(`Error compiling ${label || `${filestem}.css`}`, 'error');
|
||||
message(err);
|
||||
|
||||
notification({
|
||||
title: `${name}.css save failed 🚨`,
|
||||
message: `Could not save stylesheet to ${name}.css`
|
||||
title: `${label || `${filestem}.css`} save failed 🚨`,
|
||||
message: `Could not save stylesheet to ${label || `${filestem}.css`}`
|
||||
});
|
||||
}
|
||||
|
||||
@@ -162,21 +163,21 @@ export default async function compileStyles(sassOptions = null, postcssOptions =
|
||||
try {
|
||||
await writeFile(outfile + '.map', result.map.toString());
|
||||
} catch (err) {
|
||||
message(`Error compiling ${name}.css.map`, 'error');
|
||||
message(`Error compiling ${label || `${filestem}.css.map`}`, 'error');
|
||||
message(err);
|
||||
|
||||
notification({
|
||||
title: `${name}.css.map save failed 🚨`,
|
||||
message: `Could not save sourcemap to ${name}.css.map`
|
||||
title: `${label || `${filestem}.css.map`} save failed 🚨`,
|
||||
message: `Could not save sourcemap to ${label || `${filestem}.css.map`}`
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
message(`Error compiling ${name}.scss`, 'error');
|
||||
message(`Error compiling ${label || `${filestem}.scss`}`, 'error');
|
||||
message(err.formatted || err);
|
||||
|
||||
notification({
|
||||
title: `${name}.scss compilation failed 🚨`,
|
||||
title: `${label || `${filestem}.scss`} compilation failed 🚨`,
|
||||
message: (err.formatted || `${err.name}: ${err.message}`)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import loconfig from '../../loconfig.json';
|
||||
import loconfig from '../utils/config.js';
|
||||
import message from '../utils/message.js';
|
||||
import notification from '../utils/notification.js';
|
||||
import template from '../utils/template.js';
|
||||
import resolve from '../utils/template.js';
|
||||
import { basename } from 'node:path';
|
||||
import mixer from 'svg-mixer';
|
||||
|
||||
@@ -49,28 +49,31 @@ export default async function compileSVGs(mixerOptions = null) {
|
||||
|
||||
loconfig.tasks.svgs.forEach(async ({
|
||||
includes,
|
||||
outfile
|
||||
outfile,
|
||||
label = null
|
||||
}) => {
|
||||
const filename = basename(outfile || 'undefined');
|
||||
if (!label) {
|
||||
label = basename(outfile || 'undefined');
|
||||
}
|
||||
|
||||
const timeLabel = `${filename} compiled in`;
|
||||
const timeLabel = `${label} compiled in`;
|
||||
console.time(timeLabel);
|
||||
|
||||
try {
|
||||
includes = includes.map((path) => template(path));
|
||||
outfile = template(outfile);
|
||||
includes = resolve(includes);
|
||||
outfile = resolve(outfile);
|
||||
|
||||
const result = await mixer(includes, mixerOptions);
|
||||
|
||||
await result.write(outfile);
|
||||
|
||||
message(`${filename} compiled`, 'success', timeLabel);
|
||||
message(`${label} compiled`, 'success', timeLabel);
|
||||
} catch (err) {
|
||||
message(`Error compiling ${filename}`, 'error');
|
||||
message(`Error compiling ${label}`, 'error');
|
||||
message(err);
|
||||
|
||||
notification({
|
||||
title: `${filename} compilation failed 🚨`,
|
||||
title: `${label} compilation failed 🚨`,
|
||||
message: `${err.name}: ${err.message}`
|
||||
});
|
||||
}
|
||||
|
||||
64
build/utils/config.js
Normal file
64
build/utils/config.js
Normal file
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* @file Provides simple user configuration options.
|
||||
*/
|
||||
|
||||
import loconfig from '../../loconfig.json';
|
||||
|
||||
let usrconfig;
|
||||
|
||||
try {
|
||||
usrconfig = await import('../../loconfig.local.json');
|
||||
usrconfig = usrconfig.default;
|
||||
|
||||
merge(loconfig, usrconfig);
|
||||
} catch (err) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
export default loconfig;
|
||||
|
||||
/**
|
||||
* Creates a new object with all nested object properties
|
||||
* merged into it recursively.
|
||||
*
|
||||
* @param {object} target - The target object.
|
||||
* @param {object[]} ...sources - The source object(s).
|
||||
* @throws {TypeError} If the target and source are the same.
|
||||
* @return {object} Returns the `target` object.
|
||||
*/
|
||||
export function merge(target, ...sources) {
|
||||
for (const source of sources) {
|
||||
if (target === source) {
|
||||
throw new TypeError(
|
||||
'Cannot merge, target and source are the same'
|
||||
);
|
||||
}
|
||||
|
||||
for (const key in source) {
|
||||
if (source[key] != null) {
|
||||
if (isObjectLike(source[key]) && isObjectLike(target[key])) {
|
||||
merge(target[key], source[key]);
|
||||
continue;
|
||||
} else if (Array.isArray(source[key]) && Array.isArray(target[key])) {
|
||||
target[key] = target[key].concat(source[key]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
target[key] = source[key];
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the passed value is an `Object`.
|
||||
*
|
||||
* @param {*} value - The value to be checked.
|
||||
* @return {boolean} Returns `true` if the value is an `Object`,
|
||||
* otherwise `false`.
|
||||
*/
|
||||
function isObjectLike(value) {
|
||||
return (value != null && typeof value === 'object');
|
||||
}
|
||||
@@ -4,8 +4,9 @@
|
||||
* 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/globby globby}
|
||||
* - {@link https://npmjs.com/package/fast-glob fast-glob}
|
||||
* - {@link https://npmjs.com/package/glob glob}
|
||||
*/
|
||||
@@ -22,7 +23,15 @@ const candidates = [
|
||||
'glob',
|
||||
];
|
||||
|
||||
export default await importGlob();
|
||||
let glob;
|
||||
|
||||
try {
|
||||
glob = await importGlob();
|
||||
} catch (err) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
export default glob;
|
||||
|
||||
/**
|
||||
* Imports the first available glob function.
|
||||
@@ -63,7 +72,7 @@ async function importGlob() {
|
||||
}
|
||||
|
||||
throw new TypeError(
|
||||
`No glob library was found, expected one of: ${modules.join(', ')}`
|
||||
`No glob library was found, expected one of: ${candidates.join(', ')}`
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* @file Provides a decorator for cross-platform notification.
|
||||
*/
|
||||
|
||||
import notifier from 'node-notifier';
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,8 +12,7 @@ try {
|
||||
autoprefixer = await import('autoprefixer');
|
||||
autoprefixer = autoprefixer.default;
|
||||
} catch (err) {
|
||||
postcss = null;
|
||||
autoprefixer = null;
|
||||
// do nothing
|
||||
}
|
||||
|
||||
export default postcss;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* @file Provides simple template tags.
|
||||
*/
|
||||
|
||||
import loconfig from '../../loconfig.json';
|
||||
import loconfig from './config.js';
|
||||
|
||||
const templateData = flatten({
|
||||
paths: loconfig.paths
|
||||
@@ -14,17 +14,53 @@ const templateData = flatten({
|
||||
* 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', … }`.
|
||||
* @param {*} input - The value being searched and replaced on.
|
||||
* If input is, or contains, a string, tags will be resolved.
|
||||
* If input is, or contains, an object, it is mutated directly.
|
||||
* If input is, or contains, an array, a shallow copy is returned.
|
||||
* Otherwise, the value is left intact.
|
||||
* @param {object} [data] - An object in the form `{ 'from': 'to', … }`.
|
||||
* @return {*} Returns the transformed value.
|
||||
*/
|
||||
export default function resolve(input, data = templateData) {
|
||||
switch (typeof input) {
|
||||
case 'string': {
|
||||
return resolveValue(input, data);
|
||||
}
|
||||
|
||||
case 'object': {
|
||||
if (input == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (Array.isArray(input)) {
|
||||
return input.map((value) => resolve(value, data));
|
||||
} else {
|
||||
for (const key in input) {
|
||||
input[key] = resolve(input[key], data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces all template tags in a string 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) {
|
||||
export function resolveValue(input, data = templateData) {
|
||||
const tags = [];
|
||||
|
||||
if (data) {
|
||||
if (data !== templateData) {
|
||||
data = flatten(data);
|
||||
} else {
|
||||
data = templateData;
|
||||
}
|
||||
|
||||
for (let tag in data) {
|
||||
@@ -55,7 +91,7 @@ export default function template(input, data) {
|
||||
|
||||
return '';
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new object with all nested object properties
|
||||
|
||||
243
build/watch.js
243
build/watch.js
@@ -1,82 +1,195 @@
|
||||
import loconfig from '../loconfig.json';
|
||||
import concatFiles from './tasks/concats.js';
|
||||
import concatFiles, { developmentConcatFilesArgs } from './tasks/concats.js';
|
||||
import compileScripts, { developmentScriptsArgs } from './tasks/scripts.js';
|
||||
import compileStyles, { developmentStylesArgs } from './tasks/styles.js' ;
|
||||
import compileSVGs, { developmentSVGsArgs } from './tasks/svgs.js';
|
||||
import template from './utils/template.js';
|
||||
import server from 'browser-sync';
|
||||
import loconfig, { merge } from './utils/config.js';
|
||||
import message from './utils/message.js';
|
||||
import notification from './utils/notification.js';
|
||||
import resolve from './utils/template.js';
|
||||
import browserSync from 'browser-sync';
|
||||
import { join } from 'node:path';
|
||||
|
||||
const { paths, tasks } = loconfig;
|
||||
|
||||
const serverConfig = {
|
||||
open: false,
|
||||
notify: false
|
||||
};
|
||||
|
||||
if (typeof paths.url === 'string' && paths.url.length > 0) {
|
||||
// Use proxy
|
||||
serverConfig.proxy = paths.url;
|
||||
} else {
|
||||
// Use base directory
|
||||
serverConfig.server = {
|
||||
baseDir: paths.dest
|
||||
};
|
||||
}
|
||||
|
||||
// Start the Browsersync server
|
||||
server.init(serverConfig);
|
||||
// Match a URL protocol.
|
||||
const regexUrlStartsWithProtocol = /^[a-z0-9\-]:\/\//i;
|
||||
|
||||
// Build scripts, compile styles, concat files,
|
||||
// and generate spritesheets on first hit
|
||||
concatFiles();
|
||||
concatFiles(...developmentConcatFilesArgs);
|
||||
compileScripts(...developmentScriptsArgs);
|
||||
compileStyles(...developmentStylesArgs);
|
||||
compileSVGs(...developmentSVGsArgs);
|
||||
|
||||
// and call any methods on it.
|
||||
server.watch(
|
||||
[
|
||||
paths.views.src,
|
||||
join(paths.scripts.dest, '*.js'),
|
||||
join(paths.styles.dest, '*.css'),
|
||||
join(paths.svgs.dest, '*.svg'),
|
||||
]
|
||||
).on('change', server.reload);
|
||||
// Create a new BrowserSync instance
|
||||
const server = browserSync.create();
|
||||
|
||||
// Watch scripts
|
||||
server.watch(
|
||||
[
|
||||
join(paths.scripts.src, '**/*.js'),
|
||||
]
|
||||
).on('change', () => {
|
||||
compileScripts(...developmentScriptsArgs);
|
||||
// Start the BrowserSync server
|
||||
server.init(createServerOptions(loconfig), (err) => {
|
||||
if (err) {
|
||||
message('Error starting development server', 'error');
|
||||
message(err);
|
||||
|
||||
notification({
|
||||
title: 'Development server failed',
|
||||
message: `${err.name}: ${err.message}`
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Watch concats
|
||||
server.watch(
|
||||
tasks.concats.reduce(
|
||||
(patterns, { includes }) => patterns.concat(includes),
|
||||
[]
|
||||
).map((path) => template(path))
|
||||
).on('change', () => {
|
||||
concatFiles();
|
||||
});
|
||||
configureServer(server, loconfig);
|
||||
|
||||
// Watch styles
|
||||
server.watch(
|
||||
[
|
||||
join(paths.styles.src, '**/*.scss'),
|
||||
]
|
||||
).on('change', () => {
|
||||
compileStyles(...developmentStylesArgs);
|
||||
});
|
||||
/**
|
||||
* Configures the BrowserSync options.
|
||||
*
|
||||
* @param {BrowserSync} server - The BrowserSync API.
|
||||
* @param {object} loconfig - The project configset.
|
||||
* @param {object} loconfig.paths - The paths options.
|
||||
* @param {object} loconfig.tasks - The tasks options.
|
||||
* @return {void}
|
||||
*/
|
||||
function configureServer(server, { paths, tasks }) {
|
||||
const views = createViewsArray(paths.views);
|
||||
|
||||
// Watch svgs
|
||||
server.watch(
|
||||
[
|
||||
join(paths.svgs.src, '*.svg'),
|
||||
]
|
||||
).on('change', () => {
|
||||
compileSVGs(...developmentSVGsArgs);
|
||||
});
|
||||
// Reload on any changes to views or processed files
|
||||
server.watch(
|
||||
[
|
||||
...views,
|
||||
join(paths.scripts.dest, '*.js'),
|
||||
join(paths.styles.dest, '*.css'),
|
||||
join(paths.svgs.dest, '*.svg'),
|
||||
]
|
||||
).on('change', server.reload);
|
||||
|
||||
// Watch source scripts
|
||||
server.watch(
|
||||
[
|
||||
join(paths.scripts.src, '**/*.js'),
|
||||
]
|
||||
).on('change', () => {
|
||||
compileScripts(...developmentScriptsArgs);
|
||||
});
|
||||
|
||||
// Watch source concats
|
||||
server.watch(
|
||||
resolve(
|
||||
tasks.concats.reduce(
|
||||
(patterns, { includes }) => patterns.concat(includes),
|
||||
[]
|
||||
)
|
||||
)
|
||||
).on('change', () => {
|
||||
concatFiles(...developmentConcatFilesArgs);
|
||||
});
|
||||
|
||||
// Watch source styles
|
||||
server.watch(
|
||||
[
|
||||
join(paths.styles.src, '**/*.scss'),
|
||||
]
|
||||
).on('change', () => {
|
||||
compileStyles(...developmentStylesArgs);
|
||||
});
|
||||
|
||||
// Watch source SVGs
|
||||
server.watch(
|
||||
[
|
||||
join(paths.svgs.src, '*.svg'),
|
||||
]
|
||||
).on('change', () => {
|
||||
compileSVGs(...developmentSVGsArgs);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new object with all the BrowserSync options.
|
||||
*
|
||||
* @param {object} loconfig - The project configset.
|
||||
* @param {object} loconfig.paths - The paths options.
|
||||
* @param {object} loconfig.server - The server options.
|
||||
* @return {object} Returns the server options.
|
||||
*/
|
||||
function createServerOptions({
|
||||
paths,
|
||||
server: options
|
||||
}) {
|
||||
const config = {
|
||||
open: false,
|
||||
notify: false
|
||||
};
|
||||
|
||||
// Resolve the URL for the BrowserSync server
|
||||
if (isNonEmptyString(paths.url)) {
|
||||
// Use proxy
|
||||
config.proxy = paths.url;
|
||||
} else if (isNonEmptyString(paths.dest)) {
|
||||
// Use base directory
|
||||
config.server = {
|
||||
baseDir: paths.dest
|
||||
};
|
||||
}
|
||||
|
||||
merge(config, resolve(options));
|
||||
|
||||
// If HTTPS is enabled, prepend `https://` to proxy URL
|
||||
if (options?.https) {
|
||||
if (isNonEmptyString(config.proxy?.target)) {
|
||||
config.proxy.target = prependSchemeToUrl(config.proxy.target, 'https');
|
||||
} else if (isNonEmptyString(config.proxy)) {
|
||||
config.proxy = prependSchemeToUrl(config.proxy, 'https');
|
||||
}
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new array (shallow-copied) from the views configset.
|
||||
*
|
||||
* @param {*} views - The views configset.
|
||||
* @throws {TypeError} If views is invalid.
|
||||
* @return {array} Returns the views array.
|
||||
*/
|
||||
function createViewsArray(views) {
|
||||
if (Array.isArray(views)) {
|
||||
return Array.from(views);
|
||||
}
|
||||
|
||||
switch (typeof views) {
|
||||
case 'string':
|
||||
return [ views ];
|
||||
|
||||
case 'object':
|
||||
if (views != null) {
|
||||
return Object.values(views);
|
||||
}
|
||||
}
|
||||
|
||||
throw new TypeError(
|
||||
'Expected \'views\' to be a string, array, or object'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepends the scheme to the URL.
|
||||
*
|
||||
* @param {string} url - The URL to mutate.
|
||||
* @param {string} [scheme] - The URL scheme to prepend.
|
||||
* @return {string} Returns the mutated URL.
|
||||
*/
|
||||
function prependSchemeToUrl(url, scheme = 'http') {
|
||||
if (regexUrlStartsWithProtocol.test(url)) {
|
||||
return url.replace(regexUrlStartsWithProtocol, `${scheme}://`);
|
||||
}
|
||||
|
||||
return `${scheme}://${url}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the passed value is a string with at least one character.
|
||||
*
|
||||
* @param {*} value - The value to be checked.
|
||||
* @return {boolean} Returns `true` if the value is a non-empty string,
|
||||
* otherwise `false`.
|
||||
*/
|
||||
function isNonEmptyString(value) {
|
||||
return (typeof value === 'string' && value.length > 0);
|
||||
}
|
||||
|
||||
344
docs/development.md
Normal file
344
docs/development.md
Normal file
@@ -0,0 +1,344 @@
|
||||
# Development
|
||||
|
||||
* [Installation](#installation)
|
||||
* [Usage](#usage)
|
||||
* [Configuration](#configuration)
|
||||
* [Environment Configuration](#environment-configuration)
|
||||
* [Development Configuration](#development-configuration)
|
||||
* [`paths` option](#paths-option)
|
||||
* [`paths.url` option](#pathsurl-option)
|
||||
* [`paths.dest` option](#pathsdest-option)
|
||||
* [`tasks` option](#tasks-option)
|
||||
* [`server` option](#server-option)
|
||||
* [Tasks](#tasks)
|
||||
* [`concats`](#concats)
|
||||
* [`scripts`](#scripts)
|
||||
* [`styles`](#styles)
|
||||
* [`svgs`](#svgs)
|
||||
|
||||
---
|
||||
|
||||
The boilerplate provides a custom, easily configured, and very simple,
|
||||
task runner for [Node] to process assets and test quickly in browsers.
|
||||
|
||||
Learn more about the boilerplate's [tasks](#tasks) below.
|
||||
|
||||
## Installation
|
||||
|
||||
Make sure you have the following installed:
|
||||
|
||||
* [Node] — at least 14.17, the latest LTS is recommended.
|
||||
* [NPM] — at least 6.0, the latest LTS is recommended.
|
||||
|
||||
```sh
|
||||
# Switch to recommended Node version from .nvmrc
|
||||
nvm use
|
||||
|
||||
# Install dependencies from package.json
|
||||
npm install
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```sh
|
||||
# Start development server, watch for changes, and compile assets
|
||||
npm start
|
||||
|
||||
# Compile and minify assets
|
||||
npm run build
|
||||
```
|
||||
|
||||
See [`build.js`](../build/build.js) and [`watch.js`](../build/watch.js)
|
||||
for details.
|
||||
|
||||
## Configuration
|
||||
|
||||
For development, most configuration values for processing front-end assets
|
||||
are defined in the [`loconfig.json`](../loconfig.json) file that exists at
|
||||
the root directory of your project.
|
||||
|
||||
### Environment Configuration
|
||||
|
||||
If any configuration options vary depending on whether your project is
|
||||
running on your computer, a collaborator's computer, or on a web server,
|
||||
these values should be stored in a `loconfig.local.json` file.
|
||||
|
||||
In fresh copy of the boilerplate, the root directory of your project
|
||||
will contain a [`loconfig.example.json`](../loconfig.example.json) file.
|
||||
|
||||
> 💡 The boilerplate's default example customizes the development server
|
||||
> to use a custom SSL certificate.
|
||||
|
||||
That file can be copied to `loconfig.local.json` and customized to suit
|
||||
your local environment.
|
||||
|
||||
Your `loconfig.local.json` _should not_ be committed to your project's
|
||||
source control.
|
||||
|
||||
> 💡 If you are developing with a team, you may wish to continue
|
||||
> including a `loconfig.example.json` file with your project.
|
||||
|
||||
### Development Configuration
|
||||
|
||||
The boilerplate provides a few configuration settings to control the
|
||||
behaviour for processing front-end assets.
|
||||
|
||||
#### `paths` option
|
||||
|
||||
The `paths` option defines URIs and file paths.
|
||||
|
||||
It is primarily used for template tags to reference any configuration
|
||||
properties to reduce repetition.
|
||||
|
||||
Template tags are specified using `{% %}` delimiters. They will be
|
||||
automatically expanded when tasks process paths.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"paths": {
|
||||
"styles": {
|
||||
"src": "./assets/styles",
|
||||
"dest": "./www/assets/styles"
|
||||
}
|
||||
},
|
||||
"tasks": {
|
||||
"styles": [
|
||||
{
|
||||
"infile": "{% paths.styles.src %}/main.scss", // → ./assets/styles/main.scss
|
||||
"outfile": "{% paths.styles.dest %}/main.css" // → ./www/assets/styles/main.css
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### `paths.url` option
|
||||
|
||||
The `paths.url` option defines the base URI of the project.
|
||||
|
||||
By default, it is used by the development server as a proxy
|
||||
for an existing virtual host.
|
||||
|
||||
```json
|
||||
{
|
||||
"paths": {
|
||||
"url": "locomotive-boilerplate.test"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### `paths.dest` option
|
||||
|
||||
The `paths.dest` option defines the public web directory of the project.
|
||||
|
||||
By default, it is used by the development server as the base directory
|
||||
to serve the website from if a proxy URI is not provided.
|
||||
|
||||
```json
|
||||
{
|
||||
"paths": {
|
||||
"dest": "./www"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### `tasks` option
|
||||
|
||||
Which assets and how they should be processed can be configured via
|
||||
the `tasks` option:
|
||||
|
||||
```json
|
||||
{
|
||||
"tasks": {
|
||||
"scripts": [
|
||||
{
|
||||
"includes": [
|
||||
"./assets/scripts/app.js"
|
||||
],
|
||||
"outfile": "./www/assets/scripts/app.js"
|
||||
}
|
||||
],
|
||||
"styles": [
|
||||
{
|
||||
"infile": "./assets/styles/main.scss",
|
||||
"outfile": "./www/assets/styles/main.css"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
See [tasks](#tasks) section, below, for details.
|
||||
|
||||
#### `server` option
|
||||
|
||||
The development server (BrowserSync) can be configured via
|
||||
the `server` option:
|
||||
|
||||
```json
|
||||
{
|
||||
"server": {
|
||||
"open": true,
|
||||
"https": {
|
||||
"key": "~/.config/valet/Certificates/{% paths.url %}.key",
|
||||
"cert": "~/.config/valet/Certificates/{% paths.url %}.crt"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Visit [BrowserSync's documentation](https://browsersync.io/docs/options)
|
||||
for all options.
|
||||
|
||||
## Tasks
|
||||
|
||||
The boilerplate provides a handful of tasks for handling
|
||||
the most commonly processed assets.
|
||||
|
||||
### `concats`
|
||||
|
||||
A wrapper around [concat] (with optional support for globbing) for concatenating multiple files.
|
||||
|
||||
By default, [tiny-glob] is installed with the boilerplate.
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"concats": [
|
||||
{
|
||||
"label": "Application Vendors",
|
||||
"includes": [
|
||||
"{% paths.scripts.src %}/vendors/*.js",
|
||||
"node_modules/focus-visible/dist/focus-visible.min.js",
|
||||
"node_modules/vue/dist/vue.min.js",
|
||||
"node_modules/vuelidate/dist/vuelidate.min.js",
|
||||
"node_modules/vuelidate/dist/validators.min.js"
|
||||
],
|
||||
"outfile": "{% paths.scripts.dest %}/app/vendors.js"
|
||||
},
|
||||
{
|
||||
"label": "Public Site Vendors",
|
||||
"includes": [
|
||||
"{% paths.scripts.src %}/vendors/*.js",
|
||||
"node_modules/focus-visible/dist/focus-visible.min.js"
|
||||
],
|
||||
"outfile": "{% paths.scripts.dest %}/site/vendors.js"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
See [`concats.js`](../build/tasks/concats.js) for details.
|
||||
|
||||
### `scripts`
|
||||
|
||||
A wrapper around [esbuild] for bundling and minifying modern JS/ES modules.
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": [
|
||||
{
|
||||
"label": "Application Dashboard JS",
|
||||
"includes": [
|
||||
"{% paths.scripts.src %}/app/dashboard.js"
|
||||
],
|
||||
"outfile": "{% paths.scripts.dest %}/app/dashboard.js"
|
||||
},
|
||||
{
|
||||
"label": "Public Site JS",
|
||||
"includes": [
|
||||
"{% paths.scripts.src %}/site/main.js"
|
||||
],
|
||||
"outfile": "{% paths.scripts.dest %}/site/main.js"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
See [`scripts.js`](../build/tasks/scripts.js) for details.
|
||||
|
||||
### `styles`
|
||||
|
||||
A wrapper around [node-sass] (and optionally [Autoprefixer] via [PostCSS])
|
||||
for compiling and minifying Sass into CSS.
|
||||
|
||||
By default, [PostCSS] and [Autoprefixer] are installed with the boilerplate.
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"styles": [
|
||||
{
|
||||
"label": "Text Editor CSS",
|
||||
"infile": "{% paths.styles.src %}/app/editor.scss",
|
||||
"outfile": "{% paths.styles.dest %}/app/editor.css"
|
||||
},
|
||||
{
|
||||
"label": "Application Dashboard CSS",
|
||||
"infile": "{% paths.styles.src %}/app/dashboard.scss",
|
||||
"outfile": "{% paths.styles.dest %}/app/dashboard.css"
|
||||
},
|
||||
{
|
||||
"label": "Public Site Critical CSS",
|
||||
"infile": "{% paths.styles.src %}/site/critical.scss",
|
||||
"outfile": "{% paths.styles.dest %}/site/critical.css"
|
||||
},
|
||||
{
|
||||
"label": "Public Site CSS",
|
||||
"infile": "{% paths.styles.src %}/site/main.scss",
|
||||
"outfile": "{% paths.styles.dest %}/site/main.css"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
See [`styles.js`](../build/tasks/styles.js) for details.
|
||||
|
||||
### `svgs`
|
||||
|
||||
A wrapper around [SVG Mixer] for transforming and minifying SVG files
|
||||
and generating spritesheets.
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"svgs": [
|
||||
{
|
||||
"label": "Application Spritesheet",
|
||||
"includes": [
|
||||
"{% paths.images.src %}/app/*.svg"
|
||||
],
|
||||
"outfile": "{% paths.svgs.dest %}/app/sprite.svg"
|
||||
},
|
||||
{
|
||||
"label": "Public Site Spritesheet",
|
||||
"includes": [
|
||||
"{% paths.images.src %}/site/*.svg"
|
||||
],
|
||||
"outfile": "{% paths.svgs.dest %}/site/sprite.svg"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
See [`svgs.js`](../build/tasks/svgs.js) for details.
|
||||
|
||||
[Autoprefixer]: https://npmjs.com/package/autoprefixer
|
||||
[BrowserSync]: https://npmjs.com/package/browser-sync
|
||||
[concat]: https://npmjs.com/package/concat
|
||||
[esbuild]: https://npmjs.com/package/esbuild
|
||||
[fast-glob]: https://npmjs.com/package/fast-glob
|
||||
[glob]: https://npmjs.com/package/glob
|
||||
[globby]: https://npmjs.com/package/globby
|
||||
[Node]: https://nodejs.org/
|
||||
[node-sass]: https://npmjs.com/package/node-sass
|
||||
[NPM]: https://npmjs.com/
|
||||
[NVM]: https://github.com/nvm-sh/nvm
|
||||
[PostCSS]: https://npmjs.com/package/postcss
|
||||
[SVG Mixer]: https://npmjs.com/package/svg-mixer
|
||||
[tiny-glob]: https://npmjs.com/package/tiny-glob
|
||||
207
docs/technologies.md
Normal file
207
docs/technologies.md
Normal file
@@ -0,0 +1,207 @@
|
||||
# Technologies
|
||||
|
||||
* [Styles](#styles)
|
||||
* [CSS Architecture](#css-architecture)
|
||||
* [CSS Naming Convention](#css-naming-convention)
|
||||
* [CSS Namespacing](#css-namespacing)
|
||||
* [Example](#example-1)
|
||||
* [Scripts](#scripts)
|
||||
* [Example](#example-2)
|
||||
* [Page transitions](#page-transitions)
|
||||
* [Example](#example-3)
|
||||
* [Scroll detection](#scroll-detection)
|
||||
* [Example](#example-4)
|
||||
|
||||
## Styles
|
||||
|
||||
[SCSS][Sass] is a superset of CSS that adds many helpful features to improve
|
||||
and modularize our styles.
|
||||
|
||||
We use [node-sass] (LibSass) for processing and minifying SCSS into CSS.
|
||||
|
||||
We also use [PostCSS] and [Autoprefixer] to parse our CSS and add
|
||||
vendor prefixes for experimental features.
|
||||
|
||||
### CSS Architecture
|
||||
|
||||
The boilerplate's CSS architecture is based on [Inuit CSS][inuitcss] and [ITCSS].
|
||||
|
||||
* `settings`: Global variables, site-wide settings, config switches, etc.
|
||||
* `tools`: Site-wide mixins and functions.
|
||||
* `generic`: Low-specificity, far-reaching rulesets (e.g. resets).
|
||||
* `elements`: Unclassed HTML elements (e.g. `a {}`, `blockquote {}`, `address {}`).
|
||||
* `objects`: Objects, abstractions, and design patterns (e.g. `.o-layout {}`).
|
||||
* `components`: Discrete, complete chunks of UI (e.g. `.c-carousel {}`).
|
||||
* `utilities`: High-specificity, very explicit selectors. Overrides and helper
|
||||
classes (e.g. `.u-hidden {}`)
|
||||
|
||||
Learn more about [Inuit CSS](https://github.com/inuitcss/inuitcss#css-directory-structure).
|
||||
|
||||
### CSS Naming Convention
|
||||
|
||||
We use a simplified [BEM] (Block, Element, Modifier) syntax:
|
||||
|
||||
* `.block`
|
||||
* `.block_element`
|
||||
* `.-modifier`
|
||||
|
||||
### CSS Namespacing
|
||||
|
||||
We namespace our classes for more UI transparency:
|
||||
|
||||
* `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.
|
||||
* `c-`: Component is a concrete, implementation-specific piece of UI. All of the changes you make to its styles should be detectable in the context you’re currently looking at. Modifying these styles should be safe and have no side effects.
|
||||
* `u-`: Utility has a very specific role (often providing only one declaration) and should not be bound onto or changed. It can be reused and is not tied to any specific piece of UI.
|
||||
* `s-`: Scope creates a new styling context. Similar to a Theme, but not necessarily cosmetic, these should be used sparingly—they can be open to abuse and lead to poor CSS if not used wisely.
|
||||
* `is-`, `has-`: Is currently styled a certain way because of a state or condition. It tells us that the DOM currently has a temporary, optional, or short-lived style applied to it due to a certain state being invoked.
|
||||
|
||||
Learn about [namespacing](https://csswizardry.com/2015/03/more-transparent-ui-code-with-namespaces/).
|
||||
|
||||
### Example \#1
|
||||
|
||||
```html
|
||||
<div class="c-block -large">
|
||||
<div class="c-block_layout o-layout">
|
||||
<div class="o-layout_item u-1/2@from-medium">
|
||||
<div class="c-block_heading o-h -medium">Heading</div>
|
||||
</div>
|
||||
<div class="o-layout_item u-1/2@from-medium">
|
||||
<a class="c-block_button o-button -outline" href="#">Button</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
```scss
|
||||
.c-block {
|
||||
&.-large {
|
||||
padding: rem(60px);
|
||||
}
|
||||
}
|
||||
|
||||
.c-block_heading {
|
||||
@media (max-width: $to-medium) {
|
||||
.c-block.-large & {
|
||||
margin-bottom: rem(40px);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Scripts
|
||||
|
||||
We use [esbuild] for bundling and minifying JavaScript/ES modules.
|
||||
|
||||
[modularJS] is a small framework we use on top of ES modules.
|
||||
|
||||
* 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://npmjs.com/package/modujs#why)
|
||||
|
||||
### Example \#2
|
||||
|
||||
```html
|
||||
<div data-module-example>
|
||||
<div data-example="main">
|
||||
<h2>Example</h2>
|
||||
</div>
|
||||
<button data-example="load">More</button>
|
||||
</div>
|
||||
```
|
||||
|
||||
```js
|
||||
import { module } from 'modujs';
|
||||
|
||||
export default class extends module {
|
||||
constructor(m) {
|
||||
super(m);
|
||||
|
||||
this.events = {
|
||||
click: {
|
||||
load: 'loadMore'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
loadMore() {
|
||||
this.$('main')[0].classList.add('is-loading');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Learn more about [modularJS].
|
||||
|
||||
## Page transitions
|
||||
|
||||
[modularLoad] is used for page transitions and lazy loading.
|
||||
|
||||
### Example \#3
|
||||
|
||||
```html
|
||||
<nav>
|
||||
<a href="/">Home</a>
|
||||
<a href="/page" data-load="transitionName">Page</a>
|
||||
</nav>
|
||||
<div data-load-container>
|
||||
<img data-load-src="assets/images/hello.jpg">
|
||||
</div>
|
||||
```
|
||||
```js
|
||||
import modularLoad from 'modularload';
|
||||
|
||||
this.load = new modularLoad({
|
||||
enterDelay: 300,
|
||||
transitions: {
|
||||
transitionName: {
|
||||
enterDelay: 450
|
||||
}
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
Learn more about [modularLoad].
|
||||
|
||||
## Scroll detection
|
||||
|
||||
[Locomotive Scroll][locomotive-scroll] is used for elements in viewport
|
||||
detection and smooth scrolling with parallax.
|
||||
|
||||
### Example \#4
|
||||
|
||||
```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';
|
||||
|
||||
this.scroll = new LocomotiveScroll({
|
||||
el: this.el,
|
||||
smooth: true
|
||||
});
|
||||
````
|
||||
|
||||
Learn more about [Locomotive Scroll][locomotive-scroll].
|
||||
|
||||
[Autoprefixer]: https://npmjs.com/package/autoprefixer
|
||||
[BEM]: https://bem.info/
|
||||
[BrowserSync]: https://npmjs.com/package/browser-sync
|
||||
[esbuild]: https://npmjs.com/package/esbuild
|
||||
[inuitcss]: https://github.com/inuitcss/inuitcss
|
||||
[ITCSS]: https://itcss.io/
|
||||
[locomotive-scroll]: https://npmjs.com/package/locomotive-scroll
|
||||
[modularJS]: https://npmjs.com/package/modujs
|
||||
[modularLoad]: https://npmjs.com/package/modularload
|
||||
[node-sass]: https://npmjs.com/package/node-sass
|
||||
[PostCSS]: https://npmjs.com/package/postcss
|
||||
[Sass]: https://sass-lang.com/
|
||||
[svg-mixer]: https://npmjs.com/package/svg-mixer
|
||||
[Node]: https://nodejs.org/
|
||||
[NPM]: https://npmjs.com/
|
||||
[NVM]: https://github.com/nvm-sh/nvm
|
||||
8
loconfig.example.json
Executable file
8
loconfig.example.json
Executable file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"server": {
|
||||
"https": {
|
||||
"key": "~/.config/valet/Certificates/{% paths.url %}.key",
|
||||
"cert": "~/.config/valet/Certificates/{% paths.url %}.crt"
|
||||
}
|
||||
}
|
||||
}
|
||||
4691
package-lock.json
generated
4691
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
16
package.json
16
package.json
@@ -14,21 +14,21 @@
|
||||
"build": "node --experimental-json-modules --no-warnings build/build.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"locomotive-scroll": "^4.1.3",
|
||||
"@barba/core": "^2.9.7",
|
||||
"locomotive-scroll": "^4.1.4",
|
||||
"modujs": "^1.4.2",
|
||||
"modularload": "^1.2.6",
|
||||
"normalize.css": "^8.0.1",
|
||||
"svg4everybody": "^2.1.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^10.4.0",
|
||||
"browser-sync": "^2.27.7",
|
||||
"autoprefixer": "^10.4.4",
|
||||
"browser-sync": "^2.27.9",
|
||||
"concat": "^1.0.3",
|
||||
"esbuild": "^0.13.12",
|
||||
"esbuild": "^0.14.27",
|
||||
"kleur": "^4.1.4",
|
||||
"node-notifier": "^10.0.0",
|
||||
"node-sass": "^6.0.1",
|
||||
"postcss": "^8.3.11",
|
||||
"node-notifier": "^10.0.1",
|
||||
"node-sass": "^7.0.1",
|
||||
"postcss": "^8.4.12",
|
||||
"svg-mixer": "^2.3.14",
|
||||
"tiny-glob": "^0.2.9"
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -16,8 +16,8 @@
|
||||
|
||||
<link id="main-css" rel="stylesheet" href="assets/styles/main.css" media="print" onload="this.media='all'; this.onload=null; this.isLoaded=true">
|
||||
</head>
|
||||
<body data-module-load>
|
||||
<div data-load-container>
|
||||
<body data-module-load data-load="wrapper">
|
||||
<div data-load="container">
|
||||
<div class="o-scroll" data-module-scroll="main">
|
||||
<header data-scroll-section>
|
||||
<a href="/"><h1>Locomotive Boilerplate</h1></a>
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
<link id="main-css" rel="stylesheet" href="assets/styles/main.css" media="print" onload="this.media='all'; this.onload=null; this.isLoaded=true">
|
||||
</head>
|
||||
<body data-module-load>
|
||||
<div data-load-container>
|
||||
<body data-module-load data-load="wrapper">
|
||||
<div data-load="container">
|
||||
<div class="o-scroll" data-module-scroll="main">
|
||||
<header data-scroll-section>
|
||||
<a href="/"><h1>Locomotive Boilerplate</h1></a>
|
||||
|
||||
@@ -33,8 +33,8 @@
|
||||
onload="this.media='all'; this.onload=null; this.isLoaded=true">
|
||||
</head>
|
||||
|
||||
<body data-module-load>
|
||||
<div data-load-container>
|
||||
<body data-module-load data-load="wrapper">
|
||||
<div data-load="container">
|
||||
<div class="o-scroll" data-module-scroll="main">
|
||||
<header data-scroll-section>
|
||||
<a href="/">
|
||||
|
||||
Reference in New Issue
Block a user