From 76bda8bb119a53270b0fcf6b4b3def21b6bcdd31 Mon Sep 17 00:00:00 2001 From: Jeremy Butler Date: Fri, 29 Sep 2023 08:06:38 +1000 Subject: [PATCH] Update formatters --- content/2.functions/detections.md | 144 ++++++++++++++++++++ utils/detections.ts | 215 ++++++++++++++++++++++++------ utils/formatters.ts | 89 +++++-------- utils/modifiers.ts | 34 ----- 4 files changed, 358 insertions(+), 124 deletions(-) create mode 100644 content/2.functions/detections.md diff --git a/content/2.functions/detections.md b/content/2.functions/detections.md new file mode 100644 index 00000000..aa3a3442 --- /dev/null +++ b/content/2.functions/detections.md @@ -0,0 +1,144 @@ +# Detections + +#### A collection of detections for common data types + +## getDeviceType +Detect if the current device is a mobile device + +```js [js] +getDeviceType() +``` + +## getRelativeMousePosition +Detect the current mouse position within a container via ID + +```js [js] +getRelativeMousePosition('container', event) +``` + +## getNetworkStatus +Detect the current network status of the user (Online or Offline) + +```js [js] +getNetworkStatus() +``` + +## getLocalStorage +Returns a local storage value by name and parses it into JSON + +```js [js] +getLocalStorage('name') +``` + +## getSessionStorage +Returns a session storage value by name and parses it into JSON + +```js [js] +getSessionStorage('name') +``` + +## getURLParameters +Returns a value from the URL by name + +```js [js] +getURLParameters('http://url.com/page?name=Adam&surname=Smith') +``` + +## getURLHashParameters +Returns a value from the URL hash by name + +```js [js] +getURLHashParameters() +``` + +## getURLSearchParameters +Retrieves and returns the parameters from the URL search query string + +```js [js] +getURLSearchParameters() +``` + +## getURL +Returns the current URL + +```js [js] +getURL() +``` + +## getDomain +Returns the current domain + +```js [js] +getDomain() +``` + +## getIP +Returns the current IP address + +```js [js] +getIP() +``` + +## getPort +Returns the current port + +```js [js] +getPort() +``` + +## getProtocol +Returns the current protocol (HTTP or HTTPS) + +```js [js] +getProtocol() +``` + +## getReferrer +Returns the URL of the referring page (the page that linked to the current page) + +```js [js] +getReferrer() +``` + +## getCachedData +Retrieves cached entries and optionally filters the entries based on a provided key + +```js [js] +getCachedData('abc') +``` + +## isInContainer +Detects if the element is currently in the container via ID + +```js [js] +isInContainer(element, 'container') +``` + +## isOverflowingY +Detects if the element is overflowing vertically + +```js [js] +isOverflowingY(element) +``` + +## isOverflowingX +Detects if the element is overflowing horizontally + +```js [js] +isOverflowingX(element) +``` + +## isScrollable +Detects if the element is scrollable (overflowing vertically or horizontally) + +```js [js] +isScrollable(element) +``` + +## isElement +Detects if the elements is an HTML element + +```js [js] +isElement(element) +``` + diff --git a/utils/detections.ts b/utils/detections.ts index cef74821..775274b3 100644 --- a/utils/detections.ts +++ b/utils/detections.ts @@ -1,19 +1,42 @@ -export function getDeviceType() { +// title: Detections +// description: A collection of detections for common data types + +/** + * Detect if the current device is a mobile device + * @example getDeviceType() + */ +export function getDeviceType(): string { return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ? 'Mobile' : 'Desktop' } +/** + * Detect if the browser window is currently active or hidden. + * @example getActiveBrowser() + */ export function getActiveBrowser(): boolean { - return document.hidden + return !document.hidden } +/** + * Detect the current color scheme + * @example getColorScheme() + */ export function getColorScheme(): string { return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' } +/** + * Detect the current browser + * @example getBrowser() + */ export function getBrowser(): string { return navigator.userAgent.toLowerCase() } +/** + * Detect the current operating system + * @example `getOS()` + */ export function getOS(): string { const userAgent = navigator.userAgent.toLowerCase() switch (true) { @@ -30,20 +53,44 @@ export function getOS(): string { } } +/** + * Detect the current browser language + * @example getBrowserLanguage() + */ export function getBrowserLanguage(): string { return navigator.language } +/** + * Detect the current user's location + * @example getUserLocation() + */ export function getGeolocation(): Promise { return new Promise((resolve, reject) => { navigator.geolocation.getCurrentPosition(resolve, reject) }) } +/** + * Detect the current user's Timezone + * @example getUserTimezone() + */ +export function getUserTimezone(): string { + return Intl.DateTimeFormat().resolvedOptions().timeZone +} + +/** + * Detect the currect device orientation + * @example getDeviceOrientation() + */ export function getDeviceOrientation(): string { return window.screen.orientation.type } +/** + * Detect the current device motion + * @example getDeviceMotion() + */ export function getDeviceMotion(): Promise { return new Promise((resolve, reject) => { window.addEventListener('devicemotion', resolve, { once: true }) @@ -51,32 +98,10 @@ export function getDeviceMotion(): Promise { }) } -// export function getDeviceLight(): Promise { -// return new Promise((resolve, reject) => { -// window.addEventListener( -// 'devicelight', -// (event: Event) => { -// resolve((event as any).value) -// }, -// { once: true } -// ) -// setTimeout(reject, 5000) -// }) -// } - -export function getDeviceProximity(): Promise { - return new Promise((resolve, reject) => { - window.addEventListener( - 'deviceproximity', - (evt: Event) => { - resolve((evt as any).value) - }, - { once: true } - ) - setTimeout(reject, 5000) - }) -} - +/** + * Detect the browser's window size + * @example getWindowSize() + */ export function getWindowSize(): { width: number; height: number } { return { width: window.innerWidth, @@ -84,6 +109,10 @@ export function getWindowSize(): { width: number; height: number } { } } +/** + * Detect the screen or monitor size + * @example getScreenSize() + */ export function getScreenSize(): { width: number; height: number } { return { width: window.screen.width, @@ -91,6 +120,10 @@ export function getScreenSize(): { width: number; height: number } { } } +/** + * Detect the container size via ID + * @example getContainerSize('container') + */ export function getContainerSize(id: string): { width: number; height: number } { const element = document.getElementById(id) if (!element) return { width: 0, height: 0 } @@ -100,6 +133,10 @@ export function getContainerSize(id: string): { width: number; height: number } } } +/** + * Detect the current breakpoint based on Tailwind CSS breakpoints + * @example getTailwindBreakpoint() + */ export function getTailwindBreakpoint(): string { const width = window.innerWidth switch (true) { @@ -118,6 +155,10 @@ export function getTailwindBreakpoint(): string { } } +/** + * Detect the current container breakpoint based on Tailwind CSS breakpoints + * @example getTailwindContainerBreakpoint('container') + */ export function getTailwindContainerBreakpoint(id: string): string { const width = getContainerSize(id).width switch (true) { @@ -148,6 +189,10 @@ export function getTailwindContainerBreakpoint(id: string): string { } } +/** + * Detect the current scroll position of the window + * @example getScrollPosition() + */ export function getScrollPosition(): { x: number; y: number } { return { x: window.scrollX, @@ -155,6 +200,10 @@ export function getScrollPosition(): { x: number; y: number } { } } +/** + * Detect the current mouse position within the window + * @example getMousePosition(event) + */ export function getMousePosition(event: MouseEvent) { return { x: event.pageX, @@ -162,6 +211,10 @@ export function getMousePosition(event: MouseEvent) { } } +/** + * Detect the current mouse position within a container via ID + * @example getRelativeMousePosition('container', event) + */ export function getRelativeMousePosition(id: string, e: MouseEvent) { const element = document.getElementById(id) if (!element) return { x: 0, y: 0 } @@ -172,16 +225,18 @@ export function getRelativeMousePosition(id: string, e: MouseEvent) { } } -export function getScreenOrientation(): string { - return window.screen.orientation.type -} - +/** + * Detect the current network status of the user (Online or Offline) + * @example getNetworkStatus() + */ export function getNetworkStatus(): string { return navigator.onLine ? 'Online' : 'Offline' } -export function getBatteryStatus() {} - +/** + * Detect the current memory status of the user (RAM) + * @example getMemoryStatus() + */ export function getMemoryStatus(): { totalJSHeapSize: number; usedJSHeapSize: number; jsHeapSizeLimit: number } { return { totalJSHeapSize: (performance as any).memory.totalJSHeapSize, @@ -190,6 +245,10 @@ export function getMemoryStatus(): { totalJSHeapSize: number; usedJSHeapSize: nu } } +/** + * Detect the current performance status of the user (CPU, RAM, etc.) + * @example getPerformance() + */ export function getPerformance(): Promise { return new Promise((resolve, reject) => { window.addEventListener('load', () => { @@ -199,6 +258,10 @@ export function getPerformance(): Promise { }) } +/** + * Detect the current storage status of the user (Local Storage, Session Storage) + * @example getStorage() + */ export function getStorage(): { localStorage: number; sessionStorage: number } { return { localStorage: JSON.stringify(localStorage).length, @@ -206,22 +269,38 @@ export function getStorage(): { localStorage: number; sessionStorage: number } { } } +/** + * Returns a cookie value by name + * @example getCookie('name') + */ export function getCookie(name: string) { const value = '; ' + document.cookie const parts = value.split('; ' + name + '=') if (parts.length === 2) return parts.pop()?.split(';').shift() } +/** + * Returns a local storage value by name and parses it into JSON + * @example getLocalStorage('name') + */ export function getLocalStorage(name: string) { const item = localStorage.getItem(name) if (item) return JSON.parse(item) } +/** + * Returns a session storage value by name and parses it into JSON + * @example getSessionStorage('name') + */ export function getSessionStorage(name: string) { const item = sessionStorage.getItem(name) if (item) return JSON.parse(item) } +/** + * Returns a value from the URL by name + * @example getURLParameters('http://url.com/page?name=Adam&surname=Smith') + */ export function getURLParameters(url: string, param?: string) { const params = (url.match(/([^?=&]+)(=([^&]*))/g) || []).reduce((a: any, v: any) => ((a[v.slice(0, v.indexOf('='))] = v.slice(v.indexOf('=') + 1)), a), {}) @@ -232,38 +311,74 @@ export function getURLParameters(url: string, param?: string) { return params } +/** + * Returns a value from the URL hash by name + * @example getURLHashParameters() + */ export function getURLHashParameters() { return getURLParameters(window.location.hash) } +/** + * Retrieves and returns the parameters from the URL search query string + * @example getURLSearchParameters() + */ export function getURLSearchParameters() { return getURLParameters(window.location.search) } +/** + * Returns the current URL + * @example getURL() + */ export function getURL() { return window.location.href } +/** + * Returns the current domain + * @example getDomain() + */ export function getDomain() { return window.location.hostname } +/** + * Returns the current IP address + * @example getIP() + */ export function getIP() { return window.location.host } -export function getProtocol() { - return window.location.protocol -} - +/** + * Returns the current port + * @example getPort() + */ export function getPort() { return window.location.port } +/** + * Returns the current protocol (HTTP or HTTPS) + * @example getProtocol() + */ +export function getProtocol() { + return window.location.protocol +} + +/** + * Returns the URL of the referring page (the page that linked to the current page) + * @example getReferrer() + */ export function getReferrer() { return document.referrer } +/** + * Retrieves cached entries and optionally filters the entries based on a provided key + * @example getCachedData('abc') + */ export function getCachedData(key?: string): PerformanceEntry[] { const cachedData = window.performance.getEntriesByType('resource') @@ -276,6 +391,10 @@ export function getCachedData(key?: string): PerformanceEntry[] { // Is it? +/** + * Detects if the element is currently in the viewport + * @example isInViewport(element) + */ export function isInViewport(element: HTMLElement) { const rect = element.getBoundingClientRect() return ( @@ -286,6 +405,10 @@ export function isInViewport(element: HTMLElement) { ) } +/** + * Detects if the element is currently in the container via ID + * @example isInContainer(element, 'container') + */ export function isInContainer(element: HTMLElement, id: string) { const rect = element.getBoundingClientRect() const container = document.getElementById(id) @@ -294,18 +417,34 @@ export function isInContainer(element: HTMLElement, id: string) { return rect.top >= containerRect.top && rect.left >= containerRect.left && rect.bottom <= containerRect.bottom && rect.right <= containerRect.right } +/** + * Detects if the element is overflowing vertically + * @example isOverflowingY(element) + */ export function isOverflowingY(element: HTMLElement) { return element.scrollWidth > element.clientWidth || element.scrollHeight > element.clientHeight } +/** + * Detects if the element is overflowing horizontally + * @example isOverflowingX(element) + */ export function isOverflowingX(element: HTMLElement) { return element.scrollWidth > element.clientWidth } +/** + * Detects if the element is scrollable (overflowing vertically or horizontally) + * @example isScrollable(element) + */ export function isScrollable(element: HTMLElement) { return isOverflowingY(element) || isOverflowingX(element) } +/** + * Detects if the elements is an HTML element + * @example isElement(element) + */ export function isElement(element: HTMLElement) { return element instanceof HTMLElement } diff --git a/utils/formatters.ts b/utils/formatters.ts index 5341b9f1..bd94be87 100644 --- a/utils/formatters.ts +++ b/utils/formatters.ts @@ -42,58 +42,43 @@ export function formatTime(seconds: number): string { } /** - * Format Phone Number + * Format a number into a percentage + * @example formatPercentage(0.1234) + * @returns 12.34% */ +export function formatPercentage(number: number): string { + return `${(number * 100).toFixed(2)}%` +} -// TODO: Make more robust -// export function formatPhoneNumber(number: string, country: string = 'US'): string { -// const patterns: { [key: string]: RegExp } = { -// US: /^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$/, -// UK: /^(\(?(?:0(?:0|11)\)?[\s-]?\(?|\+)44\)?[\s-]?)?\(?0?(?:\)[\s-]?)?([1-9]\d{1,4}\)?[\d\s-]+)((?:x|ext\.?\s?|\#)\d{3,4})?$/, -// CA: /^(\+?1[-.\s]?)?\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$/, -// BR: /^(\+?55[-.\s]?)?\(?([0-9]{2})\)?[-. ]?([0-9]{4,5})[-. ]?([0-9]{4})$/, -// AU: /^(\+?61[-.\s]?)?\(?(0?[2-57-8])\)?[-. ]?([0-9]{4})[-. ]?([0-9]{4})$/, -// DE: /^(\+?49[-.\s]?)?\(?([0-9]{2,3})\)?[-. ]?([0-9]{3,4})[-. ]?([0-9]{4})$/, -// FR: /^(\+?33[-.\s]?)?\(?([0-9]{1,5})\)?[-. ]?([0-9]{2})[-. ]?([0-9]{2})[-. ]?([0-9]{2})$/, -// IN: /^(\+?91|0)?[6789]\d{9}$/, -// NZ: /^(\+?64|0)[28]\d{7,9}$/, -// ZA: /^(\+?27|0)\d{9}$/, -// ZM: /^(\+?26)?09[567]\d{7}$/, -// ES: /^(\+?34)?(6\d{1}|7[1234])\d{7}$/, -// SE: /^(\+?46|0)[\s-]?7[\s-]?[02369]([\s-]?\d){7}$/, -// CH: /^(\+?41|0)(\d{2})?[\s-]?(\d{3})[\s-]?(\d{2})[\s-]?(\d{2})$/, -// TW: /^(\+?886-?|0)?9\d{8}$/, -// CZ: /^(\+?420)? ?[1-9][0-9]{2} ?[0-9]{3} ?[0-9]{3}$/, -// BE: /^(\+?32|0)4?\d{8}$/, -// PT: /^(\+351)?9[1236]\d{7}$/, -// GR: /^(\+?30)?(69\d{8})$/, -// HU: /^(\+?36)(20|30|70)\d{7}$/, -// IL: /^(\+972|0)([23489]|5[0248]|77)[1-9]\d{6}$/, -// IT: /^(\+?39)?\s?3\d{2} ?\d{6,7}$/, -// AR: /^(\+?549|0)(11|[2368]\d)\d{8}$/, -// MX: /^(\+?52)?(1|01)?\d{10,11}$/, -// PK: /^(\+?92|0)?[3456789]?\d{9}$/, -// JP: /^(\+?81|0)\d{1,4}[ -]?\d{1,4}[ -]?\d{4}$/ -// } - -// if (!patterns[country]) { -// throw new Error(`Unsupported country code: ${country}`) -// } - -// let replacementPattern: string -// const captureGroupsCount = (patterns[country].toString().match(/\(\?/g) || []).length -// switch (captureGroupsCount) { -// case 2: -// replacementPattern = '$1-$2' -// break -// case 3: -// replacementPattern = '$1-$2-$3' -// break - -// default: -// replacementPattern = number -// break -// } +/** + * Create a string of comma-separated values from an array of strings with an optional conjunction. + * @param items - The array of strings. + * @param limit - The maximum number of items to include before truncating. + * @param conjunction - The conjunction before the last item e.g. "and" or "or". + * @example commaList(['one', 'two', 'three']) + * @returns one, two and three + */ +export function formatList(items: any[], limit: number, conjunction: string = 'and'): string { + if (items.length === 1) { + return items[0] + } + if (items.length === 2) { + return items.join(' ' + conjunction + ' ') + } + if (items.length === 3) { + return items.slice(0, -1).join(', ') + ' ' + conjunction + ' ' + items.slice(-1) + } + if (items.length > 3) { + return items.slice(0, limit).join(', ') + ' ' + conjunction + ' ' + (items.length - limit) + ' more' + } + return '' +} -// return number.replace(patterns[country], replacementPattern) -// } +/** + * Format Unix timestamp into a datetime string + * @example formatDatetime(1619097600) + * @returns 2021-04-22 00:00:00 + */ +export function formatDatetime(timestamp: number): string { + return new Date(timestamp * 1000).toISOString().replace('T', ' ').replace('Z', '') +} diff --git a/utils/modifiers.ts b/utils/modifiers.ts index 41751413..b9bc6f73 100644 --- a/utils/modifiers.ts +++ b/utils/modifiers.ts @@ -492,40 +492,6 @@ export function list(items: any[], listType: string = 'ul'): string { } } -/** - * Create a string of comma-separated values from an array of strings with an optional conjunction. - * @param items - The array of strings. - * @param conjunction - The conjunction before the last item e.g. "and" or "or". - * @example commaList(['one', 'two', 'three']) - * @returns one, two and three - */ -export function commaList(items: any[], conjunction: string = 'and'): string { - return items.slice(0, -1).join(', ') + ' ' + conjunction + ' ' + items.slice(-1) -} - -/** - * Create a string of comma-separated values with a limit and an optional conjunction. - * @param items - The array of strings. - * @param limit - The number of items to show before truncating. - * @example truncateList(['one', 'two', 'three', 'four', 'five'], 3) - * @returns one, two, three and 2 more - */ -export function truncateList(items: any[], limit: number, conjunction: string = 'and'): string { - if (items.length === 1) { - return items[0] - } - if (items.length === 2) { - return items.join(' ' + conjunction + ' ') - } - if (items.length === 3) { - return items.slice(0, -1).join(', ') + ' ' + conjunction + ' ' + items.slice(-1) - } - if (items.length > 3) { - return items.slice(0, limit).join(', ') + ' ' + conjunction + ' ' + (items.length - limit) + ' more' - } - return '' -} - /** * Shuffles an array. * @example shuffle(['one', 'two', 'three'])