1
0
mirror of https://github.com/locomotivemtl/locomotive-boilerplate.git synced 2026-01-15 00:55:08 +08:00

31 Commits

Author SHA1 Message Date
Jérémy Minié
4ff4f2fb9c Declare REGISTERED_CUSTOM_EVENTS as a const to avoid altering window global object 2022-06-22 17:07:39 -04:00
Jérémy Minié
cfa899639e Fix non-existing variables/functions calls 2022-06-22 17:06:39 -04:00
Lucas Vallenet
d916ad030d Update comments and functions / Blends scrollup and scrolldown to one function 2022-06-02 16:42:19 +02:00
Lucas Vallenet
b346b043a6 Improve tickers comments 2022-06-02 16:42:19 +02:00
Lucas Vallenet
99291b17f5 Create tickers and events utils 2022-06-02 16:26:29 +02:00
Lucas Vallenet
c8d4e7c154 Build scripts and styles with latest updates 2022-06-01 16:26:47 +02:00
Lucas
bce37afb6e Merge pull request #121 from locomotivemtl/feature/scss-font-fallbacks
Add font fallbacks
2022-06-01 16:21:16 +02:00
Lucas
7a23abff92 Merge branch 'master' into feature/scss-font-fallbacks 2022-06-01 16:21:09 +02:00
Lucas
27d8fdee22 Merge pull request #110 from locomotivemtl/feature/icons
Add icon object styles and html example
2022-06-01 16:20:13 +02:00
Lucas
9154deb036 Merge branch 'master' into feature/icons 2022-06-01 16:19:46 +02:00
Lucas
17e8004515 Merge pull request #117 from locomotivemtl/feature/scss-functions
Add Sass functions
2022-06-01 16:17:27 +02:00
Lucas Vallenet
6b3edefa48 Reset scripts to master 2022-06-01 11:02:55 +02:00
Lucas Vallenet
fd5efe3531 Update functions comments 2022-06-01 11:02:26 +02:00
Lucas Vallenet
2783fb5138 Reset scripts from master 2022-05-31 13:20:02 +02:00
Lucas Vallenet
f1e4cd2c55 Update comments 2022-05-31 13:19:34 +02:00
Chauncey McAskill
b7d25c5865 Update _fonts.scss
Improved block comments and error for mixins.
2022-05-30 15:00:24 -04:00
Lucas Vallenet
0a199afe01 Add unsaved comments 2022-05-30 16:44:19 +02:00
Lucas Vallenet
8ca570b37a Font fallbacks 2022-05-30 16:41:53 +02:00
Lucas
e5417ff6ab Merge pull request #118 from locomotivemtl/feature/scss-variables-namespace
Update Sass variable names and add easings
2022-05-30 13:10:47 +02:00
Lucas
3a94c6aba9 Merge branch 'master' into feature/scss-variables-namespace 2022-05-30 13:09:26 +02:00
Lucas Vallenet
648109fc9b Reset unrelevant scripts changes to master 2022-05-30 13:04:33 +02:00
Lucas Vallenet
b162c62930 Remove logo.svg / Remove html example markup / Update scss instructions 2022-05-25 17:13:35 +02:00
Lucas Vallenet
cb27975087 Update maths comments / Add pixel value function 2022-05-25 16:02:15 +02:00
Chauncey McAskill
0b667542f5 Refactor visibility.js
Replaced custom callback stacks for executing handlers on page visibility change with native event listener interface and custom event types.

Added:
- Class `PageVisibility` with methods to disable/enable custom event types and check if feature is enabled.
- Custom event types "visibilityhidden" and "visibilityvisible".
2022-05-25 09:54:01 -04:00
Lucas Vallenet
d7de1b2566 Update scss maths comments 2022-05-25 13:57:30 +02:00
Lucas Vallenet
34bca7d68a Rename z-index layers var and update function 2022-05-25 13:54:03 +02:00
Lucas Vallenet
f44093ec19 Update scss semicolon spacings 2022-05-25 13:47:45 +02:00
Lucas Vallenet
141a8ffa97 Update scss vars namespace and add easings 2022-05-20 13:32:47 +02:00
Lucas Vallenet
e875495928 Add z-index function 2022-05-20 11:44:42 +02:00
Lucas Vallenet
c2db2e1922 Add SCSS Math functions 2022-05-20 11:42:06 +02:00
Lucas Vallenet
da66f89d7f Add icon object styles and html example 2022-04-29 13:36:54 +02:00
21 changed files with 754 additions and 3919 deletions

