Skip to content

Instantly share code, notes, and snippets.

@reecelucas
reecelucas / countdown-timer.js
Last active April 29, 2019 10:27
A simple native JS countdown timer
function getRemainingTime(endtime) {
if (typeof endtime !== 'object') {
throw new Error('getRemainingTime expects a Date object');
}
const total = Date.parse(endtime) - Date.parse(new Date());
return {
total: total,
days: Math.floor(total / (1000 * 60 * 60 * 24)),
@reecelucas
reecelucas / scroll-utils.js
Last active April 23, 2020 08:45
Utility functions to toggle page scroll
let bodyBlocked = false;
const { body, documentElement: html } = document;
export const blockScroll = () => {
if (bodyBlocked) {
return;
}
const scrollBarWidth = window.innerWidth - html.clientWidth;
@reecelucas
reecelucas / validate-email.js
Created July 2, 2018 20:31
Email validation utility
/**
* @param {String} email
* @return {Boolean}
*/
const validateEmail = email => {
const emailRegex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return emailRegex.test(email);
};
/**
* @param {String} key
* @param {Any} value
* @param {Number} expirationDays
* @returns {void}
*/
export const saveToLocalStorage = ({ key, value, expirationDays }) => {
// Try for localStorage support...
try {
// Convert days to milliseconds (ms)
@reecelucas
reecelucas / register-sw.js
Created July 2, 2018 20:49
Register a service worker
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker
.register('path/to/service-worker.js')
.then(registration => {
console.log('SW registered: ', registration);
})
.catch(registrationError => {
console.log('SW registration failed: ', registrationError);
});
@reecelucas
reecelucas / preventOrphanedWord.js
Last active May 25, 2023 15:21
Prevent orphaned word in string
export const preventOrphanWord = (string) => {
const words = string.trim().split(' ');
// Only proceed if we've got at least 3 words
if (words.length < 3) {
return string;
}
const [nextToLastWord, lastWord] = words.slice(-2);
const precedingWords = words.slice(0, words.length - 2);
@reecelucas
reecelucas / HTML5-form-validation.js
Last active September 30, 2018 15:15
Simple & extensible form validation using the HTML5 constraint validation API
const form = document.querySelector('form');
const config = {
errorAttribute: 'aria-invalid',
errorClass: 'error'
};
// Helpers
const isFormInput = target => {
const { nodeName } = target;
@reecelucas
reecelucas / observe-visibility.js
Last active August 27, 2018 21:03
Snippet to observe when elements are visible in the viewport, using the IntersectionObserver API
const config = {
selector: '[data-observe]',
isVisibleClass: 'is-visible',
observerOptions: {
threshold: 0,
rootId: null,
rootMargin: '0px 0px 0px 0px',
once: true
}
};
@reecelucas
reecelucas / accordion.js
Last active September 20, 2018 09:30
Simple accessible multi-select accordion. Modified from: https://inclusive-components.design/collapsible-sections/
const config = {
accordionSelector: "[data-accordion]",
headingSelector: "[data-accordion-heading]",
buttonSelector: "[data-accordion-button]"
};
const setup = accordion => {
const headings = [...accordion.querySelectorAll(config.headingSelector)];
if (!headings || headings.length === 0) return;
@reecelucas
reecelucas / scroll-progress.js
Created September 27, 2018 09:50
Scroll progress indicator in native JS
import debounce from "lodash/debounce";
const getPageHeight = () =>
Math.max(
document.body.scrollHeight,
document.body.offsetHeight,
document.documentElement.clientHeight,
document.documentElement.scrollHeight,
document.documentElement.offsetHeight
);