├── 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 |
--------------------------------------------------------------------------------