mirror of
https://github.com/locomotivemtl/locomotive-boilerplate.git
synced 2026-01-15 00:55:08 +08:00
Merge branch 'master' into feature/es6-updates
This commit is contained in:
@@ -15,6 +15,7 @@
|
|||||||
* Uses [SVG Mixer] for processing SVG files and generating spritesheets.
|
* Uses [SVG Mixer] for processing SVG files and generating spritesheets.
|
||||||
* Uses [ITCSS] for a sane and scalable CSS architecture.
|
* Uses [ITCSS] for a sane and scalable CSS architecture.
|
||||||
* Uses [Locomotive Scroll] for smooth scrolling with parallax effects.
|
* 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).
|
Learn more about [languages and technologies](docs/technologies.md).
|
||||||
|
|
||||||
@@ -84,6 +85,7 @@ Learn more about [development and building](docs/development.md).
|
|||||||
|
|
||||||
* [Development and building](docs/development.md)
|
* [Development and building](docs/development.md)
|
||||||
* [Languages and technologies](docs/technologies.md)
|
* [Languages and technologies](docs/technologies.md)
|
||||||
|
* [Grid system](docs/grid.md)
|
||||||
|
|
||||||
[BrowserSync]: https://npmjs.com/package/browser-sync
|
[BrowserSync]: https://npmjs.com/package/browser-sync
|
||||||
[ESBuild]: https://npmjs.com/package/esbuild
|
[ESBuild]: https://npmjs.com/package/esbuild
|
||||||
|
|||||||
0
assets/images/sprite/.gitkeep
Normal file
0
assets/images/sprite/.gitkeep
Normal file
@@ -3,6 +3,7 @@ import * as modules from './modules';
|
|||||||
import globals from './globals';
|
import globals from './globals';
|
||||||
import { html } from './utils/environment';
|
import { html } from './utils/environment';
|
||||||
import config from './config'
|
import config from './config'
|
||||||
|
import { isFontLoadingAPIAvailable, loadFonts } from './utils/fonts';
|
||||||
|
|
||||||
const app = new modular({
|
const app = new modular({
|
||||||
modules: modules
|
modules: modules
|
||||||
@@ -24,6 +25,11 @@ window.onload = (event) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const EAGER_FONTS = [
|
||||||
|
{ family: 'Source Sans', style: 'normal', weight: 400 },
|
||||||
|
{ family: 'Source Sans', style: 'normal', weight: 700 },
|
||||||
|
];
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
globals();
|
globals();
|
||||||
|
|
||||||
@@ -32,5 +38,21 @@ function init() {
|
|||||||
html.classList.add(config.CSS_CLASS.LOADED);
|
html.classList.add(config.CSS_CLASS.LOADED);
|
||||||
html.classList.add(config.CSS_CLASS.READY);
|
html.classList.add(config.CSS_CLASS.READY);
|
||||||
html.classList.remove(config.CSS_CLASS.LOADING);
|
html.classList.remove(config.CSS_CLASS.LOADING);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Eagerly load the following fonts.
|
||||||
|
*/
|
||||||
|
if (isFontLoadingAPIAvailable) {
|
||||||
|
loadFonts(EAGER_FONTS).then((eagerFonts) => {
|
||||||
|
html.classList.add('fonts-loaded');
|
||||||
|
// 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()
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
|
export {default as Example} from './modules/Example';
|
||||||
export {default as Load} from './modules/Load';
|
export {default as Load} from './modules/Load';
|
||||||
export {default as Scroll} from './modules/Scroll';
|
export {default as Scroll} from './modules/Scroll';
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import { module } from 'modujs';
|
import { 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) {
|
constructor(m) {
|
||||||
@@ -6,5 +8,10 @@ export default class extends module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
|
whenReady(EAGER_FONTS).then((fonts) => this.onFontsLoaded(fonts));
|
||||||
|
}
|
||||||
|
|
||||||
|
onFontsLoaded(fonts) {
|
||||||
|
console.log('Example: Eager Fonts Loaded!', fonts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
402
assets/scripts/utils/fonts.js
Normal file
402
assets/scripts/utils/fonts.js
Normal file
@@ -0,0 +1,402 @@
|
|||||||
|
/**
|
||||||
|
* 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,
|
||||||
|
}
|
||||||
@@ -1,129 +1,118 @@
|
|||||||
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');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a callback
|
* The `PageVisibility` interface provides support for dispatching
|
||||||
* @param {string} state
|
* a custom event derived from the value of {@see document.visibilityState}
|
||||||
* @param {function} callback
|
* when the "visibilitychange" event is fired.
|
||||||
* @return {string} ident
|
*
|
||||||
|
* 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}
|
||||||
*/
|
*/
|
||||||
function addCallback (state, options) {
|
export default new class PageVisibility {
|
||||||
let callback = options.callback || '';
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
if (!isFunction(callback)) {
|
|
||||||
console.warn('Callback is not a function');
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let ident = PREFIX + UUID++;
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
CALLBACKS[state].push({
|
|
||||||
ident: ident,
|
|
||||||
callback: callback
|
|
||||||
});
|
|
||||||
|
|
||||||
return ident;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a callback
|
|
||||||
* @param {string} state Visible or hidden
|
|
||||||
* @param {string} ident Unique identifier
|
|
||||||
* @return {boolean} If operation was a success
|
|
||||||
*/
|
|
||||||
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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When document state changes, trigger callbacks
|
* Tracks whether custom visibility event types
|
||||||
* @param {string} state Visible or hidden
|
* are available (`true`) or not (`false`).
|
||||||
|
*
|
||||||
|
* @type {boolean}
|
||||||
*/
|
*/
|
||||||
function onDocumentChange (state) {
|
let isVisibilityChangeObserved = false;
|
||||||
let callbackArray = CALLBACKS[state];
|
|
||||||
let i = 0;
|
|
||||||
let len = callbackArray.length;
|
|
||||||
|
|
||||||
for (; i < len; i++) {
|
/**
|
||||||
callbackArray[i].callback();
|
* 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
|
||||||
|
}
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Public facing API for adding and removing callbacks
|
* The "visibilityhidden" eveent is fired at the document when the contents
|
||||||
* @param {object} options Options
|
* of its tab have become hidden.
|
||||||
* @return {boolean|integer} Unique identifier for the callback or boolean indicating success or failure
|
*
|
||||||
|
* @event PageVisibility#visibilityhidden
|
||||||
|
* @type {Event}
|
||||||
*/
|
*/
|
||||||
function visibilityApi (options) {
|
|
||||||
let action = options.action || '';
|
|
||||||
let state = options.state || '';
|
|
||||||
let ret;
|
|
||||||
|
|
||||||
// Type and value checking
|
/**
|
||||||
if (!arrayContains(ACTIONS, action)) {
|
* The "visibilityvisible" eveent is fired at the document when the contents
|
||||||
console.warn('Action does not exist');
|
* of its tab have become visible.
|
||||||
return false;
|
*
|
||||||
}
|
* @event PageVisibility#visibilityvisible
|
||||||
if (!arrayContains(STATES, state)) {
|
* @type {Event}
|
||||||
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 };
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ $input-icon-color: 424242; // No #
|
|||||||
.c-form_input {
|
.c-form_input {
|
||||||
padding: rem(10px);
|
padding: rem(10px);
|
||||||
border: 1px solid lightgray;
|
border: 1px solid lightgray;
|
||||||
background-color: white;
|
background-color: $color-lightest;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
border-color: darkgray;
|
border-color: darkgray;
|
||||||
@@ -71,7 +71,7 @@ $checkbox-icon-color: $input-icon-color;
|
|||||||
}
|
}
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
background-color: $white;
|
background-color: $color-lightest;
|
||||||
border: 1px solid lightgray;
|
border: 1px solid lightgray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
background-color: black;
|
background-color: $color-darkest;
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
width: 7px;
|
width: 7px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ html {
|
|||||||
min-height: 100%; // [2]
|
min-height: 100%; // [2]
|
||||||
line-height: $line-height;
|
line-height: $line-height;
|
||||||
font-family: ff("sans");
|
font-family: ff("sans");
|
||||||
color: $color;
|
color: $font-color;
|
||||||
line-height: $line-height; // [3]
|
line-height: $line-height; // [3]
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
@@ -74,9 +74,9 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: $link-color;
|
color: $color-link;
|
||||||
|
|
||||||
@include u-hocus {
|
@include u-hocus {
|
||||||
color: $link-hover-color;
|
color: $color-link-hover;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ i {
|
|||||||
|
|
||||||
b,
|
b,
|
||||||
strong {
|
strong {
|
||||||
font-weight: $bold;
|
font-weight: $font-weight-bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
|
|||||||
@@ -13,11 +13,12 @@
|
|||||||
// Tools
|
// Tools
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
|
@import "tools/maths";
|
||||||
@import "tools/functions";
|
@import "tools/functions";
|
||||||
@import "tools/mixins";
|
@import "tools/mixins";
|
||||||
@import "tools/fonts";
|
@import "tools/fonts";
|
||||||
@import "tools/layout";
|
// @import "tools/layout";
|
||||||
@import "tools/widths";
|
// @import "tools/widths";
|
||||||
// @import "tools/family";
|
// @import "tools/family";
|
||||||
|
|
||||||
// Generic
|
// Generic
|
||||||
@@ -40,7 +41,9 @@
|
|||||||
@import "objects/scroll";
|
@import "objects/scroll";
|
||||||
@import "objects/container";
|
@import "objects/container";
|
||||||
@import "objects/ratio";
|
@import "objects/ratio";
|
||||||
@import "objects/layout";
|
@import "objects/icons";
|
||||||
|
@import "objects/grid";
|
||||||
|
// @import "objects/layout";
|
||||||
// @import "objects/crop";
|
// @import "objects/crop";
|
||||||
// @import "objects/table";
|
// @import "objects/table";
|
||||||
|
|
||||||
@@ -56,15 +59,12 @@
|
|||||||
@import "components/button";
|
@import "components/button";
|
||||||
@import "components/form";
|
@import "components/form";
|
||||||
|
|
||||||
// Templates
|
|
||||||
// ==========================================================================
|
|
||||||
// @import "templates/template";
|
|
||||||
|
|
||||||
// Utilities
|
// Utilities
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
@import "utilities/ratio";
|
@import "utilities/ratio";
|
||||||
@import "utilities/widths";
|
@import "utilities/grid-column";
|
||||||
|
// @import "utilities/widths";
|
||||||
// @import "utilities/align";
|
// @import "utilities/align";
|
||||||
// @import "utilities/helpers";
|
// @import "utilities/helpers";
|
||||||
// @import "utilities/states";
|
// @import "utilities/states";
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
.o-container {
|
.o-container {
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
padding-right: rem($padding);
|
padding-right: $base-column-gap;
|
||||||
padding-left: rem($padding);
|
padding-left: $base-column-gap;
|
||||||
max-width: rem($container-width + ($padding * 2));
|
|
||||||
}
|
}
|
||||||
|
|||||||
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
58
assets/styles/objects/_icons.scss
Normal file
58
assets/styles/objects/_icons.scss
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
// ==========================================================================
|
||||||
|
// 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)};
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
@@ -5,25 +5,25 @@
|
|||||||
// Palette
|
// Palette
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
$white: #FFFFFF;
|
$color-lightest: #FFFFFF;
|
||||||
$black: #000000;
|
$color-darkest: #000000;
|
||||||
|
|
||||||
// Specific
|
// Specific
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
// Link
|
// Link
|
||||||
$link-color: #1A0DAB;
|
$color-link: #1A0DAB;
|
||||||
$link-focus-color: #1A0DAB;
|
$color-link-focus: #1A0DAB;
|
||||||
$link-hover-color: darken(#1A0DAB, 10%);
|
$color-link-hover: darken(#1A0DAB, 10%);
|
||||||
|
|
||||||
// Selection
|
// Selection
|
||||||
$selection-text-color: #3297FD;
|
$selection-text-color: #3297FD;
|
||||||
$selection-background-color: #FFFFFF;
|
$selection-background-color: #FFFFFF;
|
||||||
|
|
||||||
// Social Colors
|
// Social Colors
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
$facebook-color: #3B5998;
|
$color-facebook: #3B5998;
|
||||||
$instagram-color: #E1306C;
|
$color-instagram: #E1306C;
|
||||||
$youtube-color: #CD201F;
|
$color-youtube: #CD201F;
|
||||||
$twitter-color: #1DA1F2;
|
$color-twitter: #1DA1F2;
|
||||||
|
|||||||
@@ -2,22 +2,47 @@
|
|||||||
// Settings / Config / Eases
|
// Settings / Config / Eases
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
$Power1EaseOut: cubic-bezier(0.250, 0.460, 0.450, 0.940);
|
// Power 1
|
||||||
$Power2EaseOut: cubic-bezier(0.215, 0.610, 0.355, 1.000);
|
$ease-power1-in: cubic-bezier(0.550, 0.085, 0.680, 0.530);
|
||||||
$Power3EaseOut: cubic-bezier(0.165, 0.840, 0.440, 1.000);
|
$ease-power1-out: cubic-bezier(0.250, 0.460, 0.450, 0.940);
|
||||||
$Power4EaseOut: cubic-bezier(0.230, 1.000, 0.320, 1.000);
|
$ease-power1-in-out: cubic-bezier(0.455, 0.030, 0.515, 0.955);
|
||||||
$Power1EaseIn: cubic-bezier(0.550, 0.085, 0.680, 0.530) ;
|
|
||||||
$Power2EaseIn: cubic-bezier(0.550, 0.055, 0.675, 0.190);
|
// Power 2
|
||||||
$Power3EaseIn: cubic-bezier(0.895, 0.030, 0.685, 0.220);
|
$ease-power2-in: cubic-bezier(0.550, 0.055, 0.675, 0.190);
|
||||||
$Power4EaseIn: cubic-bezier(0.755, 0.050, 0.855, 0.060);
|
$ease-power2-out: cubic-bezier(0.215, 0.610, 0.355, 1.000);
|
||||||
$ExpoEaseOut: cubic-bezier(0.190, 1.000, 0.220, 1.000);
|
$ease-power2-in-out: cubic-bezier(0.645, 0.045, 0.355, 1.000);
|
||||||
$ExpoEaseIn: cubic-bezier(0.950, 0.050, 0.795, 0.035);
|
|
||||||
$ExpoEaseInOut: cubic-bezier(1.000, 0.000, 0.000, 1.000);
|
// Power 3
|
||||||
$SineEaseOut: cubic-bezier(0.390, 0.575, 0.565, 1.000);
|
$ease-power3-in: cubic-bezier(0.895, 0.030, 0.685, 0.220);
|
||||||
$SineEaseIn: cubic-bezier(0.470, 0.000, 0.745, 0.715);
|
$ease-power3-out: cubic-bezier(0.165, 0.840, 0.440, 1.000);
|
||||||
$Power1EaseInOut: cubic-bezier(0.455, 0.030, 0.515, 0.955);
|
$ease-power3-in-out: cubic-bezier(0.770, 0.000, 0.175, 1.000);
|
||||||
$Power2EaseInOut: cubic-bezier(0.645, 0.045, 0.355, 1.000);
|
|
||||||
$Power3EaseInOut: cubic-bezier(0.770, 0.000, 0.175, 1.000);
|
// Power 3
|
||||||
$Power4EaseInOut: cubic-bezier(0.860, 0.000, 0.070, 1.000);
|
$ease-power4-in: cubic-bezier(0.755, 0.050, 0.855, 0.060);
|
||||||
$SlowEaseOut: cubic-bezier(.04,1.15,0.4,.99);
|
$ease-power4-out: cubic-bezier(0.230, 1.000, 0.320, 1.000);
|
||||||
$bounce: cubic-bezier(0.17, 0.67, 0.3, 1.33);
|
$ease-power4-in-out: cubic-bezier(0.860, 0.000, 0.070, 1.000);
|
||||||
|
|
||||||
|
// Expo
|
||||||
|
$ease-expo-in: cubic-bezier(0.950, 0.050, 0.795, 0.035);
|
||||||
|
$ease-expo-out: cubic-bezier(0.190, 1.000, 0.220, 1.000);
|
||||||
|
$ease-expo-in-out: cubic-bezier(1.000, 0.000, 0.000, 1.000);
|
||||||
|
|
||||||
|
// Back
|
||||||
|
$ease-back-in: cubic-bezier(0.600, -0.280, 0.735, 0.045);
|
||||||
|
$ease-back-out: cubic-bezier(0.175, 00.885, 0.320, 1.275);
|
||||||
|
$ease-back-in-out: cubic-bezier(0.680, -0.550, 0.265, 1.550);
|
||||||
|
|
||||||
|
// Sine
|
||||||
|
$ease-sine-in: cubic-bezier(0.470, 0.000, 0.745, 0.715);
|
||||||
|
$ease-sine-out: cubic-bezier(0.390, 0.575, 0.565, 1.000);
|
||||||
|
$ease-sine-in-out: cubic-bezier(0.445, 0.050, 0.550, 0.950);
|
||||||
|
|
||||||
|
// Circ
|
||||||
|
$ease-circ-in: cubic-bezier(0.600, 0.040, 0.980, 0.335);
|
||||||
|
$ease-circ-out: cubic-bezier(0.075, 0.820, 0.165, 1.000);
|
||||||
|
$ease-circ-in-out: cubic-bezier(0.785, 0.135, 0.150, 0.860);
|
||||||
|
|
||||||
|
// Misc
|
||||||
|
$ease-bounce: cubic-bezier(0.17, 0.67, 0.3, 1.33);
|
||||||
|
$ease-slow-out: cubic-bezier(.04,1.15,0.4,.99);
|
||||||
|
$ease-smooth: cubic-bezier(0.380, 0.005, 0.215, 1);
|
||||||
|
|||||||
@@ -14,26 +14,42 @@ $assets-path: "../" !default;
|
|||||||
// Typefaces
|
// Typefaces
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
|
// Font directory
|
||||||
$font-dir: "../fonts/";
|
$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: (
|
$font-families: (
|
||||||
"sans": ("Webfont Sans", "Helvetica Neue", Arial, sans-serif),
|
sans: join(Source Sans, $font-fallback-sans, $separator: comma),
|
||||||
// "serif": ("Webfont Serif", Georgia, serif)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// List of custom font faces as tuples.
|
||||||
|
//
|
||||||
|
// ```
|
||||||
|
// <font-name> <font-file-basename> <font-weight> <font-style>
|
||||||
|
// ```
|
||||||
$font-faces: (
|
$font-faces: (
|
||||||
// "Webfont Sans" "webfont-sans_regular" 400 normal,
|
(Source Sans, "SourceSans3-Bold", 700, normal),
|
||||||
// "Webfont Sans" "webfont-sans_regular-italic" 400 italic,
|
(Source Sans, "SourceSans3-BoldIt", 700, italic),
|
||||||
// "Webfont Serif" "webfont-sans_bold" 700 normal,
|
(Source Sans, "SourceSans3-Regular", 400, normal),
|
||||||
|
(Source Sans, "SourceSans3-RegularIt", 400, italic),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Typography
|
// Typography
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
// Base
|
// Base
|
||||||
$font-size: 16px;
|
$font-size: 16px;
|
||||||
$line-height: 24px / $font-size;
|
$line-height: 24px / $font-size;
|
||||||
$color: #222222;
|
$font-color: $color-darkest;
|
||||||
|
|
||||||
// Headings
|
// Headings
|
||||||
$font-size-h1: 36px !default;
|
$font-size-h1: 36px !default;
|
||||||
@@ -45,29 +61,31 @@ $font-size-h6: 16px !default;
|
|||||||
$line-height-h: $line-height;
|
$line-height-h: $line-height;
|
||||||
|
|
||||||
// Weights
|
// Weights
|
||||||
$light: 300;
|
$font-weight-light: 300;
|
||||||
$normal: 400;
|
$font-weight-normal: 400;
|
||||||
$medium: 500;
|
$font-weight-medium: 500;
|
||||||
$bold: 700;
|
$font-weight-bold: 700;
|
||||||
|
|
||||||
// Transitions
|
// Transitions
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
$speed: 0.3s;
|
$speed: 0.3s;
|
||||||
$easing: $Power2EaseOut;
|
$easing: $ease-power2-out;
|
||||||
|
|
||||||
// Spacing Units
|
// Spacing Units
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
$unit: 60px;
|
$unit: 60px;
|
||||||
$unit-small: 30px;
|
$unit-small: 20px;
|
||||||
|
|
||||||
// Container
|
// Container
|
||||||
// =============================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
$container-width: 2000px;
|
|
||||||
$padding: $unit;
|
$padding: $unit;
|
||||||
|
|
||||||
|
// Grid
|
||||||
|
// ==========================================================================
|
||||||
|
$base-column-nb: 12;
|
||||||
|
$base-column-gap: $unit-small;
|
||||||
|
|
||||||
// Breakpoints
|
// Breakpoints
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
@@ -89,3 +107,12 @@ $from-gigantic: 2000px !default;
|
|||||||
$to-gigantic: $from-gigantic - 1 !default;
|
$to-gigantic: $from-gigantic - 1 !default;
|
||||||
$from-colossal: 2400px !default;
|
$from-colossal: 2400px !default;
|
||||||
$to-colossal: $from-colossal - 1 !default;
|
$to-colossal: $from-colossal - 1 !default;
|
||||||
|
|
||||||
|
// Master z-indexe
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
$z-indexes: (
|
||||||
|
"header": 200,
|
||||||
|
"above": 1,
|
||||||
|
"below": -1
|
||||||
|
);
|
||||||
|
|||||||
@@ -2,11 +2,14 @@
|
|||||||
// Tools / Font Faces
|
// Tools / Font Faces
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
// Import the webfont with font-face as woff and woff2
|
// Imports the custom font.
|
||||||
//
|
//
|
||||||
// @param {List} $webfont (font name, filename, font-weight, font-style) - Each webfont to import.
|
// The mixin expects font files to be woff and woff2.
|
||||||
// @param {String} $dir - The webfont directory path
|
//
|
||||||
// @output void
|
// @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.
|
||||||
|
|
||||||
@mixin font-face($webfont, $dir) {
|
@mixin font-face($webfont, $dir) {
|
||||||
@font-face {
|
@font-face {
|
||||||
@@ -19,27 +22,39 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loops through a list of local fonts and import each font-face as woff and woff2
|
// Imports the list of custom fonts.
|
||||||
//
|
//
|
||||||
// @param {List} $webfonts [(font name, filename, font-weight, font-style)] - Each webfont to import.
|
// @require {mixin} font-face
|
||||||
// @param {String} $dir - The webfont directory path
|
//
|
||||||
// @output void
|
// @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) {
|
@mixin font-faces($webfonts, $dir) {
|
||||||
@each $webfont in $webfonts {
|
@if (length($webfonts) > 0) {
|
||||||
@include font-face($webfont, $dir);
|
@if (type-of(nth($webfonts, 1)) == "list") {
|
||||||
|
@each $webfont in $webfonts {
|
||||||
|
@include font-face($webfont, $dir);
|
||||||
|
}
|
||||||
|
} @else {
|
||||||
|
@include font-face($webfonts, $dir);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map the font-family requires with the existing imported font-families
|
// Retrieves the font family stack for the given font ID.
|
||||||
//
|
//
|
||||||
// @param {String} $font-family - The name of the webfont.
|
// @require {variable} $font-families - See settings directory.
|
||||||
// @return {String} The webfont and it's fallbacks.
|
//
|
||||||
|
// @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) {
|
@function ff($font-family) {
|
||||||
@if not map-has-key($font-families, $font-family) {
|
@if not map-has-key($font-families, $font-family) {
|
||||||
@error "No font-family found in $font-families map for `#{$font-family}`. Property omitted.";
|
@error "No font-family found in $font-families map for `#{$font-family}`.";
|
||||||
}
|
}
|
||||||
|
|
||||||
$value: map-get($font-families, $font-family);
|
$value: map-get($font-families, $font-family);
|
||||||
@return $value;
|
@return $value;
|
||||||
|
|||||||
@@ -2,6 +2,15 @@
|
|||||||
// Tools / Functions
|
// 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.
|
// Converts the given pixel value to its EM quivalent.
|
||||||
//
|
//
|
||||||
// @param {Number} $size - The pixel value to convert.
|
// @param {Number} $size - The pixel value to convert.
|
||||||
@@ -9,20 +18,12 @@
|
|||||||
// @return {Number} Scalable pixel value in EMs.
|
// @return {Number} Scalable pixel value in EMs.
|
||||||
|
|
||||||
@function em($size, $base: $font-size) {
|
@function em($size, $base: $font-size) {
|
||||||
@if (type-of($size) == number) {
|
@if not is-pixel-number($size) {
|
||||||
@if (unit($size) != "px") {
|
@error "`#{$size}` needs to be a number in pixel.";
|
||||||
@error "`#{$size}` needs to be a pixel value.";
|
|
||||||
}
|
|
||||||
} @else {
|
|
||||||
@error "`#{$size}` needs to be a number.";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@if (type-of($base) == number) {
|
@if not is-pixel-number($base) {
|
||||||
@if (unit($base) != "px") {
|
@error "`#{$base}` needs to be a number in pixel.";
|
||||||
@error "`#{$base}` needs to be a pixel value.";
|
|
||||||
}
|
|
||||||
} @else {
|
|
||||||
@error "`#{$base}` needs to be a number.";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@return ($size / $base) * 1em;
|
@return ($size / $base) * 1em;
|
||||||
@@ -35,25 +36,43 @@
|
|||||||
// @return {Number} Scalable pixel value in REMs.
|
// @return {Number} Scalable pixel value in REMs.
|
||||||
|
|
||||||
@function rem($size, $base: $font-size) {
|
@function rem($size, $base: $font-size) {
|
||||||
@if (type-of($size) == number) {
|
|
||||||
@if (unit($size) != "px") {
|
@if not is-pixel-number($size) {
|
||||||
@error "`#{$size}` needs to be a pixel value.";
|
@error "`#{$size}` needs to be a number in pixel.";
|
||||||
}
|
|
||||||
} @else {
|
|
||||||
@error "`#{$size}` needs to be a number.";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@if (type-of($base) == number) {
|
@if not is-pixel-number($base) {
|
||||||
@if (unit($base) != "px") {
|
@error "`#{$base}` needs to be a number in pixel.";
|
||||||
@error "`#{$base}` needs to be a pixel value.";
|
|
||||||
}
|
|
||||||
} @else {
|
|
||||||
@error "`#{$base}` needs to be a number.";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@return ($size / $base) * 1rem;
|
@return ($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.
|
// Converts a number to a percentage.
|
||||||
//
|
//
|
||||||
// @alias percentage()
|
// @alias percentage()
|
||||||
@@ -94,7 +113,7 @@
|
|||||||
@function important($flag: false) {
|
@function important($flag: false) {
|
||||||
@if ($flag == true) {
|
@if ($flag == true) {
|
||||||
@return !important;
|
@return !important;
|
||||||
} @elseif ($important == false) {
|
} @else if ($important == false) {
|
||||||
@return null;
|
@return null;
|
||||||
} @else {
|
} @else {
|
||||||
@error "`#{$flag}` needs to be `true` or `false`.";
|
@error "`#{$flag}` needs to be `true` or `false`.";
|
||||||
|
|||||||
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);
|
||||||
|
}
|
||||||
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};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import { writeFile } from 'node:fs/promises';
|
|||||||
import { basename } from 'node:path';
|
import { basename } from 'node:path';
|
||||||
import { promisify } from 'node:util';
|
import { promisify } from 'node:util';
|
||||||
import sass from 'node-sass';
|
import sass from 'node-sass';
|
||||||
|
import { PurgeCSS } from 'purgecss';
|
||||||
|
|
||||||
const sassRender = promisify(sass.render);
|
const sassRender = promisify(sass.render);
|
||||||
|
|
||||||
@@ -142,7 +143,12 @@ export default async function compileStyles(sassOptions = null, postcssOptions =
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
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) {
|
if (result.css) {
|
||||||
message(`${label || `${filestem}.css`} compiled`, 'success', timeLabel);
|
message(`${label || `${filestem}.css`} compiled`, 'success', timeLabel);
|
||||||
@@ -212,3 +218,37 @@ function createPostCSSProcessor(pluginsListOrMap, options)
|
|||||||
|
|
||||||
return postcss(plugins);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ export default function message(text, type, timerID) {
|
|||||||
console.log('✅ ', kleur.bgGreen().black(text));
|
console.log('✅ ', kleur.bgGreen().black(text));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'chore':
|
||||||
|
console.log('🧹 ', kleur.bgGreen().black(text));
|
||||||
|
break;
|
||||||
|
|
||||||
case 'notice':
|
case 'notice':
|
||||||
console.log('ℹ️ ', kleur.bgBlue().black(text));
|
console.log('ℹ️ ', kleur.bgBlue().black(text));
|
||||||
break;
|
break;
|
||||||
|
|||||||
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"
|
"dest": "./www/assets/images"
|
||||||
},
|
},
|
||||||
"views": {
|
"views": {
|
||||||
"src": "./views/boilerplate/template"
|
"src": "./www/"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tasks": {
|
"tasks": {
|
||||||
@@ -56,6 +56,12 @@
|
|||||||
],
|
],
|
||||||
"outfile": "{% paths.svgs.dest %}/sprite.svg"
|
"outfile": "{% paths.svgs.dest %}/sprite.svg"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"purgeCSS": {
|
||||||
|
"content": [
|
||||||
|
"./www/**/*.html",
|
||||||
|
"./assets/scripts/**/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1102
package-lock.json
generated
1102
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
11
package.json
11
package.json
@@ -21,14 +21,15 @@
|
|||||||
"svg4everybody": "^2.1.9"
|
"svg4everybody": "^2.1.9"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"autoprefixer": "^10.4.4",
|
"autoprefixer": "^10.4.12",
|
||||||
"browser-sync": "^2.27.9",
|
"browser-sync": "^2.27.10",
|
||||||
"concat": "^1.0.3",
|
"concat": "^1.0.3",
|
||||||
"esbuild": "^0.14.27",
|
"esbuild": "^0.14.54",
|
||||||
"kleur": "^4.1.4",
|
"kleur": "^4.1.5",
|
||||||
"node-notifier": "^10.0.1",
|
"node-notifier": "^10.0.1",
|
||||||
"node-sass": "^7.0.1",
|
"node-sass": "^7.0.1",
|
||||||
"postcss": "^8.4.12",
|
"postcss": "^8.4.17",
|
||||||
|
"purgecss": "^5.0.0",
|
||||||
"svg-mixer": "^2.3.14",
|
"svg-mixer": "^2.3.14",
|
||||||
"tiny-glob": "^0.2.9"
|
"tiny-glob": "^0.2.9"
|
||||||
}
|
}
|
||||||
|
|||||||
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.
@@ -609,10 +609,141 @@
|
|||||||
// assets/scripts/modules.js
|
// assets/scripts/modules.js
|
||||||
var modules_exports = {};
|
var modules_exports = {};
|
||||||
__export(modules_exports, {
|
__export(modules_exports, {
|
||||||
|
Example: () => Example_default,
|
||||||
Load: () => Load_default,
|
Load: () => Load_default,
|
||||||
Scroll: () => Scroll_default
|
Scroll: () => Scroll_default
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// assets/scripts/utils/fonts.js
|
||||||
|
var isFontLoadingAPIAvailable = "fonts" in document;
|
||||||
|
function conformsToReference(font, criterion2) {
|
||||||
|
for (const [key, value] of Object.entries(criterion2)) {
|
||||||
|
switch (key) {
|
||||||
|
case "family": {
|
||||||
|
if (trim(font[key]) !== value) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "weight": {
|
||||||
|
if (font[key] != value) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
if (font[key] !== value) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
function conformsToShorthand(font, criterion2) {
|
||||||
|
const family = trim(font.family);
|
||||||
|
if (trim(family) === criterion2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (criterion2.endsWith(trim(family)) && (criterion2.match(font.weight) || criterion2.match(font.style))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
function findManyByReference(search) {
|
||||||
|
const found = [];
|
||||||
|
for (const font of document.fonts) {
|
||||||
|
if (conformsToReference(font, search)) {
|
||||||
|
found.push(font);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
function findManyByShorthand(search) {
|
||||||
|
const found = [];
|
||||||
|
for (const font of document.fonts) {
|
||||||
|
if (conformsToShorthand(font, search)) {
|
||||||
|
found.push(font);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
function getMany(queries) {
|
||||||
|
if (!Array.isArray(queries)) {
|
||||||
|
queries = [queries];
|
||||||
|
}
|
||||||
|
const found = /* @__PURE__ */ 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];
|
||||||
|
}
|
||||||
|
function loadFonts(fontsToLoad, debug = false) {
|
||||||
|
return __async(this, null, function* () {
|
||||||
|
var _a;
|
||||||
|
if (((_a = fontsToLoad.size) != null ? _a : fontsToLoad.length) === 0) {
|
||||||
|
throw new TypeError("Expected at least one font");
|
||||||
|
}
|
||||||
|
return yield loadFontsWithAPI([...fontsToLoad], debug);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function loadFontFaceWithAPI(font) {
|
||||||
|
return __async(this, null, function* () {
|
||||||
|
return yield (font.status === "unloaded" ? font.load() : font.loaded).then((font2) => font2, (err) => font);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function loadFontsWithAPI(fontsToLoad, debug = false) {
|
||||||
|
return __async(this, null, function* () {
|
||||||
|
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 yield Promise.all(fontsToBeLoaded);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function trim(value) {
|
||||||
|
return value.replace(/['"]+/g, "");
|
||||||
|
}
|
||||||
|
function whenReady(queries) {
|
||||||
|
return __async(this, null, function* () {
|
||||||
|
const fonts = getMany(queries);
|
||||||
|
return yield Promise.all(fonts.map((font) => font.loaded));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// assets/scripts/modules/Example.js
|
||||||
|
var Example_default = class extends _default {
|
||||||
|
constructor(m) {
|
||||||
|
super(m);
|
||||||
|
}
|
||||||
|
init() {
|
||||||
|
whenReady(EAGER_FONTS).then((fonts) => this.onFontsLoaded(fonts));
|
||||||
|
}
|
||||||
|
onFontsLoaded(fonts) {
|
||||||
|
console.log("Example: Eager Fonts Loaded!", fonts);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// node_modules/modularload/dist/main.esm.js
|
// node_modules/modularload/dist/main.esm.js
|
||||||
function _classCallCheck2(instance, Constructor) {
|
function _classCallCheck2(instance, Constructor) {
|
||||||
if (!(instance instanceof Constructor)) {
|
if (!(instance instanceof Constructor)) {
|
||||||
@@ -3694,12 +3825,21 @@
|
|||||||
console.warn('The "main-css" stylesheet not found');
|
console.warn('The "main-css" stylesheet not found');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
var EAGER_FONTS = [
|
||||||
|
{ family: "Source Sans", style: "normal", weight: 400 },
|
||||||
|
{ family: "Source Sans", style: "normal", weight: 700 }
|
||||||
|
];
|
||||||
function init() {
|
function init() {
|
||||||
globals_default();
|
globals_default();
|
||||||
app.init(app);
|
app.init(app);
|
||||||
html.classList.add(config_default.CSS_CLASS.LOADED);
|
html.classList.add(config_default.CSS_CLASS.LOADED);
|
||||||
html.classList.add(config_default.CSS_CLASS.READY);
|
html.classList.add(config_default.CSS_CLASS.READY);
|
||||||
html.classList.remove(config_default.CSS_CLASS.LOADING);
|
html.classList.remove(config_default.CSS_CLASS.LOADING);
|
||||||
|
if (isFontLoadingAPIAvailable) {
|
||||||
|
loadFonts(EAGER_FONTS).then((eagerFonts) => {
|
||||||
|
html.classList.add("fonts-loaded");
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
/*
|
/*
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -516,11 +516,43 @@ button:focus, button:hover,
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-display: swap;
|
||||||
|
font-family: Source Sans;
|
||||||
|
src: url("../fonts/SourceSans3-Bold.woff2") format("woff2"), url("../fonts/SourceSans3-Bold.woff") format("woff");
|
||||||
|
font-weight: 700;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-display: swap;
|
||||||
|
font-family: Source Sans;
|
||||||
|
src: url("../fonts/SourceSans3-BoldIt.woff2") format("woff2"), url("../fonts/SourceSans3-BoldIt.woff") format("woff");
|
||||||
|
font-weight: 700;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-display: swap;
|
||||||
|
font-family: Source Sans;
|
||||||
|
src: url("../fonts/SourceSans3-Regular.woff2") format("woff2"), url("../fonts/SourceSans3-Regular.woff") format("woff");
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-display: swap;
|
||||||
|
font-family: Source Sans;
|
||||||
|
src: url("../fonts/SourceSans3-RegularIt.woff2") format("woff2"), url("../fonts/SourceSans3-RegularIt.woff") format("woff");
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
font-family: "Webfont Sans", "Helvetica Neue", Arial, sans-serif;
|
font-family: Source, Sans, -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial, sans-serif;
|
||||||
color: #222222;
|
color: #000000;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
@@ -614,9 +646,8 @@ a:focus, a:hover {
|
|||||||
.o-container {
|
.o-container {
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
padding-right: 3.75rem;
|
padding-right: 20px;
|
||||||
padding-left: 3.75rem;
|
padding-left: 20px;
|
||||||
max-width: 132.5rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.o-ratio {
|
.o-ratio {
|
||||||
@@ -644,90 +675,182 @@ a:focus, a:hover {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.o-layout {
|
.o-icon {
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
list-style: none;
|
|
||||||
font-size: 0;
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.o-layout.-gutter {
|
|
||||||
margin-left: -3.75rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.o-layout.-gutter-small {
|
|
||||||
margin-left: -1.875rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.o-layout.-center {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.o-layout.-right {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.o-layout.-reverse {
|
|
||||||
direction: rtl;
|
|
||||||
}
|
|
||||||
|
|
||||||
.o-layout.-reverse.-flex {
|
|
||||||
flex-direction: row-reverse;
|
|
||||||
}
|
|
||||||
|
|
||||||
.o-layout.-flex {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.o-layout.-flex.-top {
|
|
||||||
align-items: flex-start;
|
|
||||||
}
|
|
||||||
|
|
||||||
.o-layout.-flex.-middle {
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.o-layout.-flex.-bottom {
|
|
||||||
align-items: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
.o-layout.-stretch {
|
|
||||||
align-items: stretch;
|
|
||||||
}
|
|
||||||
|
|
||||||
.o-layout_item {
|
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 100%;
|
|
||||||
vertical-align: top;
|
|
||||||
font-size: 1rem;
|
|
||||||
padding-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.o-layout.-gutter > .o-layout_item {
|
|
||||||
padding-left: 3.75rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.o-layout.-gutter-small > .o-layout_item {
|
|
||||||
padding-left: 1.875rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.o-layout.-middle > .o-layout_item {
|
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
.o-layout.-bottom > .o-layout_item {
|
.o-icon svg {
|
||||||
vertical-align: bottom;
|
--icon-height: calc(var(--icon-width) * (1 / (var(--icon-ratio))));
|
||||||
|
display: block;
|
||||||
|
width: var(--icon-width);
|
||||||
|
height: var(--icon-height);
|
||||||
|
fill: currentColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
.o-layout.-center > .o-layout_item,
|
/**
|
||||||
.o-layout.-right > .o-layout_item,
|
* Usage:
|
||||||
.o-layout.-reverse > .o-layout_item {
|
*
|
||||||
text-align: left;
|
* ```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%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.o-layout.-reverse > .o-layout_item {
|
.o-grid:is(ul,
|
||||||
direction: ltr;
|
ol) {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o-grid.-col-12 {
|
||||||
|
grid-template-columns: repeat(12, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.o-grid.-col-4 {
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1000px) {
|
||||||
|
.o-grid.-col-12\@from-medium {
|
||||||
|
grid-template-columns: repeat(12, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.o-grid.-gutters {
|
||||||
|
gap: 20px;
|
||||||
|
-moz-column-gap: 20px;
|
||||||
|
column-gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o-grid.-full-height {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o-grid.-top-items {
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o-grid.-right-items {
|
||||||
|
justify-items: end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o-grid.-bottom-items {
|
||||||
|
align-items: end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o-grid.-left-items {
|
||||||
|
justify-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o-grid.-center-items {
|
||||||
|
align-items: center;
|
||||||
|
justify-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o-grid.-center-items-x {
|
||||||
|
justify-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o-grid.-center-items-y {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o-grid.-stretch-items {
|
||||||
|
align-items: stretch;
|
||||||
|
justify-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o-grid.-top-cells {
|
||||||
|
align-content: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o-grid.-right-cells {
|
||||||
|
justify-content: end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o-grid.-bottom-cells {
|
||||||
|
align-content: end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o-grid.-left-cells {
|
||||||
|
justify-content: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o-grid.-center-cells {
|
||||||
|
align-content: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o-grid.-center-cells-x {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o-grid.-center-cells-y {
|
||||||
|
align-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o-grid.-stretch-cells {
|
||||||
|
align-content: stretch;
|
||||||
|
justify-content: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o-grid.-space-around-cells {
|
||||||
|
align-content: space-around;
|
||||||
|
justify-content: space-around;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o-grid.-space-around-cells-x {
|
||||||
|
justify-content: space-around;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o-grid.-space-around-cells-y {
|
||||||
|
align-content: space-around;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o-grid.-space-between-cells {
|
||||||
|
justify-content: space-between;
|
||||||
|
align-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o-grid.-space-between-cells-x {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o-grid.-space-between-cells-y {
|
||||||
|
align-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o-grid.-space-evenly-cells {
|
||||||
|
justify-content: space-evenly;
|
||||||
|
align-content: space-evenly;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o-grid.-space-evenly-cells-x {
|
||||||
|
justify-content: space-evenly;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o-grid.-space-evenly-cells-y {
|
||||||
|
align-content: space-evenly;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o-grid_item {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.o-grid_item.-align-end {
|
||||||
|
align-self: end;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c-scrollbar {
|
.c-scrollbar {
|
||||||
@@ -753,7 +876,7 @@ a:focus, a:hover {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
background-color: black;
|
background-color: #000000;
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
width: 7px;
|
width: 7px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
@@ -818,7 +941,7 @@ a:focus, a:hover {
|
|||||||
.c-form_input, .c-form_select_input, .c-form_textarea {
|
.c-form_input, .c-form_select_input, .c-form_textarea {
|
||||||
padding: 0.625rem;
|
padding: 0.625rem;
|
||||||
border: 1px solid lightgray;
|
border: 1px solid lightgray;
|
||||||
background-color: white;
|
background-color: #FFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c-form_input:hover, .c-form_select_input:hover, .c-form_textarea:hover {
|
.c-form_input:hover, .c-form_select_input:hover, .c-form_textarea:hover {
|
||||||
@@ -949,68 +1072,43 @@ a:focus, a:hover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* stylelint-enable */
|
/* stylelint-enable */
|
||||||
.u-1\/1 {
|
|
||||||
width: 100% !important;
|
.u-gc-1\/3 {
|
||||||
|
grid-column-start: 1;
|
||||||
|
grid-column-end: 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.u-1\/2 {
|
@media (min-width: 1000px) {
|
||||||
width: 50% !important;
|
.u-gc-1\/5\@from-medium {
|
||||||
}
|
grid-column-start: 1;
|
||||||
|
grid-column-end: 5;
|
||||||
.u-2\/2 {
|
}
|
||||||
width: 100% !important;
|
}
|
||||||
}
|
|
||||||
|
@media (min-width: 1000px) {
|
||||||
.u-1\/3 {
|
.u-gc-1\/8\@from-medium {
|
||||||
width: 33.33333% !important;
|
grid-column-start: 1;
|
||||||
}
|
grid-column-end: 8;
|
||||||
|
}
|
||||||
.u-2\/3 {
|
}
|
||||||
width: 66.66667% !important;
|
|
||||||
}
|
@media (min-width: 1000px) {
|
||||||
|
.u-gc-5\/9\@from-medium {
|
||||||
.u-3\/3 {
|
grid-column-start: 5;
|
||||||
width: 100% !important;
|
grid-column-end: 9;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
.u-1\/4 {
|
|
||||||
width: 25% !important;
|
@media (min-width: 1000px) {
|
||||||
}
|
.u-gc-5\/13\@from-medium {
|
||||||
|
grid-column-start: 5;
|
||||||
.u-2\/4 {
|
grid-column-end: 13;
|
||||||
width: 50% !important;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.u-3\/4 {
|
@media (min-width: 1000px) {
|
||||||
width: 75% !important;
|
.u-gc-9\/13\@from-medium {
|
||||||
}
|
grid-column-start: 9;
|
||||||
|
grid-column-end: 13;
|
||||||
.u-4\/4 {
|
|
||||||
width: 100% !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.u-1\/5 {
|
|
||||||
width: 20% !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.u-2\/5 {
|
|
||||||
width: 40% !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.u-3\/5 {
|
|
||||||
width: 60% !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.u-4\/5 {
|
|
||||||
width: 80% !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.u-5\/5 {
|
|
||||||
width: 100% !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 700px) {
|
|
||||||
.u-1\/2\@from-small {
|
|
||||||
width: 50%;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -25,6 +25,7 @@
|
|||||||
<ul>
|
<ul>
|
||||||
<li><a href="images.html">Images</a></li>
|
<li><a href="images.html">Images</a></li>
|
||||||
<li><a href="form.html" data-load="customTransition">Form</a></li>
|
<li><a href="form.html" data-load="customTransition">Form</a></li>
|
||||||
|
<li><a href="grid.html">Grid</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</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>
|
<ul>
|
||||||
<li><a href="images.html">Images</a></li>
|
<li><a href="images.html">Images</a></li>
|
||||||
<li><a href="form.html" data-load="customTransition">Form</a></li>
|
<li><a href="form.html" data-load="customTransition">Form</a></li>
|
||||||
|
<li><a href="grid.html">Grid</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
@@ -29,11 +29,20 @@
|
|||||||
-->
|
-->
|
||||||
<!-- <link rel="icon" href="assets/images/favicons/favicon.svg"> -->
|
<!-- <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"
|
<link id="main-css" rel="stylesheet" href="assets/styles/main.css" media="print"
|
||||||
onload="this.media='all'; this.onload=null; this.isLoaded=true">
|
onload="this.media='all'; this.onload=null; this.isLoaded=true">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body data-module-load>
|
<body data-module-load>
|
||||||
|
|
||||||
|
<!-- <p aria-hidden="true" class="u-screen-reader-text" style="font-family: 'Webfont';"> </p> -->
|
||||||
|
|
||||||
<div data-load-container>
|
<div data-load-container>
|
||||||
<div class="o-scroll" data-module-scroll="main">
|
<div class="o-scroll" data-module-scroll="main">
|
||||||
<header data-scroll-section>
|
<header data-scroll-section>
|
||||||
@@ -44,11 +53,12 @@
|
|||||||
<ul>
|
<ul>
|
||||||
<li><a href="images.html">Images</a></li>
|
<li><a href="images.html">Images</a></li>
|
||||||
<li><a href="form.html" data-load="customTransition">Form</a></li>
|
<li><a href="form.html" data-load="customTransition">Form</a></li>
|
||||||
|
<li><a href="grid.html">Grid</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main data-scroll-section>
|
<main data-module-example data-scroll-section>
|
||||||
<div class="o-container">
|
<div class="o-container">
|
||||||
<h1 class="c-heading -h1">Hello</h1>
|
<h1 class="c-heading -h1">Hello</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user