158 lines
4.7 KiB
JavaScript
158 lines
4.7 KiB
JavaScript
import { cloudflare as cloudflareConfig } from '@freesewing/config'
|
|
|
|
/*
|
|
* VARIABLES
|
|
*/
|
|
|
|
/*
|
|
* CSS classes to spread icon + text horizontally on a button
|
|
*/
|
|
export const horFlexClasses = 'flex flex-row items-center justify-between gap-4 w-full'
|
|
|
|
/*
|
|
* CSS classes to spread icon + text horizontally on a button, only from md upwards
|
|
*/
|
|
export const horFlexClassesNoSm =
|
|
'md:flex md:flex-row md:items-center md:justify-between md:gap-4 md-w-full'
|
|
|
|
/*
|
|
* FUNCTIONS
|
|
*/
|
|
|
|
/**
|
|
* A method to capitalize a string
|
|
*
|
|
* @param {string} string - The input string
|
|
* @return {string} String - The input string capitalized (first letter only)
|
|
*/
|
|
export function capitalize(string) {
|
|
return typeof string === 'string' ? string.charAt(0).toUpperCase() + string.slice(1) : ''
|
|
}
|
|
|
|
/*
|
|
* Returns the URL of a cloudflare image
|
|
* based on the ID and Variant
|
|
*
|
|
* @param {string} id - The image ID
|
|
* @param {string} variant - One of the cloudflare image variants
|
|
* @return {string} url - The image URL
|
|
*/
|
|
export function cloudflareImageUrl({ id = 'default-avatar', variant = 'public' }) {
|
|
/*
|
|
* Return something default so that people will actually change it
|
|
*/
|
|
if (!id || id === 'default-avatar') return cloudflareConfig.dflt
|
|
|
|
/*
|
|
* If the variant is invalid, set it to the smallest thumbnail so
|
|
* people don't load enourmous images by accident
|
|
*/
|
|
if (!cloudflareConfig.variants.includes(variant)) variant = 'sq100'
|
|
|
|
return `${cloudflareConfig.url}${id}/${variant}`
|
|
}
|
|
|
|
/*
|
|
* Parses value that should be a distance (cm or inch) into a value in mm
|
|
*
|
|
* This essentially exists for the benefit of imperial users who might input
|
|
* a string like `2 3/4` and we then have to make sense of that.
|
|
*
|
|
* @param {string} val - The original input
|
|
* @param {string} imperial - True if units are imperial (not metric)
|
|
* @return {number} mm - The result in millimeter
|
|
*/
|
|
export function distanceAsMm(val = false, imperial = false) {
|
|
// No input is not valid
|
|
if (!val) return false
|
|
|
|
// Cast to string, and replace comma with period
|
|
val = val.toString().trim().replace(',', '.')
|
|
|
|
// Regex pattern for regular numbers with decimal seperator or fractions
|
|
const regex = imperial
|
|
? /^-?[0-9]*(\s?[0-9]+\/|[.])?[0-9]+$/ // imperial (fractions)
|
|
: /^-?[0-9]*[.]?[0-9]+$/ // metric (no fractions)
|
|
if (!val.match(regex)) return false
|
|
|
|
// if fractions are allowed, parse for fractions, otherwise use the number as a value
|
|
if (imperial) val = fractionToDecimal(val)
|
|
|
|
return isNaN(val) ? false : Number(val)
|
|
}
|
|
|
|
/** convert a value that may contain a fraction to a decimal */
|
|
export function fractionToDecimal(value) {
|
|
// if it's just a number, return it
|
|
if (!isNaN(value)) return value
|
|
|
|
// keep a running total
|
|
let total = 0
|
|
|
|
// split by spaces
|
|
let chunks = String(value).split(' ')
|
|
if (chunks.length > 2) return Number.NaN // too many spaces to parse
|
|
|
|
// a whole number with a fraction
|
|
if (chunks.length === 2) {
|
|
// shift the whole number from the array
|
|
const whole = Number(chunks.shift())
|
|
// if it's not a number, return NaN
|
|
if (isNaN(whole)) return Number.NaN
|
|
// otherwise add it to the total
|
|
total += whole
|
|
}
|
|
|
|
// now we have only one chunk to parse
|
|
let fraction = chunks[0]
|
|
|
|
// split it to get numerator and denominator
|
|
let fChunks = fraction.trim().split('/')
|
|
// not really a fraction. return NaN
|
|
if (fChunks.length !== 2 || fChunks[1] === '') return Number.NaN
|
|
|
|
// do the division
|
|
let num = Number(fChunks[0])
|
|
let denom = Number(fChunks[1])
|
|
if (isNaN(num) || isNaN(denom)) return NaN
|
|
return total + num / denom
|
|
}
|
|
|
|
/*
|
|
* Convert a measurement to millimeter
|
|
*
|
|
* @param {number} value - The current value
|
|
* @param {string} units - One of metric or imperial
|
|
* @return {number} mm - The value in millimeter
|
|
*/
|
|
export function measurementAsMm(value, units = 'metric') {
|
|
if (typeof value === 'number') return value * (units === 'imperial' ? 25.4 : 10)
|
|
|
|
if (String(value).endsWith('.')) return false
|
|
|
|
if (units === 'metric') {
|
|
value = Number(value)
|
|
if (isNaN(value)) return false
|
|
return value * 10
|
|
} else {
|
|
const decimal = fractionToDecimal(value)
|
|
if (isNaN(decimal)) return false
|
|
return decimal * 24.5
|
|
}
|
|
}
|
|
|
|
/** convert a millimeter value to a Number value in the given units */
|
|
export function measurementAsUnits(mmValue, units = 'metric') {
|
|
return round(mmValue / (units === 'imperial' ? 25.4 : 10), 3)
|
|
}
|
|
|
|
/*
|
|
* Generic rounding method
|
|
*
|
|
* @param {number} val - The input number
|
|
* @param {number} decimals - Number of decimals to round to
|
|
* @return {number} result - The input val rounded to the number of decimals specified
|
|
*/
|
|
export function round(val, decimals = 1) {
|
|
return Math.round(val * Math.pow(10, decimals)) / Math.pow(10, decimals)
|
|
}
|