An ATproto social media client -- with an independent Appview.

feat: convenience methods

serenity 1462e156 f963e0d8

+79 -21
+18 -21
src/alf/util/colors/conversion.ts
··· 1 - export interface HslColor { 2 - h: number 3 - s: number 4 - l: number 5 - } 6 - 7 - export interface RgbColor { 8 - r: number 9 - g: number 10 - b: number 11 - } 12 - 13 - export type HexCode = `#${string}` | string 1 + import {type HexCode, type HslColor, type RgbColor} from '#/alf/util/colors' 14 2 15 3 /** 16 4 * Converts a hexcode string in the format `"#RRGGBB"` to a `HslColor` object (`{ h: number, s: number, l: number }`). ··· 23 11 const r = parseInt(hex.substring(0, 2), 16) / 255 24 12 const g = parseInt(hex.substring(2, 4), 16) / 255 25 13 const b = parseInt(hex.substring(4, 6), 16) / 255 14 + const a = hex.length > 6 ? parseInt(hex.substring(6, 8), 16) / 255 : undefined 26 15 27 16 const max = Math.max(r, g, b) 28 17 const min = Math.min(r, g, b) ··· 57 46 h: h * 360, 58 47 s: s * 100, 59 48 l: l * 100, 49 + a, 60 50 } 61 51 } 62 52 ··· 67 57 * @returns {HexCode} A hexcode string in the format `"#RRGGBB"`. The leading "#" symbol is optional. 68 58 */ 69 59 export const hslToHex = ( 70 - {h, s, l}: HslColor, 60 + {h, s, l, a}: HslColor, 71 61 appendSymbol: boolean = true, 72 62 ): HexCode => { 73 63 h = (h % 360) / 360 ··· 103 93 const g = hue(h) * 255 104 94 const b = hue(h - 1 / 3) * 255 105 95 106 - return `${appendSymbol ? '#' : ''}${r.toString(16)}${g.toString(16)}${b.toString(16)}` 96 + return `${appendSymbol ? '#' : ''}${r.toString(16)}${g.toString(16)}${b.toString(16)}${a ? a.toString(16) : ''}` 107 97 } 108 98 109 99 /** ··· 113 103 * @returns {HexCode} A hexcode string in the format `"#RRGGBB"`. The leading "#" symbol is optional. 114 104 */ 115 105 export const rgbToHex = ( 116 - {r, g, b}: RgbColor, 106 + {r, g, b, a}: RgbColor, 117 107 appendSymbol: boolean = true, 118 108 ): HexCode => { 119 - return `${appendSymbol ? '#' : ''}${r.toString(16)}${g.toString(16)}${b.toString(16)}` 109 + return `${appendSymbol ? '#' : ''}${r.toString(16)}${g.toString(16)}${b.toString(16)}${a ? a.toString(16) : ''}` 120 110 } 121 111 122 112 /** ··· 129 119 const r = parseInt(hex.substring(0, 2), 16) / 255 130 120 const g = parseInt(hex.substring(2, 4), 16) / 255 131 121 const b = parseInt(hex.substring(4, 6), 16) / 255 132 - return {r, g, b} 122 + const a = hex.length > 6 ? parseInt(hex.substring(6, 8), 16) / 255 : undefined 123 + return {r, g, b, a} 133 124 } 134 125 135 126 /** ··· 137 128 * @param {RgbColor} - An RGB colour object. 138 129 * @returns {HslColor} A HSL colour object. 139 130 */ 140 - export const rgbToHsl = ({r, g, b}: RgbColor): HslColor => { 131 + export const rgbToHsl = ({r, g, b, a}: RgbColor): HslColor => { 141 132 r = r / 255 142 133 g = g / 255 143 134 b = b / 255 ··· 174 165 h: h * 360, 175 166 s: s * 100, 176 167 l: l * 100, 168 + a: a ? (a / 255) * 100 : undefined, 177 169 } 178 170 } 179 171 ··· 182 174 * @param {HslColor} - A HSL colour object. 183 175 * @returns {RgbColor} An RGB colour object. 184 176 */ 185 - export const hslToRgb = ({h, s, l}: HslColor): RgbColor => { 177 + export const hslToRgb = ({h, s, l, a}: HslColor): RgbColor => { 186 178 h = (h % 360) / 360 187 179 s = Math.max(0, Math.min(1, s / 100)) 188 180 l = Math.max(0, Math.min(1, l / 100)) ··· 216 208 const g = hue(h) * 255 217 209 const b = hue(h - 1 / 3) * 255 218 210 219 - return {r: Math.round(r), g: Math.round(g), b: Math.round(b)} 211 + return { 212 + r: Math.round(r), 213 + g: Math.round(g), 214 + b: Math.round(b), 215 + a: a ? (a / 100) * 255 : undefined, 216 + } 220 217 }
+61
src/alf/util/colors/index.ts
··· 1 + import {hexToHsl, hslToHex} from '#/alf/util/colors/conversion' 2 + 3 + export interface HslColor { 4 + h: number 5 + s: number 6 + l: number 7 + a?: number 8 + } 9 + 10 + export interface RgbColor { 11 + r: number 12 + g: number 13 + b: number 14 + a?: number 15 + } 16 + 17 + export type HexCode = `#${string}` | string 18 + 19 + export const clamp = (val: number) => { 20 + return Math.min(1, Math.max(0, val)) 21 + } 22 + 23 + export const lighten = ( 24 + hex: HexCode, 25 + amount: number, 26 + method: 'relative' | undefined = undefined, 27 + ) => { 28 + const hsl = hexToHsl(hex) 29 + 30 + if (typeof method !== 'undefined' && method === 'relative') { 31 + hsl.l += (hsl.l * amount) / 100 32 + } else { 33 + hsl.l += amount / 100 34 + } 35 + hsl.l = clamp(hsl.l) 36 + return hslToHex(hsl) 37 + } 38 + 39 + export const darken = ( 40 + hex: HexCode, 41 + amount: number, 42 + method: 'relative' | undefined = undefined, 43 + ) => { 44 + const hsl = hexToHsl(hex) 45 + 46 + if (typeof method !== 'undefined' && method === 'relative') { 47 + hsl.l -= (hsl.l * amount) / 100 48 + } else { 49 + hsl.l -= amount / 100 50 + } 51 + hsl.l = clamp(hsl.l) 52 + return hslToHex(hsl) 53 + } 54 + 55 + export const fade = (hex: HexCode, amount: number) => { 56 + const hsl = hexToHsl(hex) 57 + 58 + hsl.a = amount / 100 59 + hsl.a = clamp(hsl.a) 60 + return hslToHex(hsl) 61 + }