├── arrayUtils ├── index.html ├── script.js └── arrayUtils.js ├── formatters ├── index.html ├── script.js └── formatters.js ├── other.js └── domUtils ├── index.html ├── script.js └── domUtils.js /arrayUtils/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Document 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /formatters/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Document 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /other.js: -------------------------------------------------------------------------------- 1 | export function randomNumberBetween(min, max) { 2 | return Math.floor(Math.random() * (max - min + 1) + min) 3 | } 4 | 5 | export function sleep(duration) { 6 | return new Promise(resolve => { 7 | setTimeout(resolve, duration) 8 | }) 9 | } 10 | 11 | export function memoize(cb) { 12 | const cache = new Map() 13 | return (...args) => { 14 | const key = JSON.stringify(args) 15 | if (cache.has(key)) return cache.get(key) 16 | 17 | const result = cb(...args) 18 | cache.set(key, result) 19 | return result 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /arrayUtils/script.js: -------------------------------------------------------------------------------- 1 | import { first, groupBy, last, sample, pluck } from "./arrayUtils.js" 2 | 3 | const array = ["A", "B", "C", "D", "E", "F", "G"] 4 | 5 | console.log("First:\n", first(array)) 6 | console.log("First 3:\n", first(array, 3)) 7 | console.log("Last:\n", last(array)) 8 | console.log("Last 3:\n", last(array, 3)) 9 | console.log("Sample:\n", sample(array)) 10 | 11 | const people = [ 12 | { name: "Kyle", age: 26 }, 13 | { name: "John", age: 24 }, 14 | { name: "Mike", age: 18 }, 15 | { name: "Jill", age: 26 }, 16 | { name: "Sally", age: 21 }, 17 | ] 18 | 19 | console.log("Pluck:\n", pluck(people, "name")) 20 | console.log("Group By:\n", groupBy(people, "age")) 21 | -------------------------------------------------------------------------------- /domUtils/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Document 9 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 |
26 | 27 | -------------------------------------------------------------------------------- /arrayUtils/arrayUtils.js: -------------------------------------------------------------------------------- 1 | import { randomNumberBetween } from "../other.js" 2 | 3 | export function first(array, n = 1) { 4 | if (n === 1) return array[0] 5 | return array.filter((_, index) => index < n) 6 | } 7 | 8 | export function last(array, n = 1) { 9 | if (n === 1) return array[array.length - 1] 10 | return array.filter((_, index) => array.length - index <= n) 11 | } 12 | 13 | export function sample(array) { 14 | return array[randomNumberBetween(0, array.length - 1)] 15 | } 16 | 17 | export function pluck(array, key) { 18 | return array.map(element => element[key]) 19 | } 20 | 21 | export function groupBy(array, key) { 22 | return array.reduce((group, element) => { 23 | const keyValue = element[key] 24 | return { ...group, [keyValue]: [...(group[keyValue] ?? []), element] } 25 | }, {}) 26 | } 27 | -------------------------------------------------------------------------------- /domUtils/script.js: -------------------------------------------------------------------------------- 1 | import { addGlobalEventListener, createElement, qs, qsa } from "./domUtils.js" 2 | 3 | console.log("Buttons:\n", qsa(".btn")) 4 | console.log("Wrapper:\n", qs(".wrapper")) 5 | console.log("Buttons In Wrapper:\n", qsa(".btn", qs(".wrapper"))) 6 | 7 | addGlobalEventListener("click", ".btn", e => { 8 | console.log(e.target.textContent) 9 | }) 10 | 11 | addGlobalEventListener("click", ".btn", () => console.log("Runs once"), { 12 | once: true, 13 | }) 14 | 15 | addGlobalEventListener( 16 | "click", 17 | ".btn", 18 | () => console.log("Only works on buttons in modal"), 19 | {}, 20 | qs(".wrapper") 21 | ) 22 | 23 | const element = createElement("button", { 24 | class: "btn", 25 | text: "New", 26 | dataset: { test: true }, 27 | id: "new", 28 | "data-hi": "Yes", 29 | }) 30 | qs(".wrapper").append(element) 31 | -------------------------------------------------------------------------------- /formatters/script.js: -------------------------------------------------------------------------------- 1 | import { 2 | formatCompactNumber, 3 | formatCurrency, 4 | formatNumber, 5 | formatRelativeDate, 6 | } from "./formatters.js" 7 | 8 | const number = 9_123_456.789123 9 | console.log("Default:\n", number) 10 | console.log("Currency:\n", formatCurrency(number)) 11 | console.log("Number:\n", formatNumber(number)) 12 | console.log("Compact:\n", formatCompactNumber(number)) 13 | 14 | const currentDate = new Date() 15 | const twoMonthsAgo = new Date().setMonth(currentDate.getMonth() - 2) 16 | const yesterday = new Date().setDate(currentDate.getDate() - 1) 17 | const nineDaysAgo = new Date().setDate(currentDate.getDate() - 9) 18 | 19 | console.log("Two Months Ago:\n", formatRelativeDate(twoMonthsAgo)) 20 | console.log("Yesterday:\n", formatRelativeDate(yesterday)) 21 | console.log("Nine Days Ago:\n", formatRelativeDate(nineDaysAgo)) 22 | console.log( 23 | "Yesterday vs Nine Days Ago:\n", 24 | formatRelativeDate(yesterday, nineDaysAgo) 25 | ) 26 | -------------------------------------------------------------------------------- /domUtils/domUtils.js: -------------------------------------------------------------------------------- 1 | export function addGlobalEventListener( 2 | type, 3 | selector, 4 | callback, 5 | options, 6 | parent = document 7 | ) { 8 | parent.addEventListener( 9 | type, 10 | e => { 11 | if (e.target.matches(selector)) callback(e) 12 | }, 13 | options 14 | ) 15 | } 16 | 17 | export function qs(selector, parent = document) { 18 | return parent.querySelector(selector) 19 | } 20 | 21 | export function qsa(selector, parent = document) { 22 | return [...parent.querySelectorAll(selector)] 23 | } 24 | 25 | export function createElement(type, options = {}) { 26 | const element = document.createElement(type) 27 | Object.entries(options).forEach(([key, value]) => { 28 | if (key === "class") { 29 | element.classList.add(value) 30 | return 31 | } 32 | 33 | if (key === "dataset") { 34 | Object.entries(value).forEach(([dataKey, dataValue]) => { 35 | element.dataset[dataKey] = dataValue 36 | }) 37 | return 38 | } 39 | 40 | if (key === "text") { 41 | element.textContent = value 42 | return 43 | } 44 | 45 | element.setAttribute(key, value) 46 | }) 47 | return element 48 | } 49 | -------------------------------------------------------------------------------- /formatters/formatters.js: -------------------------------------------------------------------------------- 1 | const CURRENCY_FORMATTER = new Intl.NumberFormat(undefined, { 2 | currency: "USD", 3 | style: "currency", 4 | }) 5 | export function formatCurrency(number) { 6 | return CURRENCY_FORMATTER.format(number) 7 | } 8 | 9 | const NUMBER_FORMATTER = new Intl.NumberFormat(undefined) 10 | export function formatNumber(number) { 11 | return NUMBER_FORMATTER.format(number) 12 | } 13 | 14 | const COMPACT_NUMBER_FORMATTER = new Intl.NumberFormat(undefined, { 15 | notation: "compact", 16 | }) 17 | export function formatCompactNumber(number) { 18 | return COMPACT_NUMBER_FORMATTER.format(number) 19 | } 20 | 21 | const DIVISIONS = [ 22 | { amount: 60, name: "seconds" }, 23 | { amount: 60, name: "minutes" }, 24 | { amount: 24, name: "hours" }, 25 | { amount: 7, name: "days" }, 26 | { amount: 4.34524, name: "weeks" }, 27 | { amount: 12, name: "months" }, 28 | { amount: Number.POSITIVE_INFINITY, name: "years" }, 29 | ] 30 | const RELATIVE_DATE_FORMATTER = new Intl.RelativeTimeFormat(undefined, { 31 | numeric: "auto", 32 | }) 33 | export function formatRelativeDate(toDate, fromDate = new Date()) { 34 | let duration = (toDate - fromDate) / 1000 35 | 36 | for (let i = 0; i <= DIVISIONS.length; i++) { 37 | const division = DIVISIONS[i] 38 | if (Math.abs(duration) < division.amount) { 39 | return RELATIVE_DATE_FORMATTER.format(Math.round(duration), division.name) 40 | } 41 | duration /= division.amount 42 | } 43 | } 44 | --------------------------------------------------------------------------------