mirror of
https://github.com/locomotivemtl/locomotive-boilerplate.git
synced 2026-01-15 00:55:08 +08:00
Compare commits
122 Commits
feature/ty
...
devenini/d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb5957024d | ||
|
|
7c1b61eda9 | ||
|
|
68dd79caef | ||
|
|
be89145728 | ||
|
|
8f3034d54a | ||
|
|
3fa1de473c | ||
|
|
ecf60ee507 | ||
|
|
9632d6270e | ||
|
|
bc3a1a6934 | ||
|
|
e4ae03a94c | ||
|
|
3cde7d40ee | ||
|
|
d1d4fb5fe5 | ||
|
|
2f6b353616 | ||
|
|
3cd81bdb3e | ||
|
|
b6970832a3 | ||
|
|
b8f0a24cdc | ||
|
|
0c718a2644 | ||
|
|
56d255eac8 | ||
|
|
e7e343e62c | ||
|
|
590e06fc03 | ||
|
|
4fd7968b86 | ||
|
|
20b167da33 | ||
|
|
f7ca837782 | ||
|
|
0c8ed9595f | ||
|
|
eead1d27cd | ||
|
|
2e3db21ec8 | ||
|
|
9c478f5f7d | ||
|
|
ebcbb6dc84 | ||
|
|
b7c49086c9 | ||
|
|
9219a4cc0a | ||
|
|
14afe2295a | ||
|
|
1bdd2def8d | ||
|
|
84ce496df7 | ||
|
|
05e631dbca | ||
|
|
f8f0a7779c | ||
|
|
8e320f2cd0 | ||
|
|
a8314d064f | ||
|
|
76614e8126 | ||
|
|
bed84ce392 | ||
|
|
feb2241164 | ||
|
|
b1f5a00b8c | ||
|
|
2b30d9ac5c | ||
|
|
9e5704238e | ||
|
|
1ede84e1b1 | ||
|
|
3a83a3209b | ||
|
|
98957eb6c4 | ||
|
|
6712d2d24d | ||
|
|
139a6739f6 | ||
|
|
3272521dba | ||
|
|
e7f0455ce4 | ||
|
|
bf425521c4 | ||
|
|
4bdaa5d085 | ||
|
|
a385f6ed11 | ||
|
|
4079752fe0 | ||
|
|
14d7e09b2b | ||
|
|
e70bf33409 | ||
|
|
8b0926269a | ||
|
|
8d1b548ad0 | ||
|
|
7ca7486913 | ||
|
|
520b75185f | ||
|
|
a056a87855 | ||
|
|
9b99a1958b | ||
|
|
d6193a41fa | ||
|
|
4fafcb8e1d | ||
|
|
aadc410e44 | ||
|
|
0439b165cf | ||
|
|
f98eebc9e1 | ||
|
|
cb80a2ed13 | ||
|
|
07c3155c29 | ||
|
|
c264cb7905 | ||
|
|
1050b83326 | ||
|
|
d0a075ff24 | ||
|
|
ad4a1c7d47 | ||
|
|
de6b3d73a1 | ||
|
|
e8af22009c | ||
|
|
de1a5904a8 | ||
|
|
f527488464 | ||
|
|
cf3f40c956 | ||
|
|
ebb55769f9 | ||
|
|
c8d4e7c154 | ||
|
|
bce37afb6e | ||
|
|
7a23abff92 | ||
|
|
27d8fdee22 | ||
|
|
9154deb036 | ||
|
|
17e8004515 | ||
|
|
9a461ab4c0 | ||
|
|
6b3edefa48 | ||
|
|
fd5efe3531 | ||
|
|
2783fb5138 | ||
|
|
f1e4cd2c55 | ||
|
|
b7d25c5865 | ||
|
|
0a199afe01 | ||
|
|
8ca570b37a | ||
|
|
e5417ff6ab | ||
|
|
3a94c6aba9 | ||
|
|
648109fc9b | ||
|
|
eddc0ee156 | ||
|
|
202e4064f8 | ||
|
|
e20111fd2e | ||
|
|
de0c4993cb | ||
|
|
b162c62930 | ||
|
|
cb27975087 | ||
|
|
0b667542f5 | ||
|
|
d7de1b2566 | ||
|
|
34bca7d68a | ||
|
|
f44093ec19 | ||
|
|
6a4043408b | ||
|
|
92500f908f | ||
|
|
d97fa82c77 | ||
|
|
ccf813f6be | ||
|
|
141a8ffa97 | ||
|
|
e875495928 | ||
|
|
c2db2e1922 | ||
|
|
32ba1c0eeb | ||
|
|
5199ee2025 | ||
|
|
d6c8fdac23 | ||
|
|
15a4f2e64f | ||
|
|
9e35894ef1 | ||
|
|
cabeba55c0 | ||
|
|
47974a77a9 | ||
|
|
e8b2a86798 | ||
|
|
da66f89d7f |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,3 +3,4 @@ node_modules
|
||||
Thumbs.db
|
||||
loconfig.*.json
|
||||
!loconfig.example.json
|
||||
.prettierrc
|
||||
7
.prettierrc.json
Normal file
7
.prettierrc.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"tabWidth": 4,
|
||||
"trailingComma": "es5",
|
||||
"useTabs": false
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
* 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.
|
||||
* Uses a custom [grid system](docs/grid.md) for layout creation.
|
||||
|
||||
Learn more about [languages and technologies](docs/technologies.md).
|
||||
|
||||
@@ -22,8 +23,8 @@ Learn more about [languages and technologies](docs/technologies.md).
|
||||
|
||||
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.
|
||||
* [Node] — at least 18.13, the latest LTS is recommended.
|
||||
* [NPM] — at least 8.0, the latest LTS is recommended.
|
||||
|
||||
> 💡 You can use [NVM] to install and use different versions of Node via the command-line.
|
||||
|
||||
@@ -84,6 +85,7 @@ Learn more about [development and building](docs/development.md).
|
||||
|
||||
* [Development and building](docs/development.md)
|
||||
* [Languages and technologies](docs/technologies.md)
|
||||
* [Grid system](docs/grid.md)
|
||||
|
||||
[BrowserSync]: https://npmjs.com/package/browser-sync
|
||||
[ESBuild]: https://npmjs.com/package/esbuild
|
||||
|
||||
3
assets.json
Normal file
3
assets.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"version": 1675197299100
|
||||
}
|
||||
0
assets/images/sprite/.gitkeep
Normal file
0
assets/images/sprite/.gitkeep
Normal file
@@ -1,35 +1,79 @@
|
||||
import modular from 'modujs';
|
||||
import * as modules from './modules';
|
||||
import globals from './globals';
|
||||
import { html } from './utils/environment';
|
||||
import modular from 'modujs'
|
||||
import * as modules from './modules'
|
||||
import globals from './globals'
|
||||
import { html } from './utils/environment'
|
||||
import config from './config'
|
||||
import { isFontLoadingAPIAvailable, loadFonts } from './utils/fonts'
|
||||
|
||||
const app = new modular({
|
||||
modules: modules
|
||||
});
|
||||
modules: modules,
|
||||
})
|
||||
|
||||
window.onload = (event) => {
|
||||
const $style = document.getElementById('main-css');
|
||||
const $style = document.getElementById('main-css')
|
||||
|
||||
if ($style) {
|
||||
if ($style.isLoaded) {
|
||||
init();
|
||||
init()
|
||||
} else {
|
||||
$style.addEventListener('load', (event) => {
|
||||
init();
|
||||
});
|
||||
init()
|
||||
})
|
||||
}
|
||||
} else {
|
||||
console.warn('The "main-css" stylesheet not found');
|
||||
console.warn('The "main-css" stylesheet not found')
|
||||
}
|
||||
};
|
||||
|
||||
function init() {
|
||||
globals();
|
||||
|
||||
app.init(app);
|
||||
|
||||
html.classList.add('is-loaded');
|
||||
html.classList.add('is-ready');
|
||||
html.classList.remove('is-loading');
|
||||
}
|
||||
|
||||
export const EAGER_FONTS = [
|
||||
{ family: 'Source Sans', style: 'normal', weight: 400 },
|
||||
{ family: 'Source Sans', style: 'normal', weight: 700 },
|
||||
]
|
||||
|
||||
function init() {
|
||||
globals()
|
||||
|
||||
app.init(app)
|
||||
|
||||
html.classList.add('is-loaded')
|
||||
html.classList.add('is-ready')
|
||||
html.classList.remove('is-loading')
|
||||
|
||||
/**
|
||||
* Eagerly load the following fonts.
|
||||
*/
|
||||
if (isFontLoadingAPIAvailable) {
|
||||
loadFonts(EAGER_FONTS, config.IS_DEV).then((eagerFonts) => {
|
||||
html.classList.add('fonts-loaded')
|
||||
|
||||
if (config.IS_DEV) {
|
||||
console.group(
|
||||
'Eager fonts loaded!',
|
||||
eagerFonts.length,
|
||||
'/',
|
||||
document.fonts.size
|
||||
)
|
||||
console.group('State of eager fonts:')
|
||||
eagerFonts.forEach((font) =>
|
||||
console.log(
|
||||
font.family,
|
||||
font.style,
|
||||
font.weight,
|
||||
font.status /*, font*/
|
||||
)
|
||||
)
|
||||
console.groupEnd()
|
||||
console.group('State of all fonts:')
|
||||
document.fonts.forEach((font) =>
|
||||
console.log(
|
||||
font.family,
|
||||
font.style,
|
||||
font.weight,
|
||||
font.status /*, font*/
|
||||
)
|
||||
)
|
||||
console.groupEnd()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
24
assets/scripts/config.js
Normal file
24
assets/scripts/config.js
Normal file
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* > When using the esBuild API, all `process.env.NODE_ENV` expressions
|
||||
* > are automatically defined to `"production"` if all minification
|
||||
* > options are enabled and `"development"` otherwise. This only happens
|
||||
* > if `process`, `process.env`, and `process.env.NODE_ENV` are not already
|
||||
* > defined. This substitution is necessary to avoid code crashing instantly
|
||||
* > (since `process` is a Node API, not a web API).
|
||||
* > — https://esbuild.github.io/api/#platform
|
||||
*/
|
||||
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,23 @@
|
||||
import svg4everybody from 'svg4everybody';
|
||||
import svg4everybody from 'svg4everybody'
|
||||
import config from './config'
|
||||
|
||||
export default function() {
|
||||
svg4everybody();
|
||||
// Dynamic imports for development mode only
|
||||
let gridHelper
|
||||
;(async () => {
|
||||
if (config.IS_DEV) {
|
||||
const gridHelperModule = await import('./utils/grid-helper')
|
||||
gridHelper = gridHelperModule?.gridHelper
|
||||
}
|
||||
})()
|
||||
|
||||
export default function () {
|
||||
/**
|
||||
* Use external SVG spritemaps
|
||||
*/
|
||||
svg4everybody()
|
||||
|
||||
/**
|
||||
* Add grid helper
|
||||
*/
|
||||
gridHelper?.()
|
||||
}
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export {default as Load} from './modules/Load';
|
||||
export {default as Scroll} from './modules/Scroll';
|
||||
export { default as Example } from './modules/Example'
|
||||
export { default as Load } from './modules/Load'
|
||||
export { default as Scroll } from './modules/Scroll'
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
import { module } from 'modujs';
|
||||
import { module as Module } from 'modujs'
|
||||
import { EAGER_FONTS } from '../app'
|
||||
import { whenReady } from '../utils/fonts'
|
||||
|
||||
export default class extends module {
|
||||
export default class extends Module {
|
||||
constructor(m) {
|
||||
super(m);
|
||||
super(m)
|
||||
}
|
||||
|
||||
init() {
|
||||
whenReady(EAGER_FONTS).then((fonts) => this.onFontsLoaded(fonts))
|
||||
}
|
||||
|
||||
onFontsLoaded(fonts) {
|
||||
console.log('Example: Eager Fonts Loaded!', fonts)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import { module } from 'modujs';
|
||||
import modularLoad from 'modularload';
|
||||
import { module as Module } from 'modujs'
|
||||
import modularLoad from 'modularload'
|
||||
|
||||
export default class extends module {
|
||||
export default class extends Module {
|
||||
constructor(m) {
|
||||
super(m);
|
||||
super(m)
|
||||
}
|
||||
|
||||
init() {
|
||||
const load = new modularLoad({
|
||||
enterDelay: 0,
|
||||
transitions: {
|
||||
customTransition: {}
|
||||
}
|
||||
});
|
||||
customTransition: {},
|
||||
},
|
||||
})
|
||||
|
||||
load.on('loaded', (transition, oldContainer, newContainer) => {
|
||||
this.call('destroy', oldContainer, 'app');
|
||||
this.call('update', newContainer, 'app');
|
||||
});
|
||||
this.call('destroy', oldContainer, 'app')
|
||||
this.call('update', newContainer, 'app')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import { module } from 'modujs';
|
||||
import { lazyLoadImage } from '../utils/image';
|
||||
import LocomotiveScroll from 'locomotive-scroll';
|
||||
import { module as Module } from 'modujs'
|
||||
import { lazyLoadImage } from '../utils/image'
|
||||
import LocomotiveScroll from 'locomotive-scroll'
|
||||
|
||||
export default class extends module {
|
||||
export default class extends Module {
|
||||
constructor(m) {
|
||||
super(m);
|
||||
super(m)
|
||||
}
|
||||
|
||||
init() {
|
||||
this.scroll = new LocomotiveScroll({
|
||||
el: this.el,
|
||||
smooth: true
|
||||
});
|
||||
smooth: true,
|
||||
})
|
||||
|
||||
this.scroll.on('call', (func, way, obj, id) => {
|
||||
// Using modularJS
|
||||
this.call(func[0], { way, obj }, func[1], func[2]);
|
||||
});
|
||||
this.call(func[0], { way, obj }, func[1], func[2])
|
||||
})
|
||||
|
||||
this.scroll.on('scroll', (args) => {
|
||||
// console.log(args.scroll);
|
||||
@@ -47,6 +47,6 @@ export default class extends module {
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.scroll.destroy();
|
||||
this.scroll.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
import { isArray } from './is';
|
||||
|
||||
export function addToArray ( array, value ) {
|
||||
const index = array.indexOf( value );
|
||||
|
||||
if ( index === -1 ) {
|
||||
array.push( value );
|
||||
}
|
||||
}
|
||||
|
||||
export function arrayContains ( array, value ) {
|
||||
for ( let i = 0, c = array.length; i < c; i++ ) {
|
||||
if ( array[i] == value ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export function arrayContentsMatch ( a, b ) {
|
||||
let i;
|
||||
|
||||
if ( !isArray( a ) || !isArray( b ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( a.length !== b.length ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
i = a.length;
|
||||
while ( i-- ) {
|
||||
if ( a[i] !== b[i] ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function ensureArray ( x ) {
|
||||
if ( typeof x === 'string' ) {
|
||||
return [ x ];
|
||||
}
|
||||
|
||||
if ( x === undefined ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
export function lastItem ( array ) {
|
||||
return array[ array.length - 1 ];
|
||||
}
|
||||
|
||||
export function removeFromArray ( array, member ) {
|
||||
if ( !array ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const index = array.indexOf( member );
|
||||
|
||||
if ( index !== -1 ) {
|
||||
array.splice( index, 1 );
|
||||
}
|
||||
}
|
||||
|
||||
export function toArray ( arrayLike ) {
|
||||
const array = [];
|
||||
let i = arrayLike.length;
|
||||
while ( i-- ) {
|
||||
array[i] = arrayLike[i];
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
export function findByKeyValue( array, key, value ) {
|
||||
return array.filter(function( obj ) {
|
||||
return obj[key] === value;
|
||||
});
|
||||
}
|
||||
|
||||
export function cloneArray( array ) {
|
||||
return JSON.parse(JSON.stringify(array));
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuffles array in place. ES6 version
|
||||
* @param {Array} a items An array containing the items.
|
||||
*/
|
||||
export function shuffle(a) {
|
||||
for (let i = a.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[a[i], a[j]] = [a[j], a[i]];
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
export default function(func, wait, immediate) {
|
||||
let timeout;
|
||||
return function() {
|
||||
const context = this;
|
||||
const args = arguments;
|
||||
const later = function() {
|
||||
timeout = null;
|
||||
if (!immediate) func.apply(context, args);
|
||||
};
|
||||
const callNow = immediate && !timeout;
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(later, wait);
|
||||
if (callNow) func.apply(context, args);
|
||||
};
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
const APP_NAME = 'Boilerplate';
|
||||
const DATA_API_KEY = '.data-api';
|
||||
const APP_NAME = 'Boilerplate'
|
||||
const DATA_API_KEY = '.data-api'
|
||||
|
||||
const html = document.documentElement;
|
||||
const body = document.body;
|
||||
const isDebug = html.hasAttribute('data-debug');
|
||||
const html = document.documentElement
|
||||
const body = document.body
|
||||
const isDebug = html.hasAttribute('data-debug')
|
||||
|
||||
export { APP_NAME, DATA_API_KEY, html, body, isDebug };
|
||||
export { APP_NAME, DATA_API_KEY, html, body, isDebug }
|
||||
|
||||
391
assets/scripts/utils/fonts.js
Normal file
391
assets/scripts/utils/fonts.js
Normal file
@@ -0,0 +1,391 @@
|
||||
/**
|
||||
* Font Faces
|
||||
*
|
||||
* Provides utilities to facilitate interactions with the CSS Font Loading API.
|
||||
*
|
||||
* Features functions to:
|
||||
*
|
||||
* - Retrieve one or more `FontFace` instances based on a font search query.
|
||||
* - Check if a `FontFace` instance matches a font search query.
|
||||
* - Eagerly load fonts that match a font search query.
|
||||
* - Wait until fonts that match a font search query are loaded.
|
||||
*
|
||||
* References:
|
||||
*
|
||||
* - {@link https://developer.mozilla.org/en-US/docs/Web/API/CSS_Font_Loading_API}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} FontFaceReference
|
||||
*
|
||||
* @property {string} family - The name used to identify the font in our CSS.
|
||||
* @property {string} [style] - The style used by the font in our CSS.
|
||||
* @property {string} [weight] - The weight used by the font in our CSS.
|
||||
*/
|
||||
|
||||
const isFontLoadingAPIAvailable = 'fonts' in document
|
||||
|
||||
/**
|
||||
* Determines if the given font matches the given `FontFaceReference`.
|
||||
*
|
||||
* @param {FontFace} font - The font to inspect.
|
||||
* @param {FontFaceReference} criterion - The object of property values to match.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function conformsToReference(font, criterion) {
|
||||
for (const [key, value] of Object.entries(criterion)) {
|
||||
switch (key) {
|
||||
case 'family': {
|
||||
if (trim(font[key]) !== value) {
|
||||
return false
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 'weight': {
|
||||
/**
|
||||
* Note concerning font weights:
|
||||
* Loose equality (`==`) is used to compare numeric weights,
|
||||
* a number (`400`) and a numeric string (`"400"`).
|
||||
* Comparison between numeric and keyword values is neglected.
|
||||
*
|
||||
* @link https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight#common_weight_name_mapping
|
||||
*/
|
||||
if (font[key] != value) {
|
||||
return false
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
default: {
|
||||
if (font[key] !== value) {
|
||||
return false
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the given font matches the given font shorthand.
|
||||
*
|
||||
* @param {FontFace} font - The font to inspect.
|
||||
* @param {string} criterion - The font shorthand to match.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function conformsToShorthand(font, criterion) {
|
||||
const family = trim(font.family)
|
||||
|
||||
if (trim(family) === criterion) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (
|
||||
criterion.endsWith(trim(family)) &&
|
||||
(criterion.match(font.weight) || criterion.match(font.style))
|
||||
) {
|
||||
return true
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the given font matches any of the given criteria.
|
||||
*
|
||||
* @param {FontFace} font - The font to inspect.
|
||||
* @param {FontFaceReference[]} criteria - A list of objects with property values to match.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function conformsToAnyReference(font, criteria) {
|
||||
for (const criterion of criteria) {
|
||||
if (conformsToReference(font, criterion)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator of all `FontFace` from `document.fonts` that satisfy
|
||||
* the provided `FontFaceReference`.
|
||||
*
|
||||
* @param {FontFaceReference} font
|
||||
*
|
||||
* @returns {FontFace[]}
|
||||
*/
|
||||
function findManyByReference(search) {
|
||||
const found = []
|
||||
|
||||
for (const font of document.fonts) {
|
||||
if (conformsToReference(font, search)) {
|
||||
found.push(font)
|
||||
}
|
||||
}
|
||||
|
||||
return found
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator of all `FontFace` from `document.fonts` that satisfy
|
||||
* the provided font shorthand.
|
||||
*
|
||||
* @param {string} font
|
||||
*
|
||||
* @returns {FontFace[]}
|
||||
*/
|
||||
function findManyByShorthand(search) {
|
||||
const found = []
|
||||
|
||||
for (const font of document.fonts) {
|
||||
if (conformsToShorthand(font, search)) {
|
||||
found.push(font)
|
||||
}
|
||||
}
|
||||
|
||||
return found
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first `FontFace` from `document.fonts` that satisfies
|
||||
* the provided `FontFaceReference`.
|
||||
*
|
||||
* @param {FontFaceReference} font
|
||||
*
|
||||
* @returns {?FontFace}
|
||||
*/
|
||||
function findOneByReference(search) {
|
||||
for (const font of document.fonts) {
|
||||
if (conformsToReference(font, criterion)) {
|
||||
return font
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first `FontFace` from `document.fonts` that satisfies
|
||||
* the provided font shorthand.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* - "Roboto"
|
||||
* - "italic bold 16px Roboto"
|
||||
*
|
||||
* @param {string} font
|
||||
*
|
||||
* @returns {?FontFace}
|
||||
*/
|
||||
function findOneByShorthand(search) {
|
||||
for (const font of document.fonts) {
|
||||
if (conformsToShorthand(font, search)) {
|
||||
return font
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a `FontFace` from `document.fonts` that satisfies
|
||||
* the provided query.
|
||||
*
|
||||
* @param {FontFaceReference|string} font - Either:
|
||||
* - a `FontFaceReference` object
|
||||
* - a font family name
|
||||
* - a font specification, for example "italic bold 16px Roboto"
|
||||
*
|
||||
* @returns {?FontFace}
|
||||
*
|
||||
* @throws {TypeError}
|
||||
*/
|
||||
function getAny(search) {
|
||||
if (search) {
|
||||
switch (typeof search) {
|
||||
case 'string':
|
||||
return findOneByShorthand(search)
|
||||
|
||||
case 'object':
|
||||
return findOneByReference(search)
|
||||
}
|
||||
}
|
||||
|
||||
throw new TypeError(
|
||||
'Expected font query to be font shorthand or font reference'
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator of all `FontFace` from `document.fonts` that satisfy
|
||||
* the provided queries.
|
||||
*
|
||||
* @param {FontFaceReference|string|(FontFaceReference|string)[]} queries
|
||||
*
|
||||
* @returns {FontFace[]}
|
||||
*
|
||||
* @throws {TypeError}
|
||||
*/
|
||||
function getMany(queries) {
|
||||
if (!Array.isArray(queries)) {
|
||||
queries = [queries]
|
||||
}
|
||||
|
||||
const found = new Set()
|
||||
|
||||
queries.forEach((search) => {
|
||||
if (search) {
|
||||
switch (typeof search) {
|
||||
case 'string':
|
||||
found.add(...findManyByShorthand(search))
|
||||
return
|
||||
|
||||
case 'object':
|
||||
found.add(...findManyByReference(search))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
throw new TypeError(
|
||||
'Expected font query to be font shorthand or font reference'
|
||||
)
|
||||
})
|
||||
|
||||
return [...found]
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a font face is registered.
|
||||
*
|
||||
* @param {FontFace|FontFaceReference|string} search - Either:
|
||||
* - a `FontFace` instance
|
||||
* - a `FontFaceReference` object
|
||||
* - a font family name
|
||||
* - a font specification, for example "italic bold 16px Roboto"
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasAny(search) {
|
||||
if (search instanceof FontFace) {
|
||||
return document.fonts.has(search)
|
||||
}
|
||||
|
||||
return getAny(search) != null
|
||||
}
|
||||
|
||||
/**
|
||||
* Eagerly load fonts.
|
||||
*
|
||||
* Most user agents only fetch and load fonts when they are first needed
|
||||
* ("lazy loaded"), which can result in a perceptible delay.
|
||||
*
|
||||
* This function will "eager load" the fonts.
|
||||
*
|
||||
* @param {(FontFace|FontFaceReference)[]} fontsToLoad - List of fonts to load.
|
||||
* @param {boolean} [debug] - If TRUE, log details to the console.
|
||||
*
|
||||
* @returns {Promise}
|
||||
*/
|
||||
async function loadFonts(fontsToLoad, debug = false) {
|
||||
if ((fontsToLoad.size ?? fontsToLoad.length) === 0) {
|
||||
throw new TypeError('Expected at least one font')
|
||||
}
|
||||
|
||||
return await loadFontsWithAPI([...fontsToLoad], debug)
|
||||
}
|
||||
|
||||
/**
|
||||
* Eagerly load a font using `FontFaceSet` API.
|
||||
*
|
||||
* @param {FontFace} font
|
||||
*
|
||||
* @returns {Promise}
|
||||
*/
|
||||
async function loadFontFaceWithAPI(font) {
|
||||
return await (font.status === 'unloaded' ? font.load() : font.loaded).then(
|
||||
(font) => font,
|
||||
(err) => font
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Eagerly load fonts using `FontFaceSet` API.
|
||||
*
|
||||
* @param {FontFaceReference[]} fontsToLoad
|
||||
* @param {boolean} [debug]
|
||||
*
|
||||
* @returns {Promise}
|
||||
*/
|
||||
async function loadFontsWithAPI(fontsToLoad, debug = false) {
|
||||
debug &&
|
||||
console.group(
|
||||
'[loadFonts:API]',
|
||||
fontsToLoad.length,
|
||||
'/',
|
||||
document.fonts.size
|
||||
)
|
||||
|
||||
const fontsToBeLoaded = []
|
||||
|
||||
for (const fontToLoad of fontsToLoad) {
|
||||
if (fontToLoad instanceof FontFace) {
|
||||
if (!document.fonts.has(fontToLoad)) {
|
||||
document.fonts.add(fontToLoad)
|
||||
}
|
||||
|
||||
fontsToBeLoaded.push(loadFontFaceWithAPI(fontToLoad))
|
||||
} else {
|
||||
fontsToBeLoaded.push(
|
||||
...getMany(fontToLoad).map((font) => loadFontFaceWithAPI(font))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
debug && console.groupEnd()
|
||||
|
||||
return await Promise.all(fontsToBeLoaded)
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes quotes from the the string.
|
||||
*
|
||||
* When a `@font-face` is declared, the font family is sometimes
|
||||
* defined in quotes which end up included in the `FontFace` instance.
|
||||
*
|
||||
* @param {string} value
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
function trim(value) {
|
||||
return value.replace(/['"]+/g, '')
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Promise that resolves with the specified fonts
|
||||
* when they are done loading or failed.
|
||||
*
|
||||
* @param {FontFaceReference|string|(FontFaceReference|string)[]} queries
|
||||
*
|
||||
* @returns {Promise}
|
||||
*/
|
||||
async function whenReady(queries) {
|
||||
const fonts = getMany(queries)
|
||||
|
||||
return await Promise.all(fonts.map((font) => font.loaded))
|
||||
}
|
||||
|
||||
export {
|
||||
getAny,
|
||||
getMany,
|
||||
hasAny,
|
||||
isFontLoadingAPIAvailable,
|
||||
loadFonts,
|
||||
whenReady,
|
||||
}
|
||||
138
assets/scripts/utils/grid-helper.js
Normal file
138
assets/scripts/utils/grid-helper.js
Normal file
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* Grid Helper
|
||||
*
|
||||
* Provides a grid based on the design guidelines and is helpful for web integration.
|
||||
*
|
||||
* - `Control + g` to toggle the grid
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} GridHelperReference
|
||||
*
|
||||
* @property {string} [gutterCssVar=GRID_HELPER_GUTTER_CSS_VAR] - CSS variable used to define grid gutters.
|
||||
* @property {string} [marginCssVar=GRID_HELPER_MARGIN_CSS_VAR] - CSS variable used to define grid margins.
|
||||
* @property {string} [rgbaColor=GRID_HELPER_RGBA_COLOR] - RGBA color for the grid appearence.
|
||||
*/
|
||||
|
||||
const GRID_HELPER_GUTTER_CSS_VAR = '--grid-gutter'
|
||||
const GRID_HELPER_MARGIN_CSS_VAR = '--grid-margin'
|
||||
const GRID_HELPER_RGBA_COLOR = 'rgba(255, 0, 0, .1)'
|
||||
|
||||
/**
|
||||
* Create a grid helper
|
||||
*
|
||||
* @param {GridHelperReference}
|
||||
*
|
||||
*/
|
||||
function gridHelper({
|
||||
gutterCssVar = GRID_HELPER_GUTTER_CSS_VAR,
|
||||
marginCssVar = GRID_HELPER_MARGIN_CSS_VAR,
|
||||
rgbaColor = GRID_HELPER_RGBA_COLOR,
|
||||
} = {}) {
|
||||
// Set grid container
|
||||
const $gridContainer = document.createElement('div')
|
||||
document.body.append($gridContainer)
|
||||
|
||||
// Set grid appearence
|
||||
setGridHelperColumns($gridContainer, rgbaColor)
|
||||
setGridHelperStyles($gridContainer, gutterCssVar, marginCssVar)
|
||||
|
||||
// Set grid interactivity
|
||||
setGridEvents($gridContainer, rgbaColor)
|
||||
}
|
||||
|
||||
/**
|
||||
* Set grid container styles
|
||||
*
|
||||
* @param {HTMLElement} $container - DOM Element that contains a list of generated columns
|
||||
* @param {string} gutterCssVar - CSS variable used to define grid gutters.
|
||||
* @param {string} marginCssVar - CSS variable used to define grid margins.
|
||||
*
|
||||
*/
|
||||
function setGridHelperStyles($container, gutterCssVar, marginCssVar) {
|
||||
const elStyles = $container.style
|
||||
elStyles.zIndex = '10000'
|
||||
elStyles.position = 'fixed'
|
||||
elStyles.top = '0'
|
||||
elStyles.left = '0'
|
||||
elStyles.display = 'flex'
|
||||
elStyles.width = '100%'
|
||||
elStyles.height = '100%'
|
||||
elStyles.columnGap = `var(${gutterCssVar}, 0)`
|
||||
elStyles.paddingLeft = `var(${marginCssVar}, 0)`
|
||||
elStyles.paddingRight = `var(${marginCssVar}, 0)`
|
||||
elStyles.pointerEvents = 'none'
|
||||
elStyles.visibility = 'hidden'
|
||||
}
|
||||
|
||||
/**
|
||||
* Set grid columns
|
||||
*
|
||||
* @param {HTMLElement} $container - DOM Element that will contain a list of generated columns
|
||||
* @param {string} rgbaColor - RGBA color to stylize the generated columns
|
||||
*
|
||||
*/
|
||||
function setGridHelperColumns($container, rgbaColor) {
|
||||
// Clear columns
|
||||
$container.innerHTML = ''
|
||||
|
||||
// Loop through columns
|
||||
const columns = Number(
|
||||
window.getComputedStyle($container).getPropertyValue('--grid-columns')
|
||||
)
|
||||
|
||||
let $col
|
||||
for (var i = 0; i < columns; i++) {
|
||||
$col = document.createElement('div')
|
||||
$col.style.flex = '1 1 0'
|
||||
$col.style.backgroundColor = rgbaColor
|
||||
$container.appendChild($col)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set grid events
|
||||
*
|
||||
* Resize to rebuild columns
|
||||
* Keydown/Keyup to toggle the grid display
|
||||
*
|
||||
* @param {HTMLElement} $container - DOM Element that contains a list of generated columns
|
||||
* @param {string} rgbaColor - RGBA color to stylize the generated columns
|
||||
*
|
||||
*/
|
||||
function setGridEvents($container, rgbaColor) {
|
||||
// Handle resize
|
||||
window.addEventListener(
|
||||
'resize',
|
||||
setGridHelperColumns($container, rgbaColor)
|
||||
)
|
||||
|
||||
// Toggle grid
|
||||
let ctrlDown = false
|
||||
let isActive = false
|
||||
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key == 'Control') {
|
||||
ctrlDown = true
|
||||
} else {
|
||||
if (ctrlDown && e.key == 'g') {
|
||||
if (isActive) {
|
||||
$container.style.visibility = 'hidden'
|
||||
} else {
|
||||
$container.style.visibility = 'visible'
|
||||
}
|
||||
|
||||
isActive = !isActive
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
document.addEventListener('keyup', (e) => {
|
||||
if (e.key == 'Control') {
|
||||
ctrlDown = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export { gridHelper }
|
||||
@@ -1,141 +1,129 @@
|
||||
/**
|
||||
* @see https://github.com/ractivejs/ractive/blob/dev/src/utils/html.js
|
||||
* Escape HTML string
|
||||
* @param {string} str - string to escape
|
||||
* @return {string} escaped string
|
||||
*/
|
||||
export function escapeHtml(str) {
|
||||
return str
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>');
|
||||
}
|
||||
|
||||
const escapeHtml = (str) =>
|
||||
str.replace(
|
||||
/[&<>'"]/g,
|
||||
(tag) =>
|
||||
({
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
"'": ''',
|
||||
'"': '"',
|
||||
}[tag])
|
||||
)
|
||||
|
||||
/**
|
||||
* Prepare HTML content that contains mustache characters for use with Ractive
|
||||
* @param {string} str
|
||||
* @return {string}
|
||||
* Unescape HTML string
|
||||
* @param {string} str - string to unescape
|
||||
* @return {string} unescaped string
|
||||
*/
|
||||
export function unescapeHtml(str) {
|
||||
return str
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/&/g, '&');
|
||||
}
|
||||
|
||||
const unescapeHtml = (str) =>
|
||||
str
|
||||
.replace('&', '&')
|
||||
.replace('<', '<')
|
||||
.replace('>', '>')
|
||||
.replace(''', "'")
|
||||
.replace('"', '"')
|
||||
|
||||
/**
|
||||
* Get element data attributes
|
||||
* @param {DOMElement} node
|
||||
* @return {Array} data
|
||||
* @param {HTMLElement} node - node element
|
||||
* @return {array} node data
|
||||
*/
|
||||
export function getNodeData(node) {
|
||||
|
||||
const getNodeData = (node) => {
|
||||
// All attributes
|
||||
const attributes = node.attributes;
|
||||
const attributes = node.attributes
|
||||
|
||||
// Regex Pattern
|
||||
const pattern = /^data\-(.+)$/;
|
||||
const pattern = /^data\-(.+)$/
|
||||
|
||||
// Output
|
||||
const data = {};
|
||||
const data = {}
|
||||
|
||||
for (let i in attributes) {
|
||||
if (!attributes[i]) {
|
||||
continue;
|
||||
continue
|
||||
}
|
||||
|
||||
// Attributes name (ex: data-module)
|
||||
let name = attributes[i].name;
|
||||
let name = attributes[i].name
|
||||
|
||||
// This happens.
|
||||
if (!name) {
|
||||
continue;
|
||||
continue
|
||||
}
|
||||
|
||||
let match = name.match(pattern);
|
||||
let match = name.match(pattern)
|
||||
if (!match) {
|
||||
continue;
|
||||
continue
|
||||
}
|
||||
|
||||
// If this throws an error, you have some
|
||||
// serious problems in your HTML.
|
||||
data[match[1]] = getData(node.getAttribute(name));
|
||||
data[match[1]] = getData(node.getAttribute(name))
|
||||
}
|
||||
|
||||
return data;
|
||||
return data
|
||||
}
|
||||
|
||||
const rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/;
|
||||
|
||||
/**
|
||||
* Parse value to data type.
|
||||
*
|
||||
* @link https://github.com/jquery/jquery/blob/3.1.1/src/data.js
|
||||
* @param {string} data - A value to convert.
|
||||
* @return {mixed} Returns the value in its natural data type.
|
||||
* @param {string} data - value to convert
|
||||
* @return {mixed} value in its natural data type
|
||||
*/
|
||||
export function getData(data) {
|
||||
|
||||
const rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/
|
||||
const getData = (data) => {
|
||||
if (data === 'true') {
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
|
||||
if (data === 'false') {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
if (data === 'null') {
|
||||
return null;
|
||||
return null
|
||||
}
|
||||
|
||||
// Only convert to a number if it doesn't change the string
|
||||
if (data === +data+'') {
|
||||
return +data;
|
||||
if (data === +data + '') {
|
||||
return +data
|
||||
}
|
||||
|
||||
if (rbrace.test( data )) {
|
||||
return JSON.parse( data );
|
||||
if (rbrace.test(data)) {
|
||||
return JSON.parse(data)
|
||||
}
|
||||
|
||||
return data;
|
||||
return data
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array containing all the parent nodes of the given node
|
||||
* @param {object} node
|
||||
* @return {array} parent nodes
|
||||
* @param {HTMLElement} $el - DOM Element
|
||||
* @return {array} parent nodes
|
||||
*/
|
||||
export function getParents(elem) {
|
||||
|
||||
const getParents = ($el) => {
|
||||
// Set up a parent array
|
||||
let parents = [];
|
||||
let parents = []
|
||||
|
||||
// Push each parent element to the array
|
||||
for ( ; elem && elem !== document; elem = elem.parentNode ) {
|
||||
parents.push(elem);
|
||||
for (; $el && $el !== document; $el = $el.parentNode) {
|
||||
parents.push($el)
|
||||
}
|
||||
|
||||
// Return our parent array
|
||||
return parents;
|
||||
return parents
|
||||
}
|
||||
|
||||
// https://gomakethings.com/how-to-get-the-closest-parent-element-with-a-matching-selector-using-vanilla-javascript/
|
||||
export function queryClosestParent(elem, selector) {
|
||||
|
||||
// Element.matches() polyfill
|
||||
if (!Element.prototype.matches) {
|
||||
Element.prototype.matches =
|
||||
Element.prototype.matchesSelector ||
|
||||
Element.prototype.mozMatchesSelector ||
|
||||
Element.prototype.msMatchesSelector ||
|
||||
Element.prototype.oMatchesSelector ||
|
||||
Element.prototype.webkitMatchesSelector ||
|
||||
function(s) {
|
||||
var matches = (this.document || this.ownerDocument).querySelectorAll(s),
|
||||
i = matches.length;
|
||||
while (--i >= 0 && matches.item(i) !== this) {}
|
||||
return i > -1;
|
||||
};
|
||||
}
|
||||
|
||||
// Get the closest matching element
|
||||
for ( ; elem && elem !== document; elem = elem.parentNode ) {
|
||||
if ( elem.matches( selector ) ) return elem;
|
||||
}
|
||||
return null;
|
||||
|
||||
};
|
||||
export { escapeHtml, unescapeHtml, getNodeData, getData, getParents }
|
||||
|
||||
@@ -1,81 +1,97 @@
|
||||
const LAZY_LOADED_IMAGES = []
|
||||
/**
|
||||
* Get an image meta data
|
||||
*
|
||||
* @param {HTMLImageElement} $img - The image element.
|
||||
* @return {object} The given image meta data
|
||||
*/
|
||||
|
||||
export function loadImage(url, options = {}) {
|
||||
const getImageMetadata = ($img) => ({
|
||||
url: $img.src,
|
||||
width: $img.naturalWidth,
|
||||
height: $img.naturalHeight,
|
||||
ratio: $img.naturalWidth / $img.naturalHeight,
|
||||
})
|
||||
|
||||
/**
|
||||
* Load the given image.
|
||||
*
|
||||
* @param {string} url - The URI to lazy load into $el.
|
||||
* @param {object} options - An object of options
|
||||
* @return {void}
|
||||
*/
|
||||
|
||||
const loadImage = (url, options = {}) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const $img = new Image();
|
||||
const $img = new Image()
|
||||
|
||||
if (options.crossOrigin) {
|
||||
$img.crossOrigin = options.crossOrigin;
|
||||
$img.crossOrigin = options.crossOrigin
|
||||
}
|
||||
|
||||
const loadCallback = () => {
|
||||
resolve({
|
||||
element: $img,
|
||||
...getImageMetadata($img),
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
if($img.decode) {
|
||||
if ($img.decode) {
|
||||
$img.src = url
|
||||
$img.decode().then(loadCallback).catch(e => {
|
||||
reject(e)
|
||||
})
|
||||
$img.decode()
|
||||
.then(loadCallback)
|
||||
.catch((e) => {
|
||||
reject(e)
|
||||
})
|
||||
} else {
|
||||
$img.onload = loadCallback
|
||||
$img.onerror = (e) => {
|
||||
reject(e);
|
||||
};
|
||||
reject(e)
|
||||
}
|
||||
$img.src = url
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function getImageMetadata($img) {
|
||||
return {
|
||||
url: $img.src,
|
||||
width: $img.naturalWidth,
|
||||
height: $img.naturalHeight,
|
||||
ratio: $img.naturalWidth / $img.naturalHeight,
|
||||
};
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazy load the given image.
|
||||
*
|
||||
* @param {HTMLImageElement} $el - The image element.
|
||||
* @param {?string} url - The URI to lazy load into $el.
|
||||
* @param {HTMLImageElement} $el - The image element.
|
||||
* @param {?string} url - The URI to lazy load into $el.
|
||||
* If falsey, the value of the `data-src` attribute on $el will be used as the URI.
|
||||
* @param {?function} callback - A function to call when the image is loaded.
|
||||
* @param {?function} callback - A function to call when the image is loaded.
|
||||
* @return {void}
|
||||
*/
|
||||
export async function lazyLoadImage($el, url, callback) {
|
||||
|
||||
const LAZY_LOADED_IMAGES = []
|
||||
const lazyLoadImage = async ($el, url, callback) => {
|
||||
let src = url ? url : $el.dataset.src
|
||||
|
||||
let loadedImage = LAZY_LOADED_IMAGES.find(image => image.url === src)
|
||||
let loadedImage = LAZY_LOADED_IMAGES.find((image) => image.url === src)
|
||||
|
||||
if (!loadedImage) {
|
||||
loadedImage = await loadImage(src)
|
||||
|
||||
if (!loadedImage.url) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
LAZY_LOADED_IMAGES.push(loadedImage)
|
||||
}
|
||||
|
||||
if($el.src === src) {
|
||||
if ($el.src === src) {
|
||||
return
|
||||
}
|
||||
|
||||
if ($el.tagName === 'IMG') {
|
||||
$el.src = loadedImage.url;
|
||||
$el.src = loadedImage.url
|
||||
} else {
|
||||
$el.style.backgroundImage = `url(${loadedImage.url})`;
|
||||
$el.style.backgroundImage = `url(${loadedImage.url})`
|
||||
}
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
let lazyParent = $el.closest('.c-lazy');
|
||||
let lazyParent = $el.closest('.c-lazy')
|
||||
|
||||
if(lazyParent) {
|
||||
if (lazyParent) {
|
||||
lazyParent.classList.add('-lazy-loaded')
|
||||
lazyParent.style.backgroundImage = ''
|
||||
}
|
||||
@@ -85,3 +101,5 @@ export async function lazyLoadImage($el, url, callback) {
|
||||
callback?.()
|
||||
})
|
||||
}
|
||||
|
||||
export { getImageMetadata, loadImage, lazyLoadImage }
|
||||
|
||||
@@ -1,37 +1,21 @@
|
||||
const toString = Object.prototype.toString;
|
||||
const arrayLikePattern = /^\[object (?:Array|FileList)\]$/;
|
||||
/**
|
||||
* Determines if the argument is object-like.
|
||||
*
|
||||
* A value is object-like if it's not `null` and has a `typeof` result of "object".
|
||||
*
|
||||
* @param {*} x - The value to be checked.
|
||||
* @return {boolean}
|
||||
*/
|
||||
|
||||
// thanks, http://perfectionkills.com/instanceof-considered-harmful-or-how-to-write-a-robust-isarray/
|
||||
export function isArray ( thing ) {
|
||||
return toString.call( thing ) === '[object Array]';
|
||||
}
|
||||
const isObject = (x) => x && typeof x === 'object'
|
||||
|
||||
export function isArrayLike ( obj ) {
|
||||
return arrayLikePattern.test( toString.call( obj ) );
|
||||
}
|
||||
/**
|
||||
* Determines if the argument is a function.
|
||||
*
|
||||
* @param {*} x - The value to be checked.
|
||||
* @return {boolean}
|
||||
*/
|
||||
|
||||
export function isEqual ( a, b ) {
|
||||
if ( a === null && b === null ) {
|
||||
return true;
|
||||
}
|
||||
const isFunction = (x) => typeof x === 'function'
|
||||
|
||||
if ( typeof a === 'object' || typeof b === 'object' ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return a === b;
|
||||
}
|
||||
|
||||
// http://stackoverflow.com/questions/18082/validate-numbers-in-javascript-isnumeric
|
||||
export function isNumeric ( thing ) {
|
||||
return !isNaN( parseFloat( thing ) ) && isFinite( thing );
|
||||
}
|
||||
|
||||
export function isObject ( thing ) {
|
||||
return ( thing && toString.call( thing ) === '[object Object]' );
|
||||
}
|
||||
|
||||
export function isFunction( thing ) {
|
||||
const getType = {};
|
||||
return thing && getType.toString.call(thing) === '[object Function]';
|
||||
}
|
||||
export { isObject, isFunction }
|
||||
|
||||
@@ -1,3 +1,45 @@
|
||||
export function lerp(start, end, amt){
|
||||
return (1 - amt) * start + amt * end
|
||||
/**
|
||||
* Clamp value
|
||||
* @param {number} min - start value
|
||||
* @param {number} max - end value
|
||||
* @param {number} a - alpha value
|
||||
* @return {number} clamped value
|
||||
*/
|
||||
|
||||
const clamp = (min = 0, max = 1, a) => Math.min(max, Math.max(min, a))
|
||||
|
||||
/**
|
||||
* Calculate lerp
|
||||
* @param {number} x - start value
|
||||
* @param {number} y - end value
|
||||
* @param {number} a - alpha value
|
||||
* @return {number} lerp value
|
||||
*/
|
||||
|
||||
const lerp = (x, y, a) => x * (1 - a) + y * a
|
||||
|
||||
/**
|
||||
* Calculate inverted lerp
|
||||
* @param {number} x - start value
|
||||
* @param {number} y - end value
|
||||
* @param {number} a - alpha value
|
||||
* @return {number} inverted lerp value
|
||||
*/
|
||||
|
||||
const invlerp = (x, y, a) => clamp((v - x) / (a - x))
|
||||
|
||||
/**
|
||||
* Round number to the specified precision.
|
||||
*
|
||||
* This function is necessary because `Number.prototype.toPrecision()`
|
||||
* and `Number.prototype.toFixed()`
|
||||
*
|
||||
* @param {number} number - The floating point number to round.
|
||||
* @param {number} [precision] - The number of digits to appear after the decimal point.
|
||||
* @return {number} The rounded number.
|
||||
*/
|
||||
const roundNumber = (number, precision = 2) => {
|
||||
return Number.parseFloat(number.toPrecision(precision))
|
||||
}
|
||||
|
||||
export { clamp, lerp, invlerp, roundNumber }
|
||||
|
||||
73
assets/scripts/utils/tickers.js
Normal file
73
assets/scripts/utils/tickers.js
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Creates a debounced function.
|
||||
*
|
||||
* A debounced function delays invoking `callback` until after
|
||||
* `delay` milliseconds have elapsed since the last time the
|
||||
* debounced function was invoked.
|
||||
*
|
||||
* Useful for behaviour that should only happen _before_ or
|
||||
* _after_ an event has stopped occurring.
|
||||
*
|
||||
* @template {function} T
|
||||
*
|
||||
* @param {T} callback - The function to debounce.
|
||||
* @param {number} delay - The number of milliseconds to wait.
|
||||
* @param {boolean} [immediate] -
|
||||
* If `true`, `callback` is invoked before `delay`.
|
||||
* If `false`, `callback` is invoked after `delay`.
|
||||
* @return {function<T>} The new debounced function.
|
||||
*/
|
||||
|
||||
const debounce = (callback, delay, immediate = false) => {
|
||||
let timeout = null
|
||||
|
||||
return (...args) => {
|
||||
clearTimeout(timeout)
|
||||
|
||||
const later = () => {
|
||||
timeout = null
|
||||
if (!immediate) {
|
||||
callback(...args)
|
||||
}
|
||||
}
|
||||
|
||||
if (immediate && !timeout) {
|
||||
callback(...args)
|
||||
}
|
||||
|
||||
timeout = setTimeout(later, delay)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a throttled function.
|
||||
*
|
||||
* A throttled function invokes `callback` at most once per every
|
||||
* `delay` milliseconds.
|
||||
*
|
||||
* Useful for rate-limiting an event that occurs in quick succession.
|
||||
*
|
||||
* @template {function} T
|
||||
*
|
||||
* @param {T} callback - The function to throttle.
|
||||
* @param {number} delay - The number of milliseconds to wait.
|
||||
* @return {function<T>} The new throttled function.
|
||||
*/
|
||||
|
||||
const throttle = (callback, delay) => {
|
||||
let timeout = false
|
||||
|
||||
return (...args) => {
|
||||
if (!timeout) {
|
||||
timeout = true
|
||||
|
||||
callback(...args)
|
||||
|
||||
setTimeout(() => {
|
||||
timeout = false
|
||||
}, delay)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { debounce, throttle }
|
||||
@@ -1,21 +1,35 @@
|
||||
export function transform(el, transformValue){
|
||||
el.style.webkitTransform = transformValue;
|
||||
el.style.msTransform = transformValue;
|
||||
el.style.transform = transformValue;
|
||||
/**
|
||||
* Get translate function
|
||||
* @param {HTMLElement} $el - DOM Element
|
||||
* @return {number|object} translate value
|
||||
*/
|
||||
|
||||
const getTranslate = ($el) => {
|
||||
if (!window.getComputedStyle) {
|
||||
return
|
||||
}
|
||||
|
||||
let translate
|
||||
const style = getComputedStyle($el)
|
||||
const transform =
|
||||
style.msTransform ||
|
||||
style.webkitTransform ||
|
||||
style.MozTransform ||
|
||||
style.OTransform ||
|
||||
style.transform
|
||||
|
||||
const matrix3D = transform.match(/^matrix3d\((.+)\)$/)
|
||||
if (matrix3D) {
|
||||
translate = parseFloat(matrix3D[1].split(', ')[13])
|
||||
} else {
|
||||
const matrix = transform.match(/^matrix\((.+)\)$/)
|
||||
translate = {
|
||||
x: matrix ? parseFloat(matrix[1].split(', ')[4]) : 0,
|
||||
y: matrix ? parseFloat(matrix[1].split(', ')[5]) : 0,
|
||||
}
|
||||
}
|
||||
|
||||
return translate
|
||||
}
|
||||
|
||||
export function getTranslate(el){
|
||||
const translate = {}
|
||||
if(!window.getComputedStyle) return;
|
||||
|
||||
const style = getComputedStyle(el);
|
||||
const transform = style.transform || style.webkitTransform || style.mozTransform;
|
||||
|
||||
let mat = transform.match(/^matrix3d\((.+)\)$/);
|
||||
if(mat) return parseFloat(mat[1].split(', ')[13]);
|
||||
mat = transform.match(/^matrix\((.+)\)$/);
|
||||
translate.x = mat ? parseFloat(mat[1].split(', ')[4]) : 0;
|
||||
translate.y = mat ? parseFloat(mat[1].split(', ')[5]) : 0;
|
||||
|
||||
return translate;
|
||||
}
|
||||
export { transform, getTranslate }
|
||||
|
||||
@@ -1,129 +1,126 @@
|
||||
import { isFunction } from './is';
|
||||
import { arrayContains, findByKeyValue, removeFromArray } from './array';
|
||||
import { $document, $window, $html, $body } from './environment';
|
||||
|
||||
const CALLBACKS = {
|
||||
hidden: [],
|
||||
visible: []
|
||||
};
|
||||
|
||||
const ACTIONS = [
|
||||
'addCallback',
|
||||
'removeCallback'
|
||||
];
|
||||
|
||||
const STATES = [
|
||||
'visible',
|
||||
'hidden'
|
||||
];
|
||||
|
||||
const PREFIX = 'v-';
|
||||
|
||||
let UUID = 0;
|
||||
|
||||
// Main event
|
||||
$document.on('visibilitychange', function(event) {
|
||||
if (document.hidden) {
|
||||
onDocumentChange('hidden');
|
||||
} else {
|
||||
onDocumentChange('visible');
|
||||
/**
|
||||
* The `PageVisibility` interface provides support for dispatching
|
||||
* a custom event derived from the value of {@see document.visibilityState}
|
||||
* when the "visibilitychange" event is fired.
|
||||
*
|
||||
* The custom events are:
|
||||
*
|
||||
* - "visibilityhidden" representing the "hidden" visibility state.
|
||||
* - "visibilityvisible" representing the "visibile" visibility state.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```js
|
||||
* import pageVisibility from './utils/visibility.js';
|
||||
*
|
||||
* pageVisibility.enableCustomEvents();
|
||||
*
|
||||
* document.addEventListener('visibilityhidden', () => videoElement.pause());
|
||||
* ```
|
||||
*
|
||||
* The dispatched event object is the same from "visibilitychange"
|
||||
* and renamed according to the visibility state.
|
||||
*
|
||||
* The `PageVisibility` interface does not manage the attachment/detachment
|
||||
* of event listeners on the custom event types.
|
||||
*
|
||||
* Further reading:
|
||||
*
|
||||
* - {@link https://www.w3.org/TR/page-visibility/ W3 Specification}
|
||||
* - {@link https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API MDN Web Docs}
|
||||
*/
|
||||
export default new (class PageVisibility {
|
||||
/**
|
||||
* Checks if the "visibilitychange" event listener has been registered.
|
||||
*
|
||||
* @return {boolean} Returns `false` if the event listener is not registered,
|
||||
* otherwise returns `true`.
|
||||
*/
|
||||
get isEnabled() {
|
||||
return isVisibilityChangeObserved
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Removes the "visibilitychange" event listener.
|
||||
*
|
||||
* @return {boolean} Returns `false` if the event listener was already unregistered,
|
||||
* otherwise returns `true`.
|
||||
*/
|
||||
disableCustomEvents() {
|
||||
if (isVisibilityChangeObserved) {
|
||||
isVisibilityChangeObserved = false
|
||||
document.removeEventListener(
|
||||
'visibilitychange',
|
||||
handleCustomVisibilityChange
|
||||
)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the "visibilitychange" event listener.
|
||||
*
|
||||
* @return {boolean} Returns `false` if the event listener was already registered,
|
||||
* otherwise returns `true`.
|
||||
*/
|
||||
enableCustomEvents() {
|
||||
if (!isVisibilityChangeObserved) {
|
||||
isVisibilityChangeObserved = true
|
||||
document.addEventListener(
|
||||
'visibilitychange',
|
||||
handleCustomVisibilityChange
|
||||
)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
})()
|
||||
|
||||
/**
|
||||
* Add a callback
|
||||
* @param {string} state
|
||||
* @param {function} callback
|
||||
* @return {string} ident
|
||||
* Tracks whether custom visibility event types
|
||||
* are available (`true`) or not (`false`).
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
function addCallback (state, options) {
|
||||
let callback = options.callback || '';
|
||||
let isVisibilityChangeObserved = false
|
||||
|
||||
if (!isFunction(callback)) {
|
||||
console.warn('Callback is not a function');
|
||||
return false;
|
||||
}
|
||||
|
||||
let ident = PREFIX + UUID++;
|
||||
|
||||
CALLBACKS[state].push({
|
||||
ident: ident,
|
||||
callback: callback
|
||||
});
|
||||
|
||||
return ident;
|
||||
/**
|
||||
* Dispatches a custom visibility event at the document derived
|
||||
* from the value of {@see document.visibilityState}.
|
||||
*
|
||||
* @listens document#visibilitychange
|
||||
*
|
||||
* @fires PageVisibility#visibilityhidden
|
||||
* @fires PageVisibility#visibilityvisible
|
||||
*
|
||||
* @param {Event} event
|
||||
* @return {void}
|
||||
*/
|
||||
function handleCustomVisibilityChange(event) {
|
||||
document.dispatchEvent(
|
||||
new CustomEvent(`visibility${document.visibilityState}`, {
|
||||
detail: {
|
||||
cause: event,
|
||||
},
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a callback
|
||||
* @param {string} state Visible or hidden
|
||||
* @param {string} ident Unique identifier
|
||||
* @return {boolean} If operation was a success
|
||||
* The "visibilityhidden" eveent is fired at the document when the contents
|
||||
* of its tab have become hidden.
|
||||
*
|
||||
* @event PageVisibility#visibilityhidden
|
||||
* @type {Event}
|
||||
*/
|
||||
function removeCallback (state, options) {
|
||||
let ident = options.ident || '';
|
||||
|
||||
if (typeof(ident) === 'undefined' || ident === '') {
|
||||
console.warn('Need ident to remove callback');
|
||||
return false;
|
||||
}
|
||||
|
||||
let index = findByKeyValue(CALLBACKS[state], 'ident', ident)[0];
|
||||
|
||||
// console.log(ident)
|
||||
// console.log(CALLBACKS[state])
|
||||
|
||||
if (typeof(index) !== 'undefined') {
|
||||
removeFromArray(CALLBACKS[state], index);
|
||||
return true;
|
||||
} else {
|
||||
console.warn('Callback could not be found');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When document state changes, trigger callbacks
|
||||
* @param {string} state Visible or hidden
|
||||
* The "visibilityvisible" eveent is fired at the document when the contents
|
||||
* of its tab have become visible.
|
||||
*
|
||||
* @event PageVisibility#visibilityvisible
|
||||
* @type {Event}
|
||||
*/
|
||||
function onDocumentChange (state) {
|
||||
let callbackArray = CALLBACKS[state];
|
||||
let i = 0;
|
||||
let len = callbackArray.length;
|
||||
|
||||
for (; i < len; i++) {
|
||||
callbackArray[i].callback();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Public facing API for adding and removing callbacks
|
||||
* @param {object} options Options
|
||||
* @return {boolean|integer} Unique identifier for the callback or boolean indicating success or failure
|
||||
*/
|
||||
function visibilityApi (options) {
|
||||
let action = options.action || '';
|
||||
let state = options.state || '';
|
||||
let ret;
|
||||
|
||||
// Type and value checking
|
||||
if (!arrayContains(ACTIONS, action)) {
|
||||
console.warn('Action does not exist');
|
||||
return false;
|
||||
}
|
||||
if (!arrayContains(STATES, state)) {
|
||||
console.warn('State does not exist');
|
||||
return false;
|
||||
}
|
||||
|
||||
// @todo Magic call function pls
|
||||
if (action === 'addCallback') {
|
||||
ret = addCallback(state, options);
|
||||
} else if (action === 'removeCallback') {
|
||||
ret = removeCallback(state, options);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
export { visibilityApi };
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
// ==========================================================================
|
||||
// Components / Buttons
|
||||
// ==========================================================================
|
||||
|
||||
.c-button {
|
||||
padding: rem(15px) rem(20px);
|
||||
background-color: lightgray;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// ==========================================================================
|
||||
// Form
|
||||
// Components / Form
|
||||
// ==========================================================================
|
||||
.c-form {
|
||||
|
||||
.c-form {
|
||||
}
|
||||
|
||||
.c-form_item {
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
// Label
|
||||
// ==========================================================================
|
||||
|
||||
.c-form_label {
|
||||
display: block;
|
||||
margin-bottom: rem(10px);
|
||||
@@ -19,12 +20,13 @@
|
||||
|
||||
// Input
|
||||
// ==========================================================================
|
||||
|
||||
$input-icon-color: 424242; // No #
|
||||
|
||||
.c-form_input {
|
||||
padding: rem(10px);
|
||||
border: 1px solid lightgray;
|
||||
background-color: white;
|
||||
background-color: $color-lightest;
|
||||
|
||||
&:hover {
|
||||
border-color: darkgray;
|
||||
@@ -41,6 +43,7 @@ $input-icon-color: 424242; // No #
|
||||
|
||||
// Checkbox
|
||||
// ==========================================================================
|
||||
|
||||
$checkbox: rem(18px);
|
||||
$checkbox-icon-color: $input-icon-color;
|
||||
|
||||
@@ -54,27 +57,28 @@ $checkbox-icon-color: $input-icon-color;
|
||||
padding-left: ($checkbox + rem(10px));
|
||||
cursor: pointer;
|
||||
|
||||
&::before, &::after {
|
||||
&::before,
|
||||
&::after {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
display: inline-block;
|
||||
margin-top: (-$checkbox / 2);
|
||||
margin-top: math.div(-$checkbox, 2);
|
||||
padding: 0;
|
||||
width: $checkbox;
|
||||
height: $checkbox;
|
||||
content: "";
|
||||
content: '';
|
||||
}
|
||||
|
||||
&::before {
|
||||
background-color: $white;
|
||||
background-color: $color-lightest;
|
||||
border: 1px solid lightgray;
|
||||
}
|
||||
|
||||
&::after {
|
||||
border-color: transparent;
|
||||
background-color: transparent;
|
||||
background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20x%3D%220%22%20y%3D%220%22%20width%3D%2213%22%20height%3D%2210.5%22%20viewBox%3D%220%200%2013%2010.5%22%20enable-background%3D%22new%200%200%2013%2010.5%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20fill%3D%22%23#{$checkbox-icon-color}%22%20d%3D%22M4.8%205.8L2.4%203.3%200%205.7l4.8%204.8L13%202.4c0%200-2.4-2.4-2.4-2.4L4.8%205.8z%22%2F%3E%3C%2Fsvg%3E");
|
||||
background-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20x%3D%220%22%20y%3D%220%22%20width%3D%2213%22%20height%3D%2210.5%22%20viewBox%3D%220%200%2013%2010.5%22%20enable-background%3D%22new%200%200%2013%2010.5%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20fill%3D%22%23#{$checkbox-icon-color}%22%20d%3D%22M4.8%205.8L2.4%203.3%200%205.7l4.8%204.8L13%202.4c0%200-2.4-2.4-2.4-2.4L4.8%205.8z%22%2F%3E%3C%2Fsvg%3E');
|
||||
background-position: center;
|
||||
background-size: rem(12px);
|
||||
background-repeat: no-repeat;
|
||||
@@ -108,17 +112,19 @@ $checkbox-icon-color: $input-icon-color;
|
||||
|
||||
// Radio
|
||||
// ==========================================================================
|
||||
|
||||
$radio-icon-color: $input-icon-color;
|
||||
|
||||
.c-form_radioLabel {
|
||||
@extend .c-form_checkboxLabel;
|
||||
|
||||
&::before, &::after {
|
||||
&::before,
|
||||
&::after {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
&::after {
|
||||
background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20x%3D%220%22%20y%3D%220%22%20width%3D%2213%22%20height%3D%2213%22%20viewBox%3D%220%200%2013%2013%22%20enable-background%3D%22new%200%200%2013%2013%22%20xml%3Aspace%3D%22preserve%22%3E%3Ccircle%20fill%3D%22%23#{$radio-icon-color}%22%20cx%3D%226.5%22%20cy%3D%226.5%22%20r%3D%226.5%22%2F%3E%3C%2Fsvg%3E");
|
||||
background-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20x%3D%220%22%20y%3D%220%22%20width%3D%2213%22%20height%3D%2213%22%20viewBox%3D%220%200%2013%2013%22%20enable-background%3D%22new%200%200%2013%2013%22%20xml%3Aspace%3D%22preserve%22%3E%3Ccircle%20fill%3D%22%23#{$radio-icon-color}%22%20cx%3D%226.5%22%20cy%3D%226.5%22%20r%3D%226.5%22%2F%3E%3C%2Fsvg%3E');
|
||||
background-size: rem(6px);
|
||||
}
|
||||
}
|
||||
@@ -129,6 +135,7 @@ $radio-icon-color: $input-icon-color;
|
||||
|
||||
// Select
|
||||
// =============================================================================
|
||||
|
||||
$select-icon: rem(40px);
|
||||
$select-icon-color: $input-icon-color;
|
||||
|
||||
@@ -143,11 +150,11 @@ $select-icon-color: $input-icon-color;
|
||||
bottom: 0;
|
||||
z-index: 2;
|
||||
width: $select-icon;
|
||||
background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20x%3D%220%22%20y%3D%220%22%20width%3D%2213%22%20height%3D%2211.3%22%20viewBox%3D%220%200%2013%2011.3%22%20enable-background%3D%22new%200%200%2013%2011.3%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20fill%3D%22%23#{$select-icon-color}%22%20points%3D%226.5%2011.3%203.3%205.6%200%200%206.5%200%2013%200%209.8%205.6%20%22%2F%3E%3C%2Fsvg%3E");
|
||||
background-image: url('data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20x%3D%220%22%20y%3D%220%22%20width%3D%2213%22%20height%3D%2211.3%22%20viewBox%3D%220%200%2013%2011.3%22%20enable-background%3D%22new%200%200%2013%2011.3%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20fill%3D%22%23#{$select-icon-color}%22%20points%3D%226.5%2011.3%203.3%205.6%200%200%206.5%200%2013%200%209.8%205.6%20%22%2F%3E%3C%2Fsvg%3E');
|
||||
background-position: center;
|
||||
background-size: rem(8px);
|
||||
background-repeat: no-repeat;
|
||||
content: "";
|
||||
content: '';
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
@@ -163,6 +170,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;
|
||||
@@ -12,7 +16,9 @@
|
||||
transform: scaleX(1.45);
|
||||
}
|
||||
|
||||
&:hover, .has-scroll-scrolling &, .has-scroll-dragging & {
|
||||
&:hover,
|
||||
.has-scroll-scrolling &,
|
||||
.has-scroll-dragging & {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
@@ -21,7 +27,7 @@
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
background-color: black;
|
||||
background-color: $color-darkest;
|
||||
opacity: 0.5;
|
||||
width: 7px;
|
||||
border-radius: 10px;
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
$assets-path: "assets/";
|
||||
// ==========================================================================
|
||||
// Critical CSS
|
||||
// ==========================================================================
|
||||
|
||||
$assets-path: 'assets/';
|
||||
|
||||
@@ -1,19 +1,36 @@
|
||||
// ==========================================================================
|
||||
// Base / Page
|
||||
// Elements / Document
|
||||
// ==========================================================================
|
||||
|
||||
:root {
|
||||
// Grid
|
||||
--grid-columns: 4;
|
||||
--grid-gutter: #{rem(10px)};
|
||||
--grid-gutter-half: calc(0.5 * var(--grid-gutter));
|
||||
--grid-margin: 0px;
|
||||
|
||||
@media (min-width: $from-small) {
|
||||
--grid-columns: 12;
|
||||
--grid-gutter: #{rem(16px)};
|
||||
--grid-margin: #{rem(20px)};
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// 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] */
|
||||
color: $color;
|
||||
font-family: $font-family;
|
||||
line-height: $line-height; /* [1] */
|
||||
min-height: 100%; // [2]
|
||||
line-height: $line-height; // [3]
|
||||
font-family: ff('sans');
|
||||
color: $font-color;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
|
||||
@@ -30,7 +47,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) {
|
||||
@@ -51,6 +68,11 @@ html {
|
||||
|
||||
&.has-scroll-smooth {
|
||||
overflow: hidden;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&.has-scroll-dragging {
|
||||
@@ -71,9 +93,9 @@ body {
|
||||
}
|
||||
|
||||
a {
|
||||
color: $link-color;
|
||||
color: $color-link;
|
||||
|
||||
@include u-hocus {
|
||||
color: $link-hover-color;
|
||||
color: $color-link-hover;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -34,7 +33,7 @@ i {
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: $bold;
|
||||
font-weight: $font-weight-bold;
|
||||
}
|
||||
|
||||
a {
|
||||
@@ -58,15 +57,26 @@ figure {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Single taps should be dispatched immediately on clickable elements
|
||||
*/
|
||||
a, area, button, input, label, select, textarea, [tabindex] {
|
||||
-ms-touch-action: manipulation; /* [1] */
|
||||
// 1. Single taps should be dispatched immediately on clickable elements
|
||||
|
||||
a,
|
||||
area,
|
||||
button,
|
||||
input,
|
||||
label,
|
||||
select,
|
||||
textarea,
|
||||
[tabindex] {
|
||||
-ms-touch-action: manipulation; // [1]
|
||||
touch-action: manipulation;
|
||||
}
|
||||
|
||||
@@ -85,5 +95,5 @@ hr {
|
||||
padding: 0;
|
||||
height: 1px;
|
||||
border: 0;
|
||||
border-top: 1px solid #CCCCCC;
|
||||
border-top: 1px solid #cccccc;
|
||||
}
|
||||
|
||||
@@ -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]
|
||||
}
|
||||
|
||||
@@ -1,43 +1,50 @@
|
||||
// ==========================================================================
|
||||
// Main
|
||||
// ==========================================================================
|
||||
@use 'sass:math';
|
||||
|
||||
// Settings
|
||||
// ==========================================================================
|
||||
@import "settings/config.eases";
|
||||
@import "settings/config.colors";
|
||||
@import "settings/config";
|
||||
|
||||
@import 'settings/config.eases';
|
||||
@import 'settings/config.colors';
|
||||
@import 'settings/config';
|
||||
|
||||
// ==========================================================================
|
||||
// Tools
|
||||
// ==========================================================================
|
||||
@import "tools/functions";
|
||||
@import "tools/mixins";
|
||||
@import "tools/fonts";
|
||||
@import "tools/layout";
|
||||
@import "tools/widths";
|
||||
|
||||
@import 'tools/maths';
|
||||
@import 'tools/functions';
|
||||
@import 'tools/mixins';
|
||||
@import 'tools/fonts';
|
||||
// @import "tools/layout";
|
||||
// @import "tools/widths";
|
||||
// @import "tools/family";
|
||||
|
||||
// Generic
|
||||
// ==========================================================================
|
||||
@import "node_modules/normalize.css/normalize";
|
||||
@import "generic/generic";
|
||||
@import "generic/media";
|
||||
@import "generic/form";
|
||||
@import "generic/button";
|
||||
|
||||
@import 'node_modules/normalize.css/normalize';
|
||||
@import 'generic/generic';
|
||||
@import 'generic/media';
|
||||
@import 'generic/form';
|
||||
@import 'generic/button';
|
||||
|
||||
// Elements
|
||||
// ==========================================================================
|
||||
@import "elements/fonts";
|
||||
@import "elements/page";
|
||||
|
||||
@import 'elements/document';
|
||||
|
||||
// Objects
|
||||
// ==========================================================================
|
||||
@import "objects/scroll";
|
||||
@import "objects/container";
|
||||
@import "objects/ratio";
|
||||
@import "objects/layout";
|
||||
// @import "objects/crop";
|
||||
|
||||
@import 'objects/scroll';
|
||||
@import 'objects/container';
|
||||
@import 'objects/ratio';
|
||||
@import 'objects/icons';
|
||||
@import 'objects/grid';
|
||||
// @import "objects/layout";
|
||||
// @import "objects/table";
|
||||
|
||||
// Vendors
|
||||
@@ -46,19 +53,18 @@
|
||||
|
||||
// Components
|
||||
// ==========================================================================
|
||||
@import "components/scrollbar";
|
||||
@import "components/heading";
|
||||
@import "components/button";
|
||||
@import "components/form";
|
||||
|
||||
// Templates
|
||||
// ==========================================================================
|
||||
// @import "templates/template";
|
||||
@import 'components/scrollbar';
|
||||
@import 'components/heading';
|
||||
@import 'components/button';
|
||||
@import 'components/form';
|
||||
|
||||
// Utilities
|
||||
// ==========================================================================
|
||||
@import "utilities/ratio";
|
||||
@import "utilities/widths";
|
||||
|
||||
@import 'utilities/ratio';
|
||||
@import 'utilities/grid-column';
|
||||
// @import "utilities/widths";
|
||||
// @import "utilities/align";
|
||||
// @import "utilities/helpers";
|
||||
// @import "utilities/states";
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// Objects / Container
|
||||
// ==========================================================================
|
||||
|
||||
//
|
||||
// Page-level constraining and wrapping elements.
|
||||
//
|
||||
// > In programming languages the word *container* is generally used for structures
|
||||
@@ -10,12 +9,10 @@
|
||||
// > 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;
|
||||
margin-left: auto;
|
||||
padding-right: rem($padding);
|
||||
padding-left: rem($padding);
|
||||
max-width: rem($container-width + ($padding * 2));
|
||||
padding-right: $base-column-gap;
|
||||
padding-left: $base-column-gap;
|
||||
}
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
// ==========================================================================
|
||||
// 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.
|
||||
*/
|
||||
.o-crop {
|
||||
position: relative; /* [1] */
|
||||
display: block;
|
||||
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.
|
||||
*/
|
||||
.o-crop_content {
|
||||
position: absolute;
|
||||
top: 0; /* [1] */
|
||||
left: 0; /* [1] */
|
||||
max-width: none; /* [2] */
|
||||
|
||||
/**
|
||||
* We can position the media in different locations within the cropping area.
|
||||
*/
|
||||
&.-right {
|
||||
right: 0;
|
||||
left: auto;
|
||||
}
|
||||
|
||||
&.-bottom {
|
||||
top: auto;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
&.-center {
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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."
|
||||
}
|
||||
|
||||
@if (type-of($consequent) != number) {
|
||||
@error "`#{$consequent}` needs to be a number."
|
||||
}
|
||||
|
||||
&.-#{$antecedent}\:#{$consequent} {
|
||||
padding-bottom: ($consequent/$antecedent) * 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* stylelint-enable */
|
||||
171
assets/styles/objects/_grid.scss
Normal file
171
assets/styles/objects/_grid.scss
Normal file
@@ -0,0 +1,171 @@
|
||||
// ==========================================================================
|
||||
// Grid helper
|
||||
// ==========================================================================
|
||||
// Help: https://css-tricks.com/snippets/css/complete-guide-grid/
|
||||
//
|
||||
/**
|
||||
* Usage:
|
||||
*
|
||||
* ```html
|
||||
* <div class="o-grid -col-4 -col-12@from-medium -gutters">
|
||||
* <div class="o-grid_item u-gc-1/2 u-gc-3/9@from-medium">
|
||||
* <p>Hello</p>
|
||||
* </div>
|
||||
* <div class="o-grid_item u-gc-3/4 u-gc-9/13@from-medium">
|
||||
* <p>Hello</p>
|
||||
* </div>
|
||||
* </div>
|
||||
* ```
|
||||
*/
|
||||
|
||||
.o-grid {
|
||||
display: grid;
|
||||
width: 100%;
|
||||
|
||||
&:is(ul, ol) {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// Cols
|
||||
// ==========================================================================
|
||||
&.-col-#{$base-column-nb} {
|
||||
grid-template-columns: repeat(#{$base-column-nb}, 1fr);
|
||||
}
|
||||
|
||||
&.-col-4 {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
}
|
||||
|
||||
&.-col-#{$base-column-nb}\@from-medium {
|
||||
@media (min-width: $from-medium) {
|
||||
grid-template-columns: repeat(#{$base-column-nb}, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// Gutters
|
||||
// ==========================================================================
|
||||
|
||||
// Gutters rows and columns
|
||||
&.-gutters {
|
||||
gap: $base-column-gap;
|
||||
column-gap: $base-column-gap;
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// Modifiers
|
||||
// ==========================================================================
|
||||
&.-full-height {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// Aligns
|
||||
// ==========================================================================
|
||||
|
||||
// ==========================================================================
|
||||
// Items inside cells
|
||||
//
|
||||
&.-top-items {
|
||||
align-items: start;
|
||||
}
|
||||
&.-right-items {
|
||||
justify-items: end;
|
||||
}
|
||||
&.-bottom-items {
|
||||
align-items: end;
|
||||
}
|
||||
&.-left-items {
|
||||
justify-items: start;
|
||||
}
|
||||
&.-center-items {
|
||||
align-items: center;
|
||||
justify-items: center;
|
||||
}
|
||||
&.-center-items-x {
|
||||
justify-items: center;
|
||||
}
|
||||
&.-center-items-y {
|
||||
align-items: center;
|
||||
}
|
||||
&.-stretch-items {
|
||||
align-items: stretch;
|
||||
justify-items: stretch;
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// Cells
|
||||
//
|
||||
&.-top-cells {
|
||||
align-content: start;
|
||||
}
|
||||
&.-right-cells {
|
||||
justify-content: end;
|
||||
}
|
||||
&.-bottom-cells {
|
||||
align-content: end;
|
||||
}
|
||||
&.-left-cells {
|
||||
justify-content: start;
|
||||
}
|
||||
&.-center-cells {
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
}
|
||||
&.-center-cells-x {
|
||||
justify-content: center;
|
||||
}
|
||||
&.-center-cells-y {
|
||||
align-content: center;
|
||||
}
|
||||
&.-stretch-cells {
|
||||
align-content: stretch;
|
||||
justify-content: stretch;
|
||||
}
|
||||
&.-space-around-cells {
|
||||
align-content: space-around;
|
||||
justify-content: space-around;
|
||||
}
|
||||
&.-space-around-cells-x {
|
||||
justify-content: space-around;
|
||||
}
|
||||
&.-space-around-cells-y {
|
||||
align-content: space-around;
|
||||
}
|
||||
&.-space-between-cells {
|
||||
justify-content: space-between;
|
||||
align-content: space-between;
|
||||
}
|
||||
&.-space-between-cells-x {
|
||||
justify-content: space-between;
|
||||
}
|
||||
&.-space-between-cells-y {
|
||||
align-content: space-between;
|
||||
}
|
||||
&.-space-evenly-cells {
|
||||
justify-content: space-evenly;
|
||||
align-content: space-evenly;
|
||||
}
|
||||
&.-space-evenly-cells-x {
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
&.-space-evenly-cells-y {
|
||||
align-content: space-evenly;
|
||||
}
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
// Grid item
|
||||
// ==========================================================================
|
||||
// By default, a grid item takes full width of its parent.
|
||||
//
|
||||
.o-grid_item {
|
||||
grid-column: 1 / -1;
|
||||
|
||||
&.-align-end {
|
||||
align-self: end;
|
||||
}
|
||||
}
|
||||
55
assets/styles/objects/_icons.scss
Normal file
55
assets/styles/objects/_icons.scss
Normal file
@@ -0,0 +1,55 @@
|
||||
// ==========================================================================
|
||||
// Objects / SVG Icons
|
||||
// ==========================================================================
|
||||
|
||||
// Markup
|
||||
//
|
||||
// 1. If icon is accessible and has a title
|
||||
// 2. If icon is decorative
|
||||
//
|
||||
// <i class="o-icon ${modifier}">
|
||||
// <svg
|
||||
// class="svg-${icon-name}"
|
||||
// xmlns="http://www.w3.org/2000/svg"
|
||||
// role="img" [1]
|
||||
// aria-hidden="true" [2]
|
||||
// focusable="false" [2]
|
||||
// aria-labelledby="${id}" [1]
|
||||
// >
|
||||
// <title id="${id}"> [1]
|
||||
// Locomotive
|
||||
// </title>
|
||||
// <use xlink:href="assets/images/sprite.svg#${icon-name}" xmlns:xlink="http://www.w3.org/1999/xlink"/>
|
||||
// </svg>
|
||||
// </i>
|
||||
|
||||
// Global styles for icones
|
||||
// ==========================================================================
|
||||
|
||||
.o-icon {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
|
||||
svg {
|
||||
--icon-height: calc(var(--icon-width) * (1 / (var(--icon-ratio))));
|
||||
|
||||
display: block;
|
||||
width: var(--icon-width);
|
||||
height: var(--icon-height);
|
||||
fill: currentColor;
|
||||
}
|
||||
}
|
||||
|
||||
// SVG sizes
|
||||
// ==========================================================================
|
||||
|
||||
// // Logo
|
||||
// .svg-logo {
|
||||
// --icon-width: #{rem(100px)};
|
||||
// --icon-ratio: 20/30; // width/height based on svg viewBox
|
||||
|
||||
// // Sizes
|
||||
// .o-icon.-big & {
|
||||
// --icon-width: #{rem(200px)};
|
||||
// }
|
||||
// }
|
||||
@@ -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;
|
||||
@@ -68,17 +68,17 @@
|
||||
}
|
||||
|
||||
&.-flex {
|
||||
display: flex;
|
||||
display: flex;
|
||||
|
||||
&.-top {
|
||||
&.-top {
|
||||
align-items: flex-start;
|
||||
}
|
||||
&.-middle {
|
||||
}
|
||||
&.-middle {
|
||||
align-items: center;
|
||||
}
|
||||
&.-bottom {
|
||||
}
|
||||
&.-bottom {
|
||||
align-items: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.-stretch {
|
||||
align-items: stretch;
|
||||
|
||||
@@ -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,17 +16,17 @@
|
||||
|
||||
&:before {
|
||||
display: block;
|
||||
padding-bottom: 100%; /* [1] */
|
||||
padding-bottom: 100%; // [1]
|
||||
width: 100%;
|
||||
content: "";
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
|
||||
.o-ratio_content,
|
||||
.o-ratio > img,
|
||||
.o-ratio > iframe,
|
||||
.o-ratio > embed,
|
||||
.o-ratio > object {
|
||||
.o-ratio > img,
|
||||
.o-ratio > iframe,
|
||||
.o-ratio > embed,
|
||||
.o-ratio > object {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
|
||||
@@ -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,22 +4,26 @@
|
||||
|
||||
// Palette
|
||||
// =============================================================================
|
||||
$white: #FFFFFF;
|
||||
$black: #000000;
|
||||
|
||||
$color-lightest: #ffffff;
|
||||
$color-darkest: #000000;
|
||||
|
||||
// Specific
|
||||
// =============================================================================
|
||||
|
||||
// Link
|
||||
$link-color: #1A0DAB;
|
||||
$link-focus-color: #1A0DAB;
|
||||
$link-hover-color: darken(#1A0DAB, 10%);
|
||||
$color-link: #1a0dab;
|
||||
$color-link-focus: #1a0dab;
|
||||
$color-link-hover: darken(#1a0dab, 10%);
|
||||
|
||||
// Selection
|
||||
$selection-text-color: #3297FD;
|
||||
$selection-background-color: #FFFFFF;
|
||||
$selection-text-color: #3297fd;
|
||||
$selection-background-color: #ffffff;
|
||||
|
||||
// Social Colors
|
||||
// =============================================================================
|
||||
$facebook-color: #3B5998;
|
||||
$instagram-color: #E1306C;
|
||||
$youtube-color: #CD201F;
|
||||
$twitter-color: #1DA1F2;
|
||||
|
||||
$color-facebook: #3b5998;
|
||||
$color-instagram: #e1306c;
|
||||
$color-youtube: #cd201f;
|
||||
$color-twitter: #1da1f2;
|
||||
|
||||
@@ -1,19 +1,48 @@
|
||||
$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);
|
||||
$Power4EaseOut: cubic-bezier(0.230, 1.000, 0.320, 1.000);
|
||||
$Power1EaseIn: cubic-bezier(0.550, 0.085, 0.680, 0.530) ;
|
||||
$Power2EaseIn: cubic-bezier(0.550, 0.055, 0.675, 0.190);
|
||||
$Power3EaseIn: cubic-bezier(0.895, 0.030, 0.685, 0.220);
|
||||
$Power4EaseIn: cubic-bezier(0.755, 0.050, 0.855, 0.060);
|
||||
$ExpoEaseOut: cubic-bezier(0.190, 1.000, 0.220, 1.000);
|
||||
$ExpoEaseIn: cubic-bezier(0.950, 0.050, 0.795, 0.035);
|
||||
$ExpoEaseInOut: cubic-bezier(1.000, 0.000, 0.000, 1.000);
|
||||
$SineEaseOut: cubic-bezier(0.390, 0.575, 0.565, 1.000);
|
||||
$SineEaseIn: cubic-bezier(0.470, 0.000, 0.745, 0.715);
|
||||
$Power1EaseInOut: cubic-bezier(0.455, 0.030, 0.515, 0.955);
|
||||
$Power2EaseInOut: cubic-bezier(0.645, 0.045, 0.355, 1.000);
|
||||
$Power3EaseInOut: cubic-bezier(0.770, 0.000, 0.175, 1.000);
|
||||
$Power4EaseInOut: cubic-bezier(0.860, 0.000, 0.070, 1.000);
|
||||
$SlowEaseOut: cubic-bezier(.04,1.15,0.4,.99);
|
||||
$bounce: cubic-bezier(0.17, 0.67, 0.3, 1.33);
|
||||
// ==========================================================================
|
||||
// Settings / Config / Eases
|
||||
// ==========================================================================
|
||||
|
||||
// Power 1
|
||||
$ease-power1-in: cubic-bezier(0.55, 0.085, 0.68, 0.53);
|
||||
$ease-power1-out: cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
$ease-power1-in-out: cubic-bezier(0.455, 0.03, 0.515, 0.955);
|
||||
|
||||
// Power 2
|
||||
$ease-power2-in: cubic-bezier(0.55, 0.055, 0.675, 0.19);
|
||||
$ease-power2-out: cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||
$ease-power2-in-out: cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||
|
||||
// Power 3
|
||||
$ease-power3-in: cubic-bezier(0.895, 0.03, 0.685, 0.22);
|
||||
$ease-power3-out: cubic-bezier(0.165, 0.84, 0.44, 1);
|
||||
$ease-power3-in-out: cubic-bezier(0.77, 0, 0.175, 1);
|
||||
|
||||
// Power 3
|
||||
$ease-power4-in: cubic-bezier(0.755, 0.05, 0.855, 0.06);
|
||||
$ease-power4-out: cubic-bezier(0.23, 1, 0.32, 1);
|
||||
$ease-power4-in-out: cubic-bezier(0.86, 0, 0.07, 1);
|
||||
|
||||
// Expo
|
||||
$ease-expo-in: cubic-bezier(0.95, 0.05, 0.795, 0.035);
|
||||
$ease-expo-out: cubic-bezier(0.19, 1, 0.22, 1);
|
||||
$ease-expo-in-out: cubic-bezier(1, 0, 0, 1);
|
||||
|
||||
// Back
|
||||
$ease-back-in: cubic-bezier(0.6, -0.28, 0.735, 0.045);
|
||||
$ease-back-out: cubic-bezier(0.175, 00.885, 0.32, 1.275);
|
||||
$ease-back-in-out: cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
||||
|
||||
// Sine
|
||||
$ease-sine-in: cubic-bezier(0.47, 0, 0.745, 0.715);
|
||||
$ease-sine-out: cubic-bezier(0.39, 0.575, 0.565, 1);
|
||||
$ease-sine-in-out: cubic-bezier(0.445, 0.05, 0.55, 0.95);
|
||||
|
||||
// Circ
|
||||
$ease-circ-in: cubic-bezier(0.6, 0.04, 0.98, 0.335);
|
||||
$ease-circ-out: cubic-bezier(0.075, 0.82, 0.165, 1);
|
||||
$ease-circ-in-out: cubic-bezier(0.785, 0.135, 0.15, 0.86);
|
||||
|
||||
// Misc
|
||||
$ease-bounce: cubic-bezier(0.17, 0.67, 0.3, 1.33);
|
||||
$ease-slow-out: cubic-bezier(0.04, 1.15, 0.4, 0.99);
|
||||
$ease-smooth: cubic-bezier(0.38, 0.005, 0.215, 1);
|
||||
|
||||
@@ -4,69 +4,120 @@
|
||||
|
||||
// Context
|
||||
// =============================================================================
|
||||
|
||||
// The current stylesheet context. Available values: frontend, editor.
|
||||
$context: frontend !default;
|
||||
$context: frontend !default;
|
||||
|
||||
// Path is relative to the stylesheets directory.
|
||||
$assets-path: "../" !default;
|
||||
$assets-path: '../' !default;
|
||||
|
||||
// Typefaces
|
||||
// =============================================================================
|
||||
$font-sans-serif: sans-serif;
|
||||
|
||||
// Font directory
|
||||
$font-dir: '../fonts/';
|
||||
|
||||
// Font fallbacks (retrieved from systemfontstack.com on 2022-05-31)
|
||||
$font-fallback-sans: -apple-system, BlinkMacSystemFont, avenir next, avenir,
|
||||
segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial,
|
||||
sans-serif;
|
||||
$font-fallback-serif: Iowan Old Style, Apple Garamond, Baskerville,
|
||||
Times New Roman, Droid Serif, Times, Source Serif Pro, serif,
|
||||
Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;
|
||||
$font-fallback-mono: Menlo, Consolas, Monaco, Liberation Mono, Lucida Console,
|
||||
monospace;
|
||||
|
||||
// Map of font families.
|
||||
//
|
||||
// ```
|
||||
// <font-id>: (<font-name>, <font-fallbacks>)
|
||||
// ```
|
||||
$font-families: (
|
||||
sans: join('Source Sans', $font-fallback-sans, $separator: comma),
|
||||
);
|
||||
|
||||
// List of custom font faces as tuples.
|
||||
//
|
||||
// ```
|
||||
// <font-name> <font-file-basename> <font-weight> <font-style>
|
||||
// ```
|
||||
$font-faces: (
|
||||
('Source Sans', 'SourceSans3-Bold', 700, normal),
|
||||
('Source Sans', 'SourceSans3-BoldIt', 700, italic),
|
||||
('Source Sans', 'SourceSans3-Regular', 400, normal),
|
||||
('Source Sans', 'SourceSans3-RegularIt', 400, italic)
|
||||
);
|
||||
|
||||
// Typography
|
||||
// =============================================================================
|
||||
|
||||
// Base
|
||||
$font-size: 16px;
|
||||
$line-height: 24px / $font-size;
|
||||
$font-family: $font-sans-serif;
|
||||
$color: #222222;
|
||||
$font-size: 16px;
|
||||
$line-height: math.div(24px, $font-size);
|
||||
$font-color: $color-darkest;
|
||||
|
||||
// Headings
|
||||
$font-size-h1: 36px !default;
|
||||
$font-size-h2: 28px !default;
|
||||
$font-size-h3: 24px !default;
|
||||
$font-size-h4: 20px !default;
|
||||
$font-size-h5: 18px !default;
|
||||
$font-size-h6: 16px !default;
|
||||
$font-size-h1: 36px !default;
|
||||
$font-size-h2: 28px !default;
|
||||
$font-size-h3: 24px !default;
|
||||
$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;
|
||||
$medium: 500;
|
||||
$bold: 700;
|
||||
$font-weight-light: 300;
|
||||
$font-weight-normal: 400;
|
||||
$font-weight-medium: 500;
|
||||
$font-weight-bold: 700;
|
||||
|
||||
// Transitions
|
||||
// =============================================================================
|
||||
$speed: 0.3s;
|
||||
$easing: $Power2EaseOut;
|
||||
|
||||
$speed: 0.3s;
|
||||
$easing: $ease-power2-out;
|
||||
|
||||
// Spacing Units
|
||||
// =============================================================================
|
||||
$unit: 60px;
|
||||
$unit-small: 30px;
|
||||
$unit: 60px;
|
||||
$unit-small: 20px;
|
||||
|
||||
// Container
|
||||
// ==========================================================================
|
||||
$container-width: 2000px;
|
||||
$padding: $unit;
|
||||
$padding: $unit;
|
||||
|
||||
// Grid
|
||||
// ==========================================================================
|
||||
$base-column-nb: 12;
|
||||
$base-column-gap: $unit-small;
|
||||
|
||||
// Breakpoints
|
||||
// =============================================================================
|
||||
$from-tiny: 500px !default;
|
||||
$to-tiny: $from-tiny - 1 !default;
|
||||
$from-small: 700px !default;
|
||||
$to-small: $from-small - 1 !default;
|
||||
$from-medium: 1000px !default;
|
||||
$to-medium: $from-medium - 1 !default;
|
||||
$from-large: 1200px !default;
|
||||
$to-large: $from-large - 1 !default;
|
||||
$from-big: 1400px !default;
|
||||
$to-big: $from-big - 1 !default;
|
||||
$from-huge: 1600px !default;
|
||||
$to-huge: $from-huge - 1 !default;
|
||||
$from-enormous: 1800px !default;
|
||||
$to-enormous: $from-enormous - 1 !default;
|
||||
$from-gigantic: 2000px !default;
|
||||
$to-gigantic: $from-gigantic - 1 !default;
|
||||
$from-colossal: 2400px !default;
|
||||
$to-colossal: $from-colossal - 1 !default;
|
||||
|
||||
$from-tiny: 500px !default;
|
||||
$to-tiny: $from-tiny - 1 !default;
|
||||
$from-small: 700px !default;
|
||||
$to-small: $from-small - 1 !default;
|
||||
$from-medium: 1000px !default;
|
||||
$to-medium: $from-medium - 1 !default;
|
||||
$from-large: 1200px !default;
|
||||
$to-large: $from-large - 1 !default;
|
||||
$from-big: 1400px !default;
|
||||
$to-big: $from-big - 1 !default;
|
||||
$from-huge: 1600px !default;
|
||||
$to-huge: $from-huge - 1 !default;
|
||||
$from-enormous: 1800px !default;
|
||||
$to-enormous: $from-enormous - 1 !default;
|
||||
$from-gigantic: 2000px !default;
|
||||
$to-gigantic: $from-gigantic - 1 !default;
|
||||
$from-colossal: 2400px !default;
|
||||
$to-colossal: $from-colossal - 1 !default;
|
||||
|
||||
// Master z-indexe
|
||||
// =============================================================================
|
||||
|
||||
$z-indexes: (
|
||||
'header': 200,
|
||||
'above': 1,
|
||||
'below': -1,
|
||||
);
|
||||
|
||||
@@ -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,59 +219,66 @@
|
||||
}
|
||||
}
|
||||
|
||||
/// 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);
|
||||
|
||||
&:nth-last-child(n + #{$min}):nth-last-child(-n + #{$max}):first-child,
|
||||
&:nth-last-child(n + #{$min}):nth-last-child(-n + #{$max}):first-child ~ #{$child} {
|
||||
&:nth-last-child(n + #{$min}):nth-last-child(-n + #{$max}):first-child
|
||||
~ #{$child} {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
@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
|
||||
@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 +286,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 +342,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,60 @@
|
||||
// Tools / Font Faces
|
||||
// ==========================================================================
|
||||
|
||||
$global-font-file-formats: "woff2", "woff" !default;
|
||||
// Imports the custom font.
|
||||
//
|
||||
// The mixin expects font files to be woff and woff2.
|
||||
//
|
||||
// @param {List} $webfont - A custom font to import, as a tuple:
|
||||
// `<font-name> <font-file-basename> <font-weight> <font-style>`.
|
||||
// @param {String} $dir - The webfont directory path.
|
||||
// @output The `@font-face` at-rule specifying the custom font.
|
||||
|
||||
//
|
||||
// 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"),
|
||||
);
|
||||
@mixin font-face($webfont, $dir) {
|
||||
@font-face {
|
||||
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)};
|
||||
}
|
||||
}
|
||||
|
||||
@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);
|
||||
// Imports the list of custom fonts.
|
||||
//
|
||||
// @require {mixin} font-face
|
||||
//
|
||||
// @param {List<List>} $webfonts - List of custom fonts to import.
|
||||
// See `font-face` mixin for details.
|
||||
// @param {String} $dir - The webfont directory path.
|
||||
// @output The `@font-face` at-rules specifying the custom fonts.
|
||||
|
||||
@mixin font-faces($webfonts, $dir) {
|
||||
@if (length($webfonts) > 0) {
|
||||
@if (type-of(nth($webfonts, 1)) == 'list') {
|
||||
@each $webfont in $webfonts {
|
||||
@include font-face($webfont, $dir);
|
||||
}
|
||||
} @else {
|
||||
@include font-face($webfonts, $dir);
|
||||
}
|
||||
}
|
||||
|
||||
@return $src;
|
||||
}
|
||||
|
||||
// Retrieves the font family stack for the given font ID.
|
||||
//
|
||||
// Generates an `@font-face` declaration.
|
||||
// @require {variable} $font-families - See settings directory.
|
||||
//
|
||||
// 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
|
||||
) {
|
||||
@font-face {
|
||||
font-family: $font-family;
|
||||
src: font-source-declaration( $font-family, $file-path, $file-formats);
|
||||
@content;
|
||||
// @param {String} $font-family - The custom font ID.
|
||||
// @throws Error if the $font-family does not exist.
|
||||
// @return {List} The font stack.
|
||||
|
||||
@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}`.";
|
||||
}
|
||||
|
||||
$value: map-get($font-families, $font-family);
|
||||
@return $value;
|
||||
}
|
||||
|
||||
@@ -1,73 +1,88 @@
|
||||
// ==========================================================================
|
||||
// Tools / Functions
|
||||
// ==========================================================================
|
||||
|
||||
// Check if the given value is a number in pixel
|
||||
//
|
||||
// @param {Number} $number - The value to check
|
||||
// @return {Boolean}
|
||||
|
||||
@function is-pixel-number($number) {
|
||||
@return type-of($number) == number and unit($number) == 'px';
|
||||
}
|
||||
|
||||
// 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") {
|
||||
@error "`#{$size}` needs to be a pixel value.";
|
||||
}
|
||||
} @else {
|
||||
@error "`#{$size}` needs to be a number.";
|
||||
@if not is-pixel-number($size) {
|
||||
@error "`#{$size}` needs to be a number in pixel.";
|
||||
}
|
||||
|
||||
@if (type-of($base) == number) {
|
||||
@if (unit($base) != "px") {
|
||||
@error "`#{$base}` needs to be a pixel value.";
|
||||
}
|
||||
} @else {
|
||||
@error "`#{$base}` needs to be a number.";
|
||||
@if not is-pixel-number($base) {
|
||||
@error "`#{$base}` needs to be a number in pixel.";
|
||||
}
|
||||
|
||||
@return ($size / $base) * 1em;
|
||||
@return math.div($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") {
|
||||
@error "`#{$size}` needs to be a pixel value.";
|
||||
}
|
||||
} @else {
|
||||
@error "`#{$size}` needs to be a number.";
|
||||
@if not is-pixel-number($size) {
|
||||
@error "`#{$size}` needs to be a number in pixel.";
|
||||
}
|
||||
|
||||
@if (type-of($base) == number) {
|
||||
@if (unit($base) != "px") {
|
||||
@error "`#{$base}` needs to be a pixel value.";
|
||||
}
|
||||
} @else {
|
||||
@error "`#{$base}` needs to be a number.";
|
||||
@if not is-pixel-number($base) {
|
||||
@error "`#{$base}` needs to be a number in pixel.";
|
||||
}
|
||||
|
||||
@return ($size / $base) * 1rem;
|
||||
@return math.div($size, $base) * 1rem;
|
||||
}
|
||||
|
||||
// Retrieves the z-index from the {@see $layers master list}.
|
||||
//
|
||||
// @link on http://css-tricks.com/handling-z-index/
|
||||
//
|
||||
// @param {string} $layer The name of the z-index.
|
||||
// @param {number} $modifier A positive or negative modifier to apply
|
||||
// to the returned z-index value.
|
||||
// @throw Error if the $layer does not exist.
|
||||
// @throw Warning if the $modifier might overlap another master z-index.
|
||||
// @return {number} The computed z-index of $layer and $modifier.
|
||||
|
||||
@function z($layer, $modifier: 0) {
|
||||
@if not map-has-key($z-indexes, $layer) {
|
||||
@error "Unknown master z-index layer: #{$layer}";
|
||||
}
|
||||
|
||||
@if ($modifier >= 50 or $modifier <= -50) {
|
||||
@warn "Modifier may overlap the another master z-index layer: #{$modifier}";
|
||||
}
|
||||
|
||||
$index: map-get($z-indexes, $layer);
|
||||
|
||||
@return $index + $modifier;
|
||||
}
|
||||
|
||||
// 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,13 +90,10 @@
|
||||
// @param {List} $values - A single value or list of values to check for.
|
||||
// @return {Boolean}
|
||||
// @access private
|
||||
//
|
||||
@function list-contains(
|
||||
$list,
|
||||
$values...
|
||||
) {
|
||||
|
||||
@function list-contains($list, $values...) {
|
||||
@each $value in $values {
|
||||
@if type-of(index($list, $value)) != "number" {
|
||||
@if type-of(index($list, $value)) != 'number' {
|
||||
@return false;
|
||||
}
|
||||
}
|
||||
@@ -89,38 +101,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) {
|
||||
} @else if ($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]
|
||||
|
||||
136
assets/styles/tools/_maths.scss
Normal file
136
assets/styles/tools/_maths.scss
Normal file
@@ -0,0 +1,136 @@
|
||||
// ==========================================================================
|
||||
// Tools / Maths
|
||||
// ==========================================================================
|
||||
|
||||
// Removes the unit from the given number.
|
||||
//
|
||||
// @param {number} $number The number to strip.
|
||||
// @return {number}
|
||||
|
||||
@function strip-units($number) {
|
||||
@return $number / ($number * 0 + 1);
|
||||
}
|
||||
|
||||
// Returns the square root of the given number.
|
||||
//
|
||||
// @param {number} $number The number to calculate.
|
||||
// @return {number}
|
||||
|
||||
@function sqrt($number) {
|
||||
$x: 1;
|
||||
$value: $x;
|
||||
|
||||
@for $i from 1 through 10 {
|
||||
$value: $x - ($x * $x - abs($number)) / (2 * $x);
|
||||
$x: $value;
|
||||
}
|
||||
|
||||
@return $value;
|
||||
}
|
||||
|
||||
// Returns a number raised to the power of an exponent.
|
||||
//
|
||||
// @param {number} $number The base number.
|
||||
// @param {number} $exp The exponent.
|
||||
// @return {number}
|
||||
|
||||
@function pow($number, $exp) {
|
||||
$value: 1;
|
||||
|
||||
@if $exp > 0 {
|
||||
@for $i from 1 through $exp {
|
||||
$value: $value * $number;
|
||||
}
|
||||
} @else if $exp < 0 {
|
||||
@for $i from 1 through -$exp {
|
||||
$value: $value / $number;
|
||||
}
|
||||
}
|
||||
|
||||
@return $value;
|
||||
}
|
||||
|
||||
// Returns the factorial of the given number.
|
||||
//
|
||||
// @param {number} $number The number to calculate.
|
||||
// @return {number}
|
||||
|
||||
@function fact($number) {
|
||||
$value: 1;
|
||||
|
||||
@if $number > 0 {
|
||||
@for $i from 1 through $number {
|
||||
$value: $value * $i;
|
||||
}
|
||||
}
|
||||
|
||||
@return $value;
|
||||
}
|
||||
|
||||
// Returns an approximation of pi, with 11 decimals.
|
||||
//
|
||||
// @return {number}
|
||||
|
||||
@function pi() {
|
||||
@return 3.14159265359;
|
||||
}
|
||||
|
||||
// Converts the number in degrees to the radian equivalent .
|
||||
//
|
||||
// @param {number} $angle The angular value to calculate.
|
||||
// @return {number} If $angle has the `deg` unit,
|
||||
// the radian equivalent is returned.
|
||||
// Otherwise, the unitless value of $angle is returned.
|
||||
|
||||
@function rad($angle) {
|
||||
$unit: unit($angle);
|
||||
$angle: strip-units($angle);
|
||||
|
||||
// If the angle has `deg` as unit, convert to radians.
|
||||
@if ($unit == deg) {
|
||||
@return $angle / 180 * pi();
|
||||
}
|
||||
|
||||
@return $angle;
|
||||
}
|
||||
|
||||
// Returns the sine of the given number.
|
||||
//
|
||||
// @param {number} $angle The angle to calculate.
|
||||
// @return {number}
|
||||
|
||||
@function sin($angle) {
|
||||
$sin: 0;
|
||||
$angle: rad($angle);
|
||||
|
||||
@for $i from 0 through 10 {
|
||||
$sin: $sin + pow(-1, $i) * pow($angle, (2 * $i + 1)) / fact(2 * $i + 1);
|
||||
}
|
||||
|
||||
@return $sin;
|
||||
}
|
||||
|
||||
// Returns the cosine of the given number.
|
||||
//
|
||||
// @param {string} $angle The angle to calculate.
|
||||
// @return {number}
|
||||
|
||||
@function cos($angle) {
|
||||
$cos: 0;
|
||||
$angle: rad($angle);
|
||||
|
||||
@for $i from 0 through 10 {
|
||||
$cos: $cos + pow(-1, $i) * pow($angle, 2 * $i) / fact(2 * $i);
|
||||
}
|
||||
|
||||
@return $cos;
|
||||
}
|
||||
|
||||
// Returns the tangent of the given number.
|
||||
//
|
||||
// @param {string} $angle The angle to calculate.
|
||||
// @return {number}
|
||||
|
||||
@function tan($angle) {
|
||||
@return sin($angle) / cos($angle);
|
||||
}
|
||||
@@ -2,46 +2,42 @@
|
||||
// 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);
|
||||
clear: both;
|
||||
content: if(list-contains($supports, opera), " ", "");
|
||||
content: if(list-contains($supports, opera), ' ', '');
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Generate a font-size and baseline-compatible line-height.
|
||||
//
|
||||
// @link https://github.com/inuitcss/inuitcss/c14029c/tools/_tools.font-size.scss
|
||||
@@ -49,25 +45,31 @@
|
||||
// @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;
|
||||
|
||||
@if ($line-height == "auto") {
|
||||
line-height: ceil($font-size / $line-height) * ($line-height / $font-size) $important;
|
||||
}
|
||||
@else {
|
||||
@if (type-of($line-height) == number or $line-height == "inherit" or $line-height == "normal") {
|
||||
@if ($line-height == 'auto') {
|
||||
line-height: ceil($font-size / $line-height) *
|
||||
($line-height / $font-size)
|
||||
$important;
|
||||
} @else {
|
||||
@if (
|
||||
type-of($line-height) ==
|
||||
number or
|
||||
$line-height ==
|
||||
'inherit' or
|
||||
$line-height ==
|
||||
'normal'
|
||||
) {
|
||||
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`."
|
||||
} @else if ($line-height != 'none' and $line-height != false) {
|
||||
@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,14 +77,14 @@
|
||||
// and its children.
|
||||
//
|
||||
// @output `font-size`, `display`, `vertical-align`
|
||||
//
|
||||
|
||||
@mixin o-vertical-center {
|
||||
font-size: 0;
|
||||
|
||||
&::before {
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
content: "";
|
||||
content: '';
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
@@ -93,13 +95,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 +108,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 +121,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Prevent text from wrapping onto multiple lines for the current element.
|
||||
//
|
||||
// An ellipsis is appended to the end of the line.
|
||||
@@ -131,23 +130,22 @@
|
||||
//
|
||||
// @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;
|
||||
white-space: nowrap;
|
||||
word-wrap: normal; // [2]
|
||||
word-wrap: normal; // [2]
|
||||
@if $width {
|
||||
max-width: $width; // [1]
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// 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 +158,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 +173,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Hide the current element from all.
|
||||
//
|
||||
// The element will be hidden from screen readers and removed from the document flow.
|
||||
@@ -184,14 +180,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;
|
||||
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,9 +194,9 @@
|
||||
// @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;
|
||||
visibility: visible $important;
|
||||
visibility: visible $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;
|
||||
}
|
||||
|
||||
63
assets/styles/utilities/_grid-column.scss
Normal file
63
assets/styles/utilities/_grid-column.scss
Normal file
@@ -0,0 +1,63 @@
|
||||
// ==========================================================================
|
||||
// Tools / Grid Columns
|
||||
// ==========================================================================
|
||||
|
||||
//
|
||||
// Grid layout system.
|
||||
//
|
||||
// This tool generates columns for all needed media queries.
|
||||
// Unused classes will be purge by the css post-processor.
|
||||
//
|
||||
|
||||
$colsMax: $base-column-nb + 1;
|
||||
|
||||
$breakpoints: (
|
||||
'null' null,
|
||||
'from-tiny' 'from-tiny',
|
||||
'from-small' 'from-small',
|
||||
'from-medium' 'from-medium',
|
||||
'from-large' 'from-large',
|
||||
'from-big' 'from-big'
|
||||
) !default;
|
||||
|
||||
@each $breakpoint-namespace, $breakpoint in $breakpoints {
|
||||
@for $fromIndex from 1 through $colsMax {
|
||||
@for $toIndex from 1 through $colsMax {
|
||||
@if $breakpoint == null {
|
||||
.u-gc-#{$fromIndex}\/#{$toIndex} {
|
||||
grid-column-start: #{$fromIndex};
|
||||
grid-column-end: #{$toIndex};
|
||||
}
|
||||
} @else {
|
||||
.u-gc-#{$fromIndex}\/#{$toIndex}\@#{$breakpoint} {
|
||||
@if $breakpoint-namespace == 'from-tiny' {
|
||||
@media (min-width: $from-tiny) {
|
||||
grid-column-start: #{$fromIndex};
|
||||
grid-column-end: #{$toIndex};
|
||||
}
|
||||
} @else if $breakpoint-namespace == 'from-small' {
|
||||
@media (min-width: $from-small) {
|
||||
grid-column-start: #{$fromIndex};
|
||||
grid-column-end: #{$toIndex};
|
||||
}
|
||||
} @else if $breakpoint-namespace == 'from-medium' {
|
||||
@media (min-width: $from-medium) {
|
||||
grid-column-start: #{$fromIndex};
|
||||
grid-column-end: #{$toIndex};
|
||||
}
|
||||
} @else if $breakpoint-namespace == 'from-large' {
|
||||
@media (min-width: $from-large) {
|
||||
grid-column-start: #{$fromIndex};
|
||||
grid-column-end: #{$toIndex};
|
||||
}
|
||||
} @else if $breakpoint-namespace == 'from-big' {
|
||||
@media (min-width: $from-big) {
|
||||
grid-column-start: #{$fromIndex};
|
||||
grid-column-end: #{$toIndex};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,25 +4,28 @@
|
||||
|
||||
// Layout
|
||||
// ==========================================================================
|
||||
|
||||
.u-clearfix {
|
||||
@include u-clearfix;
|
||||
}
|
||||
|
||||
// Decorative
|
||||
// =============================================================================
|
||||
|
||||
.u-truncate {
|
||||
@include u-truncate;
|
||||
}
|
||||
|
||||
// Visibility / Display
|
||||
// ==========================================================================
|
||||
[hidden][aria-hidden="false"] {
|
||||
|
||||
[hidden][aria-hidden='false'] {
|
||||
position: absolute;
|
||||
display: inherit;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
[hidden][aria-hidden="false"]:focus {
|
||||
[hidden][aria-hidden='false']:focus {
|
||||
clip: auto;
|
||||
}
|
||||
|
||||
@@ -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,8 @@
|
||||
////
|
||||
|
||||
@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 +20,7 @@
|
||||
*:first-line {
|
||||
background: transparent !important;
|
||||
box-shadow: none !important;
|
||||
color: #000000 !important; /* [1] */
|
||||
color: #000000 !important; // [1]
|
||||
text-shadow: none !important;
|
||||
}
|
||||
|
||||
@@ -31,20 +30,19 @@
|
||||
}
|
||||
|
||||
a[href]:after {
|
||||
content: " (" attr(href) ")";
|
||||
content: ' (' attr(href) ')';
|
||||
}
|
||||
|
||||
abbr[title]:after {
|
||||
content: " (" attr(title) ")";
|
||||
content: ' (' attr(title) ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't show links that are fragment identifiers, or use the `javascript:`
|
||||
* pseudo protocol.
|
||||
*/
|
||||
a[href^="#"]:after,
|
||||
a[href^="javascript:"]:after {
|
||||
content: "";
|
||||
// Don't show links that are fragment identifiers, or use the `javascript:`
|
||||
// pseudo protocol.
|
||||
|
||||
a[href^='#']:after,
|
||||
a[href^='javascript:']:after {
|
||||
content: '';
|
||||
}
|
||||
|
||||
pre,
|
||||
@@ -53,9 +51,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;
|
||||
}
|
||||
@@ -65,7 +62,6 @@
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
|
||||
|
||||
img {
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
@@ -2,39 +2,40 @@
|
||||
// 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:9),
|
||||
(
|
||||
2: 1,
|
||||
),
|
||||
(
|
||||
4: 3,
|
||||
),
|
||||
(
|
||||
16: 9,
|
||||
)
|
||||
) !default;
|
||||
|
||||
/* 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) {
|
||||
@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.";
|
||||
}
|
||||
|
||||
&.u-#{$antecedent}\:#{$consequent}::before {
|
||||
padding-bottom: ($consequent/$antecedent) * 100%;
|
||||
.u-#{$antecedent}\:#{$consequent}::before {
|
||||
padding-bottom: math.div($consequent, $antecedent) * 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,25 +21,25 @@
|
||||
/* stylelint-disable string-quotes */
|
||||
|
||||
$spacing-directions: (
|
||||
null: null,
|
||||
'-top': '-top',
|
||||
'-right': '-right',
|
||||
'-bottom': '-bottom',
|
||||
'-left': '-left',
|
||||
null: null,
|
||||
'-top': '-top',
|
||||
'-right': '-right',
|
||||
'-bottom': '-bottom',
|
||||
'-left': '-left',
|
||||
'-horizontal': '-left' '-right',
|
||||
'-vertical': '-top' '-bottom',
|
||||
'-vertical': '-top' '-bottom',
|
||||
) !default;
|
||||
|
||||
$spacing-properties: (
|
||||
'padding': 'padding',
|
||||
'margin': 'margin',
|
||||
'margin': 'margin',
|
||||
) !default;
|
||||
|
||||
$spacing-sizes: (
|
||||
null: $unit,
|
||||
null: $unit,
|
||||
'-double': $unit * 2,
|
||||
'-small': $unit-small,
|
||||
'-none': 0px
|
||||
'-none': 0px,
|
||||
) !default;
|
||||
|
||||
@each $property-namespace, $property in $spacing-properties {
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
// Utilities / States
|
||||
// ==========================================================================
|
||||
|
||||
/**
|
||||
* ARIA roles display visual cursor hints
|
||||
*/
|
||||
[aria-busy="true"] {
|
||||
// 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,9 +1,11 @@
|
||||
import concatFiles from './tasks/concats.js';
|
||||
import compileScripts from './tasks/scripts.js';
|
||||
import compileStyles from './tasks/styles.js' ;
|
||||
import compileSVGs from './tasks/svgs.js' ;
|
||||
import compileStyles from './tasks/styles.js';
|
||||
import compileSVGs from './tasks/svgs.js';
|
||||
import bumpVersions from './tasks/versions.js';
|
||||
|
||||
concatFiles();
|
||||
compileScripts();
|
||||
compileStyles();
|
||||
compileSVGs();
|
||||
bumpVersions();
|
||||
|
||||
@@ -6,7 +6,8 @@ import resolve from '../utils/template.js';
|
||||
import { writeFile } from 'node:fs/promises';
|
||||
import { basename } from 'node:path';
|
||||
import { promisify } from 'node:util';
|
||||
import sass from 'node-sass';
|
||||
import sass from 'sass';
|
||||
import { PurgeCSS } from 'purgecss';
|
||||
|
||||
const sassRender = promisify(sass.render);
|
||||
|
||||
@@ -22,6 +23,7 @@ export const defaultSassOptions = {
|
||||
sourceMap: true,
|
||||
sourceMapContents: true,
|
||||
};
|
||||
|
||||
export const developmentSassOptions = Object.assign({}, defaultSassOptions, {
|
||||
outputStyle: 'expanded',
|
||||
});
|
||||
@@ -142,7 +144,12 @@ export default async function compileStyles(sassOptions = null, postcssOptions =
|
||||
}
|
||||
|
||||
try {
|
||||
await writeFile(outfile, result.css);
|
||||
await writeFile(outfile, result.css).then(() => {
|
||||
// Purge CSS once file exists.
|
||||
if (outfile) {
|
||||
purgeUnusedCSS(outfile, `${label || `${filestem}.css`}`);
|
||||
}
|
||||
});
|
||||
|
||||
if (result.css) {
|
||||
message(`${label || `${filestem}.css`} compiled`, 'success', timeLabel);
|
||||
@@ -212,3 +219,37 @@ function createPostCSSProcessor(pluginsListOrMap, options)
|
||||
|
||||
return postcss(plugins);
|
||||
}
|
||||
|
||||
/**
|
||||
* Purge unused styles from CSS files.
|
||||
*
|
||||
* @async
|
||||
*
|
||||
* @param {string} outfile - The path of a css file
|
||||
* If missing the function stops.
|
||||
* @param {string} label - The CSS file label or name.
|
||||
* @return {Promise}
|
||||
*/
|
||||
async function purgeUnusedCSS(outfile, label) {
|
||||
label = label ?? basename(outfile);
|
||||
const timeLabel = `${label} purged in`;
|
||||
console.time(timeLabel);
|
||||
|
||||
const purgeCSSContentFiles = Array.from(loconfig.tasks.purgeCSS.content);
|
||||
|
||||
const purgeCSSResults = await new PurgeCSS().purge({
|
||||
content: purgeCSSContentFiles,
|
||||
css: [ outfile ],
|
||||
rejected: true,
|
||||
defaultExtractor: content => content.match(/[a-z0-9_\-\\\/\@]+/gi) || [],
|
||||
safelist: {
|
||||
standard: [ /^((?!\bu-gc-).)*$/ ]
|
||||
}
|
||||
})
|
||||
|
||||
for(let result of purgeCSSResults) {
|
||||
await writeFile(outfile, result.css)
|
||||
|
||||
message(`${label} purged`, 'chore', timeLabel);
|
||||
}
|
||||
}
|
||||
|
||||
315
build/tasks/versions.js
Normal file
315
build/tasks/versions.js
Normal file
@@ -0,0 +1,315 @@
|
||||
import loconfig from '../utils/config.js';
|
||||
import message from '../utils/message.js';
|
||||
import resolve from '../utils/template.js';
|
||||
import { randomBytes } from 'node:crypto';
|
||||
import events from 'node:events';
|
||||
import {
|
||||
createReadStream,
|
||||
createWriteStream,
|
||||
} from 'node:fs';
|
||||
import {
|
||||
mkdir,
|
||||
rename,
|
||||
rm,
|
||||
readFile,
|
||||
writeFile,
|
||||
} from 'node:fs/promises';
|
||||
import {
|
||||
basename,
|
||||
dirname,
|
||||
} from 'node:path';
|
||||
import readline from 'node:readline';
|
||||
|
||||
/**
|
||||
* @typedef {object} VersionOptions
|
||||
* @property {string|number|null} prettyPrint - A string or number to insert
|
||||
* white space into the output JSON string for readability purposes.
|
||||
* @property {string} versionFormat - The version number format.
|
||||
* @property {string|RegExp} versionKey - Either:
|
||||
* - A string representing the JSON field name assign the version number to.
|
||||
*
|
||||
* Explicit:
|
||||
*
|
||||
* ```json
|
||||
* "key": "json:version"
|
||||
* ```
|
||||
*
|
||||
* Implicit:
|
||||
*
|
||||
* ```json
|
||||
* "key": "version"
|
||||
* ```
|
||||
*
|
||||
* - A `RegExp` object or regular expression string prefixed with `regexp:`.
|
||||
*
|
||||
* ```json
|
||||
* "key": "regexp:(?<=^const ASSETS_VERSION = ')(?<version>\\d+)(?=';$)"
|
||||
* ```
|
||||
*
|
||||
* ```js
|
||||
* key: new RegExp('(?<=^const ASSETS_VERSION = ')(?<version>\\d+)(?=';$)')
|
||||
* ```
|
||||
*
|
||||
* ```js
|
||||
* key: /(?<=^const ASSETS_VERSION = ')(?<version>\d+)(?=';$)/
|
||||
* ```
|
||||
*/
|
||||
|
||||
/**
|
||||
* @const {VersionOptions} defaultVersionOptions - The default shared version options.
|
||||
* @const {VersionOptions} developmentVersionOptions - The predefined version options for development.
|
||||
* @const {VersionOptions} productionVersionOptions - The predefined version options for production.
|
||||
*/
|
||||
export const defaultVersionOptions = {
|
||||
prettyPrint: 4,
|
||||
versionFormat: 'timestamp',
|
||||
versionKey: 'version',
|
||||
};
|
||||
export const developmentVersionOptions = Object.assign({}, defaultVersionOptions);
|
||||
export const productionVersionOptions = Object.assign({}, defaultVersionOptions);
|
||||
|
||||
/**
|
||||
* @const {object} developmentVersionFilesArgs - The predefined `bumpVersion()` options for development.
|
||||
* @const {object} productionVersionFilesArgs - The predefined `bumpVersion()` options for production.
|
||||
*/
|
||||
export const developmentVersionFilesArgs = [
|
||||
developmentVersionOptions,
|
||||
];
|
||||
export const productionVersionFilesArgs = [
|
||||
productionVersionOptions,
|
||||
];
|
||||
|
||||
/**
|
||||
* Bumps version numbers in file.
|
||||
*
|
||||
* @async
|
||||
* @param {object} [versionOptions=null] - Customize the version options.
|
||||
* If `null`, default production options are used.
|
||||
* @return {Promise}
|
||||
*/
|
||||
export default async function bumpVersions(versionOptions = null) {
|
||||
if (versionOptions == null) {
|
||||
versionOptions = productionVersionOptions;
|
||||
} else if (
|
||||
versionOptions !== developmentVersionOptions &&
|
||||
versionOptions !== productionVersionOptions
|
||||
) {
|
||||
versionOptions = Object.assign({}, defaultVersionOptions, versionOptions);
|
||||
}
|
||||
|
||||
const queue = new Map();
|
||||
|
||||
loconfig.tasks.versions.forEach(({
|
||||
outfile,
|
||||
label = null,
|
||||
...options
|
||||
}) => {
|
||||
if (!label) {
|
||||
label = basename(outfile || 'undefined');
|
||||
}
|
||||
|
||||
options.pretty = (options.pretty ?? versionOptions.prettyPrint);
|
||||
options.format = (options.format ?? versionOptions.versionFormat);
|
||||
options.key = (options.key ?? versionOptions.versionKey);
|
||||
|
||||
if (queue.has(outfile)) {
|
||||
queue.get(outfile).then(() => handleBumpVersion(outfile, label, options));
|
||||
} else {
|
||||
queue.set(outfile, handleBumpVersion(outfile, label, options));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a formatted version number or string.
|
||||
*
|
||||
* @param {string} format - The version format.
|
||||
* @return {string|number}
|
||||
*/
|
||||
function createVersionNumber(format) {
|
||||
let [ type, modifier ] = format.split(':', 2);
|
||||
|
||||
switch (type) {
|
||||
case 'hex':
|
||||
case 'hexadecimal':
|
||||
modifier = Number.parseInt(modifier);
|
||||
|
||||
if (Number.isNaN(modifier)) {
|
||||
modifier = 6;
|
||||
}
|
||||
|
||||
return randomBytes(modifier).toString('hex');
|
||||
|
||||
case 'regex':
|
||||
return new RegExp(modifier);
|
||||
|
||||
case 'timestamp':
|
||||
return Date.now().valueOf();
|
||||
}
|
||||
|
||||
throw new TypeError(
|
||||
'Expected \'format\' to be either "timestamp" or "hexadecimal"'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @async
|
||||
* @param {string} outfile
|
||||
* @param {string} label
|
||||
* @param {object} options
|
||||
* @return {Promise}
|
||||
*/
|
||||
async function handleBumpVersion(outfile, label, options) {
|
||||
const timeLabel = `${label} bumped in`;
|
||||
console.time(timeLabel);
|
||||
|
||||
try {
|
||||
options.key = parseVersionKey(options.key);
|
||||
|
||||
if (options.key instanceof RegExp) {
|
||||
await handleBumpVersionWithRegExp(outfile, label, options);
|
||||
} else {
|
||||
await handleBumpVersionInJson(outfile, label, options);
|
||||
}
|
||||
|
||||
message(`${label} bumped`, 'success', timeLabel);
|
||||
} catch (err) {
|
||||
message(`Error bumping ${label}`, 'error');
|
||||
message(err);
|
||||
|
||||
notification({
|
||||
title: `${label} bumping failed 🚨`,
|
||||
message: `${err.name}: ${err.message}`
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the version number for the provided JSON key in file.
|
||||
*
|
||||
* @async
|
||||
* @param {string} outfile
|
||||
* @param {string} label
|
||||
* @param {object} options
|
||||
* @param {string} options.key
|
||||
* @return {Promise}
|
||||
*/
|
||||
async function handleBumpVersionInJson(outfile, label, options) {
|
||||
outfile = resolve(outfile);
|
||||
|
||||
let json;
|
||||
|
||||
try {
|
||||
json = JSON.parse(await readFile(outfile, { encoding: 'utf8' }));
|
||||
} catch (err) {
|
||||
json = {};
|
||||
|
||||
message(`${label} is a new file`, 'notice');
|
||||
|
||||
await mkdir(dirname(outfile), { recursive: true });
|
||||
}
|
||||
|
||||
const version = createVersionNumber(options.format);
|
||||
|
||||
json[options.key] = version;
|
||||
|
||||
return await writeFile(
|
||||
outfile,
|
||||
JSON.stringify(json, null, options.pretty),
|
||||
{ encoding: 'utf8' }
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the version number for the provided RegExp in file.
|
||||
*
|
||||
* @async
|
||||
* @param {string} outfile
|
||||
* @param {string} label
|
||||
* @param {object} options
|
||||
* @param {RegExp} options.key
|
||||
* @return {Promise}
|
||||
*/
|
||||
async function handleBumpVersionWithRegExp(outfile, label, options) {
|
||||
outfile = resolve(outfile);
|
||||
|
||||
const bckfile = `${outfile}~`;
|
||||
|
||||
await rename(outfile, bckfile);
|
||||
|
||||
try {
|
||||
const rl = readline.createInterface({
|
||||
input: createReadStream(bckfile),
|
||||
});
|
||||
|
||||
const version = createVersionNumber(options.format);
|
||||
|
||||
const writeStream = createWriteStream(outfile, { encoding: 'utf8' });
|
||||
|
||||
rl.on('line', (line) => {
|
||||
const found = line.match(options.key);
|
||||
|
||||
if (found) {
|
||||
const groups = (found.groups ?? {});
|
||||
const replace = found[0].replace(
|
||||
(groups.build ?? groups.version ?? found[1] ?? found[0]),
|
||||
version
|
||||
);
|
||||
line = line.replace(found[0], replace);
|
||||
}
|
||||
|
||||
writeStream.write(line + "\n");
|
||||
});
|
||||
|
||||
await events.once(rl, 'close');
|
||||
|
||||
await rm(bckfile);
|
||||
} catch (err) {
|
||||
await rm(outfile, { force: true });
|
||||
|
||||
await rename(bckfile, outfile);
|
||||
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the version key.
|
||||
*
|
||||
* @param {*} key - The version key.
|
||||
* @return {string|RegExp}
|
||||
*/
|
||||
function parseVersionKey(key) {
|
||||
if (key instanceof RegExp) {
|
||||
return key;
|
||||
}
|
||||
|
||||
if (typeof key !== 'string') {
|
||||
throw new TypeError(
|
||||
'Expected \'key\' to be either a string or a RegExp'
|
||||
);
|
||||
}
|
||||
|
||||
const delimiter = key.indexOf(':');
|
||||
|
||||
if (delimiter === -1) {
|
||||
// Assumes its a JSON key
|
||||
return key;
|
||||
}
|
||||
|
||||
const type = key.slice(0, delimiter);
|
||||
const value = key.slice(delimiter + 1);
|
||||
|
||||
switch (type) {
|
||||
case 'json':
|
||||
return value;
|
||||
|
||||
case 'regex':
|
||||
case 'regexp':
|
||||
return new RegExp(value);
|
||||
}
|
||||
|
||||
throw new TypeError(
|
||||
'Expected \'key\' type to be either "json" or "regexp"'
|
||||
);
|
||||
}
|
||||
@@ -2,17 +2,19 @@
|
||||
* @file Provides simple user configuration options.
|
||||
*/
|
||||
|
||||
import loconfig from '../../loconfig.json';
|
||||
import loconfig from '../../loconfig.json' assert { type: 'json' };
|
||||
|
||||
let usrconfig;
|
||||
|
||||
try {
|
||||
usrconfig = await import('../../loconfig.local.json');
|
||||
usrconfig = await import('../../loconfig.local.json', {
|
||||
assert: { type: 'json' }
|
||||
});
|
||||
usrconfig = usrconfig.default;
|
||||
|
||||
merge(loconfig, usrconfig);
|
||||
} catch (err) {
|
||||
// do nothing
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
export default loconfig;
|
||||
|
||||
@@ -17,6 +17,10 @@ export default function message(text, type, timerID) {
|
||||
console.log('✅ ', kleur.bgGreen().black(text));
|
||||
break;
|
||||
|
||||
case 'chore':
|
||||
console.log('🧹 ', kleur.bgGreen().black(text));
|
||||
break;
|
||||
|
||||
case 'notice':
|
||||
console.log('ℹ️ ', kleur.bgBlue().black(text));
|
||||
break;
|
||||
|
||||
@@ -113,7 +113,8 @@ function createServerOptions({
|
||||
}) {
|
||||
const config = {
|
||||
open: false,
|
||||
notify: false
|
||||
notify: false,
|
||||
ghostMode: false
|
||||
};
|
||||
|
||||
// Resolve the URL for the BrowserSync server
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
* [`scripts`](#scripts)
|
||||
* [`styles`](#styles)
|
||||
* [`svgs`](#svgs)
|
||||
* [`versions`](#versions)
|
||||
|
||||
---
|
||||
|
||||
@@ -28,7 +29,9 @@ Learn more about the boilerplate's [tasks](#tasks) below.
|
||||
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.
|
||||
* [NPM] — at least 8.0, the latest LTS is recommended.
|
||||
|
||||
> 💡 You can use [NVM] to install and use different versions of Node via the command-line.
|
||||
|
||||
```sh
|
||||
# Switch to recommended Node version from .nvmrc
|
||||
@@ -262,8 +265,8 @@ 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.
|
||||
A wrapper around [sass] (with optional support for [Autoprefixer]
|
||||
via [PostCSS]) for compiling and minifying Sass into CSS.
|
||||
|
||||
By default, [PostCSS] and [Autoprefixer] are installed with the boilerplate.
|
||||
|
||||
@@ -298,6 +301,9 @@ Example:
|
||||
|
||||
See [`styles.js`](../build/tasks/styles.js) for details.
|
||||
|
||||
The task also supports [PurgeCSS] to remove unused CSS.
|
||||
See the [documentation on our Grid System](grid.md#build-tasks) for details.
|
||||
|
||||
### `svgs`
|
||||
|
||||
A wrapper around [SVG Mixer] for transforming and minifying SVG files
|
||||
@@ -328,6 +334,80 @@ Example:
|
||||
|
||||
See [`svgs.js`](../build/tasks/svgs.js) for details.
|
||||
|
||||
### `versions`
|
||||
|
||||
A task to create and update values for use in versioning assets.
|
||||
|
||||
Can generate a hexadecimal value (using random bytes) or
|
||||
use the current timestamp.
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"versions": [
|
||||
{
|
||||
"format": "timestamp",
|
||||
"key": "now",
|
||||
"outfile": "./assets.json"
|
||||
},
|
||||
{
|
||||
"format": "hex:8",
|
||||
"key": "hex",
|
||||
"outfile": "./assets.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"now": 1665071717350,
|
||||
"hex": "6ef54181c4ba"
|
||||
}
|
||||
```
|
||||
|
||||
The task supports replacing the value of a data key in a JSON file or replacing
|
||||
a string in a file using a [regular expression](RegExp).
|
||||
|
||||
* Explicit JSON field name:
|
||||
```json
|
||||
{
|
||||
"key": "json:version"
|
||||
}
|
||||
```
|
||||
* Implicit JSON field name:
|
||||
```json
|
||||
{
|
||||
"key": "version"
|
||||
}
|
||||
```
|
||||
|
||||
The regular expression can be a `RegExp` object or a pattern prefixed with `regexp:`.
|
||||
|
||||
* ```json
|
||||
{
|
||||
"key": "regexp:(?<=^const ASSETS_VERSION = ')(?<build>\\d+)(?=';$)"
|
||||
}
|
||||
```
|
||||
|
||||
* ```js
|
||||
{
|
||||
key: new RegExp('(?<=^const ASSETS_VERSION = ')(?<version>\\d+)(?=';$)')
|
||||
}
|
||||
```
|
||||
* ```js
|
||||
{
|
||||
key: /^ \* Version: +(?:.+?)\+(.+?)$/
|
||||
}
|
||||
```
|
||||
|
||||
The regular expression pattern will match the first occurrence and replace
|
||||
the first match in the following order: `build` (named capture), `version`
|
||||
(named capture), `1` (first capture), or `0` (whole match).
|
||||
|
||||
See [`versions.js`](../build/tasks/versions.js) for details.
|
||||
|
||||
[Autoprefixer]: https://npmjs.com/package/autoprefixer
|
||||
[BrowserSync]: https://npmjs.com/package/browser-sync
|
||||
[concat]: https://npmjs.com/package/concat
|
||||
@@ -336,9 +416,11 @@ See [`svgs.js`](../build/tasks/svgs.js) for details.
|
||||
[glob]: https://npmjs.com/package/glob
|
||||
[globby]: https://npmjs.com/package/globby
|
||||
[Node]: https://nodejs.org/
|
||||
[node-sass]: https://npmjs.com/package/node-sass
|
||||
[sass]: https://npmjs.com/package/sass
|
||||
[NPM]: https://npmjs.com/
|
||||
[NVM]: https://github.com/nvm-sh/nvm
|
||||
[PostCSS]: https://npmjs.com/package/postcss
|
||||
[PurgeCSS]: https://purgecss.com/
|
||||
[RegExp]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp
|
||||
[SVG Mixer]: https://npmjs.com/package/svg-mixer
|
||||
[tiny-glob]: https://npmjs.com/package/tiny-glob
|
||||
|
||||
109
docs/grid.md
Normal file
109
docs/grid.md
Normal file
@@ -0,0 +1,109 @@
|
||||
# Grid system
|
||||
|
||||
* [Architectures](#architecture)
|
||||
* [Build tasks](#build-tasks)
|
||||
* [Configuration](#configuration)
|
||||
* [Usage](#usage)
|
||||
* [Example](#example)
|
||||
|
||||
## Architecture
|
||||
|
||||
The boilerplate's grid system is meant to be simple and easy to use. The goal is to create a light, flexible, and reusable way to build layouts.
|
||||
The following styles are needed to work properly:
|
||||
|
||||
* [`o-grid`](../assets/styles/objects/_grid.scss) — Object file where the default grid styles are set such as column numbers, modifiers, and options.
|
||||
* [`u-grid-columns`](../assets/styles/utilities/_grid-column.scss) — Utility file that generates the styles for every possible column based on an array of media queries and column numbers.
|
||||
|
||||
### Build tasks
|
||||
|
||||
The columns generated by [`u-grid-columns`](../assets/styles/utilities/_grid-column.scss) adds a lot of styles to the compiled CSS file. To mitigate that, [PurgeCSS] is integrated into the `styles` build task to purge unused CSS.
|
||||
|
||||
#### Configuration
|
||||
|
||||
Depending on your project, you will need to specify all the files that include CSS classes from the grid system. These files will be scanned by [PurgeCSS] to your compiled CSS files.
|
||||
|
||||
Example of a Charcoal project:
|
||||
|
||||
```jsonc
|
||||
"purgeCSS": {
|
||||
"content": [
|
||||
"./views/app/template/**/*.mustache",
|
||||
"./src/App/Template/*.php",
|
||||
"./assets/scripts/**/*" // use case: `el.classList.add('u-gc-1/2')`
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
The first step is to set intial SCSS values in the following files :
|
||||
|
||||
- [`settings/_config.scss`](../assets/styles/settings/_config.scss)
|
||||
|
||||
```scss
|
||||
// Grid
|
||||
// ==========================================================================
|
||||
$base-column-nb: 12;
|
||||
$base-column-gap: $unit-small;
|
||||
```
|
||||
|
||||
You can create multiple column layouts depending on media queries.
|
||||
|
||||
- [`objects/_grid.scss`](../assets/styles/objects/_grid.scss)
|
||||
|
||||
```scss
|
||||
.o-grid {
|
||||
display: grid;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
|
||||
// ==========================================================================
|
||||
// Cols
|
||||
// ==========================================================================
|
||||
&.-col-#{$base-column-nb} {
|
||||
grid-template-columns: repeat(#{$base-column-nb}, 1fr);
|
||||
}
|
||||
|
||||
&.-col-4 {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
}
|
||||
|
||||
&.-col-#{$base-column-nb}\@from-medium {
|
||||
@media (min-width: $from-medium) {
|
||||
grid-template-columns: repeat(#{$base-column-nb}, 1fr);
|
||||
}
|
||||
}
|
||||
// …
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
The following layout has 4 columns at `>=999px` and 12 columns at `<1000px`.
|
||||
|
||||
```html
|
||||
<div class="o-container">
|
||||
<h1 class="c-heading -h1">Hello</h1>
|
||||
|
||||
<div class="o-grid -col-4 -col-12@from-medium -gutters">
|
||||
<div class="o-grid_item u-gc-1/8@from-medium">
|
||||
<h2 class="c-heading -h2">This grid has 4 columns and 12 columns from `medium` MQ</h2>
|
||||
</div>
|
||||
|
||||
<div class="o-grid_item u-gc-1/5@from-medium">
|
||||
<p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Expedita provident distinctio deleniti eaque cumque doloremque aut quo dicta porro commodi, temporibus totam dolor autem tempore quasi ullam sed suscipit vero?</p>
|
||||
</div>
|
||||
|
||||
<div class="o-grid_item u-gc-5/9@from-medium">
|
||||
<p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Expedita provident distinctio deleniti eaque cumque doloremque aut quo dicta porro commodi, temporibus totam dolor autem tempore quasi ullam sed suscipit vero?</p>
|
||||
</div>
|
||||
|
||||
<div class="o-grid_item u-gc-9/13@from-medium">
|
||||
<p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Expedita provident distinctio deleniti eaque cumque doloremque aut quo dicta porro commodi, temporibus totam dolor autem tempore quasi ullam sed suscipit vero?</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
[PurgeCSS]: https://purgecss.com/
|
||||
@@ -19,7 +19,7 @@
|
||||
"dest": "./www/assets/images"
|
||||
},
|
||||
"views": {
|
||||
"src": "./views/boilerplate/template"
|
||||
"src": "./www/"
|
||||
}
|
||||
},
|
||||
"tasks": {
|
||||
@@ -56,6 +56,17 @@
|
||||
],
|
||||
"outfile": "{% paths.svgs.dest %}/sprite.svg"
|
||||
}
|
||||
],
|
||||
"purgeCSS": {
|
||||
"content": [
|
||||
"./www/**/*.html",
|
||||
"./assets/scripts/**/*"
|
||||
]
|
||||
},
|
||||
"versions": [
|
||||
{
|
||||
"outfile": "./assets.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
6525
package-lock.json
generated
6525
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
28
package.json
28
package.json
@@ -6,30 +6,38 @@
|
||||
"author": "Locomotive <info@locomotive.ca>",
|
||||
"type": "module",
|
||||
"engines": {
|
||||
"node": ">=14.17",
|
||||
"npm": ">=6.0"
|
||||
"node": ">=18.13",
|
||||
"npm": ">=8.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node --experimental-json-modules --no-warnings build/watch.js",
|
||||
"build": "node --experimental-json-modules --no-warnings build/build.js"
|
||||
"build": "node --experimental-json-modules --no-warnings build/build.js",
|
||||
"precommit": "prettier --write 'assets/**/*.{js,scss,json}'"
|
||||
},
|
||||
"dependencies": {
|
||||
"locomotive-scroll": "^4.1.4",
|
||||
"modujs": "^1.4.2",
|
||||
"modularload": "^1.2.6",
|
||||
"normalize.css": "^8.0.1",
|
||||
"sass": "^1.57.1",
|
||||
"svg4everybody": "^2.1.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^10.4.4",
|
||||
"browser-sync": "^2.27.9",
|
||||
"autoprefixer": "^10.4.13",
|
||||
"browser-sync": "^2.27.11",
|
||||
"concat": "^1.0.3",
|
||||
"esbuild": "^0.14.27",
|
||||
"kleur": "^4.1.4",
|
||||
"esbuild": "^0.16.17",
|
||||
"kleur": "^4.1.5",
|
||||
"node-notifier": "^10.0.1",
|
||||
"node-sass": "^7.0.1",
|
||||
"postcss": "^8.4.12",
|
||||
"svg-mixer": "^2.3.14",
|
||||
"postcss": "^8.4.21",
|
||||
"prettier": "^2.8.3",
|
||||
"purgecss": "^5.0.0",
|
||||
"svg-mixer": "~2.3.14",
|
||||
"tiny-glob": "^0.2.9"
|
||||
},
|
||||
"overrides": {
|
||||
"svg-mixer": {
|
||||
"postcss": "^8.4.20"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BIN
www/assets/fonts/SourceSans3-Bold.woff2
Normal file
BIN
www/assets/fonts/SourceSans3-Bold.woff2
Normal file
Binary file not shown.
BIN
www/assets/fonts/SourceSans3-BoldIt.woff2
Normal file
BIN
www/assets/fonts/SourceSans3-BoldIt.woff2
Normal file
Binary file not shown.
BIN
www/assets/fonts/SourceSans3-Regular.woff2
Normal file
BIN
www/assets/fonts/SourceSans3-Regular.woff2
Normal file
Binary file not shown.
BIN
www/assets/fonts/SourceSans3-RegularIt.woff2
Normal file
BIN
www/assets/fonts/SourceSans3-RegularIt.woff2
Normal file
Binary file not shown.
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
@@ -25,6 +25,7 @@
|
||||
<ul>
|
||||
<li><a href="images.html">Images</a></li>
|
||||
<li><a href="form.html" data-load="customTransition">Form</a></li>
|
||||
<li><a href="grid.html">Grid</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
96
www/grid.html
Normal file
96
www/grid.html
Normal file
@@ -0,0 +1,96 @@
|
||||
<!doctype html>
|
||||
<html class="is-loading" lang="en" data-page="grid">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Locomotive Boilerplate</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
<meta name="msapplication-TileColor" content="#ffffff">
|
||||
<link rel="manifest" href="site.webmanifest">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="assets/images/favicons/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="assets/images/favicons/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="assets/images/favicons/favicon-16x16.png">
|
||||
<link rel="mask-icon" href="assets/images/favicons/safari-pinned-tab.svg" color="#000000">
|
||||
<!-- For a dark mode managment and svg favicon add this in your favicon.svg -->
|
||||
<!--
|
||||
<style>
|
||||
path {
|
||||
fill: #000;
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
path {
|
||||
fill: #fff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
-->
|
||||
<!-- <link rel="icon" href="assets/images/favicons/favicon.svg"> -->
|
||||
|
||||
<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>
|
||||
<div class="o-scroll" data-module-scroll="main">
|
||||
<header data-scroll-section>
|
||||
<a href="/">
|
||||
<h1>Locomotive Boilerplate</h1>
|
||||
</a>
|
||||
<nav>
|
||||
<ul>
|
||||
<li><a href="images.html">Images</a></li>
|
||||
<li><a href="form.html" data-load="customTransition">Form</a></li>
|
||||
<li><a href="grid.html">Grid</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main data-scroll-section>
|
||||
<div class="o-container">
|
||||
<h1 class="c-heading -h1">Hello</h1>
|
||||
|
||||
<div class="o-grid -col-4 -col-12@from-medium -gutters">
|
||||
<div class="o-grid_item u-gc-1/8@from-medium" style="background-color: gray;">
|
||||
<h2 class="c-heading -h2">This grid has 4 columns and 12 columns from `medium` MQ</h2>
|
||||
</div>
|
||||
|
||||
<div class="o-grid_item u-gc-1/5@from-medium" style="background-color: yellow;">
|
||||
<p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Expedita provident distinctio deleniti eaque cumque doloremque aut quo dicta porro commodi, temporibus totam dolor autem tempore quasi ullam sed suscipit vero?</p>
|
||||
</div>
|
||||
|
||||
<div class="o-grid_item u-gc-5/9@from-medium" style="background-color: red;">
|
||||
<p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Expedita provident distinctio deleniti eaque cumque doloremque aut quo dicta porro commodi, temporibus totam dolor autem tempore quasi ullam sed suscipit vero?</p>
|
||||
</div>
|
||||
|
||||
<div class="o-grid_item u-gc-9/13@from-medium" style="background-color: blue;">
|
||||
<p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Expedita provident distinctio deleniti eaque cumque doloremque aut quo dicta porro commodi, temporibus totam dolor autem tempore quasi ullam sed suscipit vero?</p>
|
||||
</div>
|
||||
|
||||
<div class="o-grid_item u-gc-1/3 u-gc-5/13@from-medium" style="background-color: pink;">
|
||||
<p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Expedita provident distinctio deleniti eaque cumque doloremque aut quo dicta porro commodi, temporibus totam dolor autem tempore quasi ullam sed suscipit vero?</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer data-scroll-section>
|
||||
<p>Made with <a href="https://github.com/locomotivemtl/locomotive-boilerplate"
|
||||
title="Locomotive Boilerplate" target="_blank" rel="noopener">🚂</a></p>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script nomodule src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/7.6.0/polyfill.min.js"
|
||||
crossorigin="anonymous"></script>
|
||||
<script nomodule
|
||||
src="https://polyfill.io/v3/polyfill.min.js?features=Element.prototype.remove%2CElement.prototype.append%2Cfetch%2CCustomEvent%2CElement.prototype.matches%2CNodeList.prototype.forEach%2CAbortController"
|
||||
crossorigin="anonymous"></script>
|
||||
|
||||
<script src="assets/scripts/vendors.js" defer></script>
|
||||
<script src="assets/scripts/app.js" defer></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -25,6 +25,7 @@
|
||||
<ul>
|
||||
<li><a href="images.html">Images</a></li>
|
||||
<li><a href="form.html" data-load="customTransition">Form</a></li>
|
||||
<li><a href="grid.html">Grid</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
@@ -39,8 +40,8 @@
|
||||
<h3 class="c-heading -h3">Basic</h3>
|
||||
|
||||
<div style="width: 640px; max-width: 100%;">
|
||||
<div class="o-ratio u-4:3"><img data-load-src="http://picsum.photos/640/480?v=1" alt="" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" /></div>
|
||||
<div class="o-ratio u-4:3"><img data-load-src="http://picsum.photos/640/480?v=2" alt="" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" /></div>
|
||||
<div class="o-ratio u-4:3"><img data-load-src="http://picsum.photos/800/600?v=1" alt="" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" /></div>
|
||||
<div class="o-ratio u-4:3"><img data-load-src="http://picsum.photos/800/600?v=2" alt="" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" /></div>
|
||||
</div>
|
||||
|
||||
<h4 class="c-heading -h3">Using o-ratio & background-image</h3>
|
||||
@@ -58,30 +59,30 @@
|
||||
|
||||
<div style="width: 640px; max-width: 100%;">
|
||||
<div class="o-ratio u-4:3">
|
||||
<img data-scroll data-scroll-call="lazyLoad, Scroll, main" data-src="http://picsum.photos/640/480?v=1" alt="" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" />
|
||||
<img data-scroll data-scroll-call="lazyLoad, Scroll, main" data-src="http://picsum.photos/800/600?v=1" alt="" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" />
|
||||
</div>
|
||||
<div class="o-ratio u-4:3">
|
||||
<img data-scroll data-scroll-call="lazyLoad, Scroll, main" data-src="http://picsum.photos/640/480?v=2" alt="" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" />
|
||||
<img data-scroll data-scroll-call="lazyLoad, Scroll, main" data-src="http://picsum.photos/800/600?v=2" alt="" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" />
|
||||
</div>
|
||||
<div class="o-ratio u-4:3">
|
||||
<img data-scroll data-scroll-call="lazyLoad, Scroll, main" data-src="http://picsum.photos/640/480?v=3" alt="" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" />
|
||||
<img data-scroll data-scroll-call="lazyLoad, Scroll, main" data-src="http://picsum.photos/800/600?v=3" alt="" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" />
|
||||
</div>
|
||||
<div class="o-ratio u-4:3">
|
||||
<img data-scroll data-scroll-call="lazyLoad, Scroll, main" data-src="http://picsum.photos/640/480?v=4" alt="" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" />
|
||||
<img data-scroll data-scroll-call="lazyLoad, Scroll, main" data-src="http://picsum.photos/800/600?v=4" alt="" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" />
|
||||
</div>
|
||||
<div class="o-ratio u-4:3">
|
||||
<img data-scroll data-scroll-call="lazyLoad, Scroll, main" data-src="http://picsum.photos/640/480?v=5" alt="" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" />
|
||||
<img data-scroll data-scroll-call="lazyLoad, Scroll, main" data-src="http://picsum.photos/800/600?v=5" alt="" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4 class="c-heading -h3">Using o-ratio & background-image</h3>
|
||||
|
||||
<div style="width: 480px; max-width: 100%;">
|
||||
<div style="background-size: cover; background-position: center;" class="o-ratio u-16:9" data-scroll data-scroll-call="lazyLoad, Scroll, main" data-src="http://picsum.photos/640/480?v=1"></div>
|
||||
<div style="background-size: cover; background-position: center;" class="o-ratio u-16:9" data-scroll data-scroll-call="lazyLoad, Scroll, main" data-src="http://picsum.photos/640/480?v=2"></div>
|
||||
<div style="background-size: cover; background-position: center;" class="o-ratio u-16:9" data-scroll data-scroll-call="lazyLoad, Scroll, main" data-src="http://picsum.photos/640/480?v=3"></div>
|
||||
<div style="background-size: cover; background-position: center;" class="o-ratio u-16:9" data-scroll data-scroll-call="lazyLoad, Scroll, main" data-src="http://picsum.photos/640/480?v=4"></div>
|
||||
<div style="background-size: cover; background-position: center;" class="o-ratio u-16:9" data-scroll data-scroll-call="lazyLoad, Scroll, main" data-src="http://picsum.photos/640/480?v=5"></div>
|
||||
<div style="background-size: cover; background-position: center;" class="o-ratio u-16:9" data-scroll data-scroll-call="lazyLoad, Scroll, main" data-src="http://picsum.photos/1280/720?v=1"></div>
|
||||
<div style="background-size: cover; background-position: center;" class="o-ratio u-16:9" data-scroll data-scroll-call="lazyLoad, Scroll, main" data-src="http://picsum.photos/1280/720?v=2"></div>
|
||||
<div style="background-size: cover; background-position: center;" class="o-ratio u-16:9" data-scroll data-scroll-call="lazyLoad, Scroll, main" data-src="http://picsum.photos/1280/720?v=3"></div>
|
||||
<div style="background-size: cover; background-position: center;" class="o-ratio u-16:9" data-scroll data-scroll-call="lazyLoad, Scroll, main" data-src="http://picsum.photos/1280/720?v=4"></div>
|
||||
<div style="background-size: cover; background-position: center;" class="o-ratio u-16:9" data-scroll data-scroll-call="lazyLoad, Scroll, main" data-src="http://picsum.photos/1280/720?v=5"></div>
|
||||
</div>
|
||||
|
||||
<h4 class="c-heading -h3">Using SVG viewport for ratio</h3>
|
||||
|
||||
@@ -29,11 +29,18 @@
|
||||
-->
|
||||
<!-- <link rel="icon" href="assets/images/favicons/favicon.svg"> -->
|
||||
|
||||
<!-- Preload Fonts -->
|
||||
<link rel="preload" href="assets/fonts/SourceSans3-Bold.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="preload" href="assets/fonts/SourceSans3-BoldIt.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="preload" href="assets/fonts/SourceSans3-Regular.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="preload" href="assets/fonts/SourceSans3-RegularIt.woff2" as="font" type="font/woff2" crossorigin>
|
||||
|
||||
<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>
|
||||
<div class="o-scroll" data-module-scroll="main">
|
||||
<header data-scroll-section>
|
||||
@@ -44,11 +51,12 @@
|
||||
<ul>
|
||||
<li><a href="images.html">Images</a></li>
|
||||
<li><a href="form.html" data-load="customTransition">Form</a></li>
|
||||
<li><a href="grid.html">Grid</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main data-scroll-section>
|
||||
<main data-module-example data-scroll-section>
|
||||
<div class="o-container">
|
||||
<h1 class="c-heading -h1">Hello</h1>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user