View File

View File

@@ -1,15 +0,0 @@
export default function(func, wait, immediate) {
let timeout;
return function() {
const context = this;
const args = arguments;
const later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
const callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}

View File

@@ -0,0 +1,180 @@
import { debounce } from './tickers'
/**
* @typedef {object} RegisteredCustomEvent
*
* @property {EventTarget} target - The event target ({@see Window} or {@see Node}).
* @property {string} type - The custom event name.
*/
/** @type {RegisteredCustomEvent[]} */
const REGISTERED_CUSTOM_EVENTS = []
/**
* Determines if the given object is the {@see Window}.
*
* @param {object} obj
* @return {boolean}
*/
const isWindow = obj => obj === window
/**
* Determines if the given object implements {@see EventTarget}.
*
* @param {object} obj
* @return {boolean}
*/
const isEventTarget = obj => (obj instanceof EventTarget)
/**
* Determines if the target already has the event attached.
*
* @param {EventTarget} target
* @param {string} type - The custom event name.
* @return {boolean}
*/
const isCustomEventRegistered = (target, type) => REGISTERED_CUSTOM_EVENTS.some(e => e.target === target && e.type === type)
/**
* Registers the custom event with the given target, if not already registered.
*
* @param {EventTarget} target
* @param {string} type - The custom event name.
* @return {void}
*/
const addCustomEvent = (target, type) => {
if (!isCustomEventRegistered(target, type)) {
REGISTERED_CUSTOM_EVENTS.push({
target,
type
})
}
}
/**
* Adds a custom "start" event for the given target.
*
* Internally, this function adds a debounced event listener on
* the given `event` to trigger the custom `<event>start` event.
*
* @param {EventTarget} target
* @param {string} type - The base event name.
* @param {number} [delay] - The number of milliseconds to wait
* before dispatching the custom event.
* @throws Error If the target is invalid.
* @throws Error If the custom event is already defined.
* @return {void}
*/
const addStartEvent = (target, type, delay = 200) => {
const customType = `${type}start`
if (!isEventTarget(target)) {
throw new Error(`addStartEvent: target parameter must be an instance of EventTarget`)
}
if (isCustomEventRegistered(target, customType)) {
throw new Error(`addStartEvent: '${customType}' already exists for target parameter`)
}
addCustomEvent(target, customType)
const startEvent = new CustomEvent(customType)
target.addEventListener(type, debounce(() => {
target.dispatchEvent(startEvent)
}, delay, true))
}
/**
* Adds a custom "end" event for the given target.
*
* Internally, this function adds a debounced event listener on
* the given `event` to trigger the custom `<event>end` event.
*
* @param {EventTarget} target
* @param {string} type - The base event name.
* @param {number} [delay] - The number of milliseconds to wait
* before dispatching the custom event.
* @throws Error If the target is invalid.
* @throws Error If the custom event is already defined.
* @return {void}
*/
const addEndEvent = (target, type, delay = 200) => {
const customType = `${type}end`
if (!isEventTarget(target)) {
throw new Error(`addEndEvent: target parameter must be an instance of EventTarget`)
}
if (isCustomEventRegistered(target, customType)) {
throw new Error(`addEndEvent: '${customType}' already exists for target parameter`)
}
addCustomEvent(target, customType)
const endEvent = new CustomEvent(customType)
target.addEventListener(type, debounce(() => {
target.dispatchEvent(endEvent)
}, delay))
}
/**
* Adds custom scroll "up" and "down" events for the given target.
*
* Internally, this function adds an event listener on
* the scroll event to detect the direction and trigger
* the custom `scrollup` and `scrolldown` events.
*
* @param {EventTarget} [target] - If omitted, the custom event
* if attached to the Window.
* @throws Error If the target is invalid.
* @return {void}
*/
const addScrollDirectionEvents = (target = window) => {
if (!isEventTarget(target)) {
throw new Error(`addScrollDirectionEvents: target parameter must be an instance of EventTarget`)
}
let scrollTop = target.scrollTop
let previousScrollTop = scrollTop
let direction = 0
const scrollUp = new CustomEvent('scrollup')
const scrollDown = new CustomEvent('scrolldown')
const scrollProperty = isWindow(target) ? 'scrollY' : 'scrollTop'
target.addEventListener('scroll', () => {
scrollTop = target[scrollProperty]
// Scroll up
if (scrollTop < previousScrollTop && direction > -1) {
target.dispatchEvent(scrollUp)
direction = -1
// Scroll down
} else if (scrollTop > previousScrollTop && direction < 1) {
target.dispatchEvent(scrollDown)
direction = 1
}
previousScrollTop = scrollTop
})
}
export {
addStartEvent,
addEndEvent,
addScrollDirectionEvents,
}

View File

@@ -0,0 +1,78 @@
/**
* Creates a debounced function.
*
* A debounced function delays invoking `callback` until after
* `delay` milliseconds have elapsed since the last time the
* debounced function was invoked.
*
* Useful for behaviour that should only happen _before_ or
* _after_ an event has stopped occurring.
*
* @template {function} T
*
* @param {T} callback - The function to debounce.
* @param {number} delay - The number of milliseconds to wait.
* @param {boolean} [immediate] -
* If `true`, `callback` is invoked before `delay`.
* If `false`, `callback` is invoked after `delay`.
* @return {function<T>} The new debounced function.
*/
const debounce = (callback, delay, immediate = false) => {
let timeout = null
return (...args) => {
clearTimeout(timeout)
const later = () => {
timeout = null
if (!immediate) {
callback(...args)
}
}
if (immediate && !timeout) {
callback(...args)
}
timeout = setTimeout(later, delay)
}
}
/**
* Creates a throttled function.
*
* A throttled function invokes `callback` at most once per every
* `delay` milliseconds.
*
* Useful for rate-limiting an event that occurs in quick succession.
*
* @template {function} T
*
* @param {T} callback - The function to throttle.
* @param {number} delay - The number of milliseconds to wait.
* @return {function<T>} The new throttled function.
*/
const throttle = (callback, delay) => {
let timeout = false
return (...args) => {
if (!timeout) {
timeout = true
callback(...args)
setTimeout(() => {
timeout = false
}, delay)
}
}
}
export {
debounce,
throttle
}

View File

@@ -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
* @param {string} state
* @param {function} callback
* @return {string} ident
* The `PageVisibility` interface provides support for dispatching
* a custom event derived from the value of {@see document.visibilityState}
* when the "visibilitychange" event is fired.
*
* The custom events are:
*
* - "visibilityhidden" representing the "hidden" visibility state.
* - "visibilityvisible" representing the "visibile" visibility state.
*
* Example:
*
* ```js
* import pageVisibility from './utils/visibility.js';
*
* pageVisibility.enableCustomEvents();
*
* document.addEventListener('visibilityhidden', () => videoElement.pause());
* ```
*
* The dispatched event object is the same from "visibilitychange"
* and renamed according to the visibility state.
*
* The `PageVisibility` interface does not manage the attachment/detachment
* of event listeners on the custom event types.
*
* Further reading:
*
* - {@link https://www.w3.org/TR/page-visibility/ W3 Specification}
* - {@link https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API MDN Web Docs}
*/
function addCallback (state, options) {
let callback = options.callback || '';
export default new class PageVisibility {
/**
* Checks if the "visibilitychange" event listener has been registered.
*
* @return {boolean} Returns `false` if the event listener is not registered,
* otherwise returns `true`.
*/
get isEnabled() {
return isVisibilityChangeObserved;
}
/**
* Removes the "visibilitychange" event listener.
*
* @return {boolean} Returns `false` if the event listener was already unregistered,
* otherwise returns `true`.
*/
disableCustomEvents() {
if (isVisibilityChangeObserved) {
isVisibilityChangeObserved = false;
document.removeEventListener('visibilitychange', handleCustomVisibilityChange);
return true;
}
if (!isFunction(callback)) {
console.warn('Callback is not a function');
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;
}
}
/**
* When document state changes, trigger callbacks
* @param {string} state Visible or hidden
* Tracks whether custom visibility event types
* are available (`true`) or not (`false`).
*
* @type {boolean}
*/
function onDocumentChange (state) {
let callbackArray = CALLBACKS[state];
let i = 0;
let len = callbackArray.length;
let isVisibilityChangeObserved = false;
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
* @param {object} options Options
* @return {boolean|integer} Unique identifier for the callback or boolean indicating success or failure
* The "visibilityhidden" eveent is fired at the document when the contents
* of its tab have become hidden.
*
* @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)) {
console.warn('Action does not exist');
return false;
}
if (!arrayContains(STATES, state)) {
console.warn('State does not exist');
return false;
}
// @todo Magic call function pls
if (action === 'addCallback') {
ret = addCallback(state, options);
} else if (action === 'removeCallback') {
ret = removeCallback(state, options);
}
return ret;
}
export { visibilityApi };
/**
* The "visibilityvisible" eveent is fired at the document when the contents
* of its tab have become visible.
*
* @event PageVisibility#visibilityvisible
* @type {Event}
*/

View File

@@ -27,7 +27,7 @@ $input-icon-color: 424242; // No #
.c-form_input {
padding: rem(10px);
border: 1px solid lightgray;
background-color: white;
background-color: $color-lightest;
&:hover {
border-color: darkgray;
@@ -71,7 +71,7 @@ $checkbox-icon-color: $input-icon-color;
}
&::before {
background-color: $white;
background-color: $color-lightest;
border: 1px solid lightgray;
}

View File

@@ -25,7 +25,7 @@
position: absolute;
top: 0;
right: 0;
background-color: black;
background-color: $color-darkest;
opacity: 0.5;
width: 7px;
border-radius: 10px;

View File

@@ -15,7 +15,7 @@ html {
min-height: 100%; // [2]
line-height: $line-height;
font-family: ff("sans");
color: $color;
color: $font-color;
line-height: $line-height; // [3]
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
@@ -74,9 +74,9 @@ body {
}
a {
color: $link-color;
color: $color-link;
@include u-hocus {
color: $link-hover-color;
color: $color-link-hover;
}
}

View File

@@ -33,7 +33,7 @@ i {
b,
strong {
font-weight: $bold;
font-weight: $font-weight-bold;
}
a {

View File

@@ -13,6 +13,7 @@
// Tools
// ==========================================================================
@import "tools/maths";
@import "tools/functions";
@import "tools/mixins";
@import "tools/fonts";
@@ -40,6 +41,7 @@
@import "objects/scroll";
@import "objects/container";
@import "objects/ratio";
@import "objects/icons";
@import "objects/layout";
// @import "objects/crop";
// @import "objects/table";
@@ -56,10 +58,6 @@
@import "components/button";
@import "components/form";
// Templates
// ==========================================================================
// @import "templates/template";
// Utilities
// ==========================================================================

View 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)};
// }
// }

View File

@@ -5,25 +5,25 @@
// Palette
// =============================================================================
$white: #FFFFFF;
$black: #000000;
$color-lightest: #FFFFFF;
$color-darkest: #000000;
// Specific
// =============================================================================
// Link
$link-color: #1A0DAB;
$link-focus-color: #1A0DAB;
$link-hover-color: darken(#1A0DAB, 10%);
$color-link: #1A0DAB;
$color-link-focus: #1A0DAB;
$color-link-hover: darken(#1A0DAB, 10%);
// Selection
$selection-text-color: #3297FD;
$selection-background-color: #FFFFFF;
$selection-text-color: #3297FD;
$selection-background-color: #FFFFFF;
// Social Colors
// =============================================================================
$facebook-color: #3B5998;
$instagram-color: #E1306C;
$youtube-color: #CD201F;
$twitter-color: #1DA1F2;
$color-facebook: #3B5998;
$color-instagram: #E1306C;
$color-youtube: #CD201F;
$color-twitter: #1DA1F2;

View File

@@ -2,22 +2,47 @@
// Settings / Config / Eases
// ==========================================================================
$Power1EaseOut: cubic-bezier(0.250, 0.460, 0.450, 0.940);
$Power2EaseOut: cubic-bezier(0.215, 0.610, 0.355, 1.000);
$Power3EaseOut: cubic-bezier(0.165, 0.840, 0.440, 1.000);
$Power4EaseOut: cubic-bezier(0.230, 1.000, 0.320, 1.000);
$Power1EaseIn: cubic-bezier(0.550, 0.085, 0.680, 0.530) ;
$Power2EaseIn: cubic-bezier(0.550, 0.055, 0.675, 0.190);
$Power3EaseIn: cubic-bezier(0.895, 0.030, 0.685, 0.220);
$Power4EaseIn: cubic-bezier(0.755, 0.050, 0.855, 0.060);
$ExpoEaseOut: cubic-bezier(0.190, 1.000, 0.220, 1.000);
$ExpoEaseIn: cubic-bezier(0.950, 0.050, 0.795, 0.035);
$ExpoEaseInOut: cubic-bezier(1.000, 0.000, 0.000, 1.000);
$SineEaseOut: cubic-bezier(0.390, 0.575, 0.565, 1.000);
$SineEaseIn: cubic-bezier(0.470, 0.000, 0.745, 0.715);
$Power1EaseInOut: cubic-bezier(0.455, 0.030, 0.515, 0.955);
$Power2EaseInOut: cubic-bezier(0.645, 0.045, 0.355, 1.000);
$Power3EaseInOut: cubic-bezier(0.770, 0.000, 0.175, 1.000);
$Power4EaseInOut: cubic-bezier(0.860, 0.000, 0.070, 1.000);
$SlowEaseOut: cubic-bezier(.04,1.15,0.4,.99);
$bounce: cubic-bezier(0.17, 0.67, 0.3, 1.33);
// Power 1
$ease-power1-in: cubic-bezier(0.550, 0.085, 0.680, 0.530);
$ease-power1-out: cubic-bezier(0.250, 0.460, 0.450, 0.940);
$ease-power1-in-out: cubic-bezier(0.455, 0.030, 0.515, 0.955);
// Power 2
$ease-power2-in: cubic-bezier(0.550, 0.055, 0.675, 0.190);
$ease-power2-out: cubic-bezier(0.215, 0.610, 0.355, 1.000);
$ease-power2-in-out: cubic-bezier(0.645, 0.045, 0.355, 1.000);
// Power 3
$ease-power3-in: cubic-bezier(0.895, 0.030, 0.685, 0.220);
$ease-power3-out: cubic-bezier(0.165, 0.840, 0.440, 1.000);
$ease-power3-in-out: cubic-bezier(0.770, 0.000, 0.175, 1.000);
// Power 3
$ease-power4-in: cubic-bezier(0.755, 0.050, 0.855, 0.060);
$ease-power4-out: cubic-bezier(0.230, 1.000, 0.320, 1.000);
$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);

View File

@@ -14,13 +14,30 @@ $assets-path: "../" !default;
// Typefaces
// =============================================================================
// Font directory
$font-dir: "../fonts/";
// Font fallbacks (retrieved from systemfontstack.com on 2022-05-31)
$font-fallback-sans: -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial, sans-serif;
$font-fallback-serif: Iowan Old Style, Apple Garamond, Baskerville, Times New Roman, Droid Serif, Times, Source Serif Pro, serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;
$font-fallback-mono: Menlo, Consolas, Monaco, Liberation Mono, Lucida Console, monospace;
// Map of font families.
//
// ```
// <font-id>: (<font-name>, <font-fallbacks>)
// ```
$font-families: (
"sans": ("Webfont Sans", "Helvetica Neue", Arial, sans-serif),
// "serif": ("Webfont Serif", Georgia, serif)
"sans": ("Webfont Sans", $font-fallback-sans),
// "serif": ("Webfont Serif", $font-fallback-serif),
// "mono": ("Webfont Mono", $font-fallback-mono)
);
// List of custom font faces as tuples.
//
// ```
// <font-name> <font-file-basename> <font-weight> <font-style>
// ```
$font-faces: (
// "Webfont Sans" "webfont-sans_regular" 400 normal,
// "Webfont Sans" "webfont-sans_regular-italic" 400 italic,
@@ -31,9 +48,9 @@ $font-faces: (
// =============================================================================
// Base
$font-size: 16px;
$line-height: 24px / $font-size;
$color: #222222;
$font-size: 16px;
$line-height: 24px / $font-size;
$font-color: $color-darkest;
// Headings
$font-size-h1: 36px !default;
@@ -45,28 +62,28 @@ $font-size-h6: 16px !default;
$line-height-h: $line-height;
// Weights
$light: 300;
$normal: 400;
$medium: 500;
$bold: 700;
$font-weight-light: 300;
$font-weight-normal: 400;
$font-weight-medium: 500;
$font-weight-bold: 700;
// Transitions
// =============================================================================
$speed: 0.3s;
$easing: $Power2EaseOut;
$speed: 0.3s;
$easing: $ease-power2-out;
// Spacing Units
// =============================================================================
$unit: 60px;
$unit-small: 30px;
$unit: 60px;
$unit-small: 30px;
// Container
// =============================================================================
$container-width: 2000px;
$padding: $unit;
$container-width: 2000px;
$padding: $unit;
// Breakpoints
// =============================================================================
@@ -89,3 +106,20 @@ $from-gigantic: 2000px !default;
$to-gigantic: $from-gigantic - 1 !default;
$from-colossal: 2400px !default;
$to-colossal: $from-colossal - 1 !default;
// Master z-indexe
// =============================================================================
$z-indexes: (
"goku": 9000,
"transition": 500,
"toast": 400,
"popover": 300,
"modal": 250,
"sheet": 200,
"fixed": 150,
"sticky": 100,
"dropdown": 50,
"default": 1,
"limbo": -999
);

View File

@@ -2,11 +2,14 @@
// 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.
// @param {String} $dir - The webfont directory path
// @output void
// The mixin expects font files to be woff and woff2.
//
// @param {List} $webfont - A custom font to import, as a tuple:
// `<font-name> <font-file-basename> <font-weight> <font-style>`.
// @param {String} $dir - The webfont directory path.
// @output The `@font-face` at-rule specifying the custom font.
@mixin font-face($webfont, $dir) {
@font-face {
@@ -19,11 +22,14 @@
}
}
// 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.
// @param {String} $dir - The webfont directory path
// @output void
// @require {mixin} font-face
//
// @param {List<List>} $webfonts - List of custom fonts to import.
// See `font-face` mixin for details.
// @param {String} $dir - The webfont directory path.
// @output The `@font-face` at-rules specifying the custom fonts.
@mixin font-faces($webfonts, $dir) {
@each $webfont in $webfonts {
@@ -31,14 +37,17 @@
}
}
// 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.
// @return {String} The webfont and it's fallbacks.
// @require {variable} $font-families - See settings directory.
//
// @param {String} $font-family - The custom font ID.
// @throws Error if the $font-family does not exist.
// @return {List} The font stack.
@function ff($font-family) {
@if not map-has-key($font-families, $font-family) {
@error "No font-family found in $font-families map for `#{$font-family}`. Property omitted.";
@error "No font-family found in $font-families map for `#{$font-family}`.";
}
$value: map-get($font-families, $font-family);

View File

@@ -2,6 +2,15 @@
// Tools / Functions
// ==========================================================================
// Check if the given value is a number in pixel
//
// @param {Number} $number - The value to check
// @return {Boolean}
@function is-pixel-number($number) {
@return type-of($number) == number and unit($number) == "px";
}
// Converts the given pixel value to its EM quivalent.
//
// @param {Number} $size - The pixel value to convert.
@@ -9,20 +18,12 @@
// @return {Number} Scalable pixel value in EMs.
@function em($size, $base: $font-size) {
@if (type-of($size) == number) {
@if (unit($size) != "px") {
@error "`#{$size}` needs to be a pixel value.";
}
} @else {
@error "`#{$size}` needs to be a number.";
@if not is-pixel-number($size) {
@error "`#{$size}` needs to be a number in pixel.";
}
@if (type-of($base) == number) {
@if (unit($base) != "px") {
@error "`#{$base}` needs to be a pixel value.";
}
} @else {
@error "`#{$base}` needs to be a number.";
@if not is-pixel-number($base) {
@error "`#{$base}` needs to be a number in pixel.";
}
@return ($size / $base) * 1em;
@@ -35,25 +36,43 @@
// @return {Number} Scalable pixel value in REMs.
@function rem($size, $base: $font-size) {
@if (type-of($size) == number) {
@if (unit($size) != "px") {
@error "`#{$size}` needs to be a pixel value.";
}
} @else {
@error "`#{$size}` needs to be a number.";
@if not is-pixel-number($size) {
@error "`#{$size}` needs to be a number in pixel.";
}
@if (type-of($base) == number) {
@if (unit($base) != "px") {
@error "`#{$base}` needs to be a pixel value.";
}
} @else {
@error "`#{$base}` needs to be a number.";
@if not is-pixel-number($base) {
@error "`#{$base}` needs to be a number in pixel.";
}
@return ($size / $base) * 1rem;
}
// 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($layers, $layer) {
@error "Unknown master z-index layer: #{$layer}";
}
@if ($modifier >= 50 or $modifier <= -50) {
@warn "Modifier may overlap the another master z-index layer: #{$modifier}";
}
$index: map-get($z-indexes, $layer);
@return $index + $modifier;
}
// Converts a number to a percentage.
//
// @alias percentage()
@@ -94,7 +113,7 @@
@function important($flag: false) {
@if ($flag == true) {
@return !important;
} @elseif ($important == false) {
} @else if ($important == false) {
@return null;
} @else {
@error "`#{$flag}` needs to be `true` or `false`.";

View 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);
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -519,8 +519,8 @@ button:focus, button:hover,
html {
min-height: 100%;
line-height: 1.5;
font-family: "Webfont Sans", "Helvetica Neue", Arial, sans-serif;
color: #222222;
font-family: "Webfont Sans", -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial, sans-serif;
color: #000000;
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
@@ -644,6 +644,19 @@ a:focus, a:hover {
width: 100%;
}
.o-icon {
display: inline-block;
vertical-align: middle;
}
.o-icon svg {
--icon-height: calc(var(--icon-width) * (1 / (var(--icon-ratio))));
display: block;
width: var(--icon-width);
height: var(--icon-height);
fill: currentColor;
}
.o-layout {
margin: 0;
padding: 0;
@@ -753,7 +766,7 @@ a:focus, a:hover {
position: absolute;
top: 0;
right: 0;
background-color: black;
background-color: #000000;
opacity: 0.5;
width: 7px;
border-radius: 10px;
@@ -818,7 +831,7 @@ a:focus, a:hover {
.c-form_input, .c-form_select_input, .c-form_textarea {
padding: 0.625rem;
border: 1px solid lightgray;
background-color: white;
background-color: #FFFFFF;
}
.c-form_input:hover, .c-form_select_input:hover, .c-form_textarea:hover {

File diff suppressed because one or more lines are too long