Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions packages/tools/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# `tools`

> TODO: description

## Usage

```
const tools = require('tools');

// TODO: DEMONSTRATE API
```
21 changes: 21 additions & 0 deletions packages/tools/__tests__/hex.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import Hex from '../lib/colors/hex'

describe('Hex', () => {
let instance;

beforeEach(() => {
instance = new Hex('rgba(255,25,2,0.5)')
});

it('toString()', () => {
expect(instance.toString()).toBe('ff190280')
})

it('toPrefixString() takes default prefix', () => {
expect(instance.toPrefixString()).toBe('#ff190280')
})

it('toPrefixString() takes prefix', () => {
expect(instance.toPrefixString('rgba:')).toBe('rgba:ff190280')
})
});
57 changes: 57 additions & 0 deletions packages/tools/__tests__/rgbaConverter.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { RGBAToHexA } from '../lib/colors/rgbaConverter'

describe('RGBAToHexA', () => {
it('converts from rgba(num, num, num, float)', () => {
expect(RGBAToHexA("rgba(255,25,2,0.5)")).toEqual({
red: "ff",
green: "19",
blue: "02",
alpha: "80"
})
})

it('converts from rgba(num num num / float)', () => {
expect(RGBAToHexA("rgba(255 25 2 / 0.5)")).toEqual({
red: "ff",
green: "19",
blue: "02",
alpha: "80"
})
})

it('converts from rgba(%, %, %, float)', () => {
expect(RGBAToHexA("rgba(50%,30%,10%,0.5)")).toEqual({
red: "80",
green: "4d",
blue: "1a",
alpha: "80"
})
})

it('converts from rgba(%, %, %, %)', () => {
expect(RGBAToHexA("rgba(50%,30%,10%,50%)")).toEqual({
red: "80",
green: "4d",
blue: "1a",
alpha: "80"
})
})

it('converts from rgba(% % % / float)', () => {
expect(RGBAToHexA("rgba(50% 30% 10% / 0.5)")).toEqual({
red: "80",
green: "4d",
blue: "1a",
alpha: "80"
})
})

it('converts from rgba(% % % / %)', () => {
expect(RGBAToHexA("rgba(50% 30% 10% / 50%)")).toEqual({
red: "80",
green: "4d",
blue: "1a",
alpha: "80"
})
})
});
25 changes: 25 additions & 0 deletions packages/tools/__tests__/socialcard.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { buildSocialCard} from '../lib/socialCard'

describe('SocialCard', () => {
it('should return a card', () => {
expect(buildSocialCard({
title: {
value: 'Deploy a Node.js App to DigitalOcean with SSL',
font:'futura',
},
tagline: {
value: '#devops #nodejs #ssl',
font:'futura',
},
image: {
publicId: 'lwj/blog-post-card',
},
text: {
color: '232129',
width: 760,
}
}, {
cloudName: 'jlengstorf'
})).toBe('https://res.cloudinary.com/jlengstorf/image/upload/c_fill,w_1280,h_669,q_auto,f_auto/c_fit,w_760,x_480,y_254,g_south_west,l_text:futura_64:Deploy%20a%20Node.js%20App%20to%20DigitalOcean%20with%20SSL,co_rgb:232129/c_fit,w_760,x_480,y_445,g_north_west,l_text:futura_48:%2523devops%20%2523nodejs%20%2523ssl,co_rgb:232129/lwj/blog-post-card')
});
});
34 changes: 34 additions & 0 deletions packages/tools/jest.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"preset": "ts-jest",
"testEnvironment": "node",
"bail": true,
"collectCoverageFrom": [
"<rootDir>/lib/**/*.ts",
"<rootDir>/lib/**/*.ts"
],
"modulePaths": [
"<rootDir>/lib"
],
"coverageThreshold": {
"global": {
"branches": 95,
"functions": 95,
"lines": 95,
"statements": 95
}
},
"globals": {
"ts-jest": {
"diagnostics": false
}
},
"reporters": [
"default",
["jest-html-reporters", {
"publicPath" : "./public/progress/",
"filename": "api-tools-report.html",
"pageTitle": "tools Report",
"expand": true
}]
]
}
29 changes: 29 additions & 0 deletions packages/tools/lib/colors/hex.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@

import { RGBAToHexA } from './rgbaConverter'
import { RGBA } from '../types/RGBA'

export class Hex implements RGBA {
red: string
green: string
blue: string
alpha?: string = ''

constructor(rgba:string) {
const colors = RGBAToHexA(rgba)

this.red = colors.red
this.green = colors.green
this.blue = colors.blue
this.alpha = colors.alpha || ''
}

toString():string {
return `${this.red}${this.green}${this.blue}${this.alpha}`
}

toPrefixString(prefix: string = '#'):string {
return `${prefix}${this.toString()}`
}
}

export default Hex
51 changes: 51 additions & 0 deletions packages/tools/lib/colors/hexConverter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import type { RGBA} from '../types/RGBA'

export const HEXToRGBA = (hex: string, isPct: boolean = false):RGBA => {

let r = 0, g = 0, b = 0, a = 1;

a = +(a / 255).toFixed(3);
if (h.length == 5) {
r = "0x" + h[1] + h[1];
g = "0x" + h[2] + h[2];
b = "0x" + h[3] + h[3];
a = "0x" + h[4] + h[4];

} else if (h.length == 9) {
r = "0x" + h[1] + h[2];
g = "0x" + h[3] + h[4];
b = "0x" + h[5] + h[6];
a = "0x" + h[7] + h[8];
}

if (isPct) {
r = +(r / 255 * 100).toFixed(1);
g = +(g / 255 * 100).toFixed(1);
b = +(b / 255 * 100).toFixed(1);
}

}

export const HEXToRGB = (hex: string) => {
if (hex.length < 4 ||)

let r = 0, g = 0, b = 0;
isPct = isPct === true;

if (h.length == 4) {
r = "0x" + h[1] + h[1];
g = "0x" + h[2] + h[2];
b = "0x" + h[3] + h[3];

} else if (h.length == 7) {
r = "0x" + h[1] + h[2];
g = "0x" + h[3] + h[4];
b = "0x" + h[5] + h[6];
}

if (isPct) {
r = +(r / 255 * 100).toFixed(1);
g = +(g / 255 * 100).toFixed(1);
b = +(b / 255 * 100).toFixed(1);
}
}
97 changes: 97 additions & 0 deletions packages/tools/lib/colors/rgbaConverter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { RGBA } from '../types/RGBA'

const toHEXValue = (num):string => num.toString(16)
const SEPARATION = ','

export const parseRGBAColorStr = (rgba: string): number[] => {
const sep = rgba.includes(SEPARATION) ? SEPARATION : " ";
const indexToParse = rgba.indexOf('(')
const colors:string[] = rgba.substr(indexToParse + 1).split(")")[0].split(sep)

// Strip the slash if using space-separated syntax
if (colors.includes("/")) {
colors.splice(3, 1)
}

const mappedColors = colors.map((color, index) => {
if (!color.includes("%")) return +color

// Convert %s to 0–255
const pixels = +(color.substr(0, color.length - 1)) / 100

return index < 3 ? Math.round(pixels * 255) : pixels
})

return mappedColors
}

export const RGBAToHexA = (rgba:string):RGBA => {
const colors:number[] = parseRGBAColorStr(rgba)

const colorIndex:string[] = ["red", "green", "blue", "alpha"]

const RGBAObj:RGBA = colors.reduce((obj:any, color:number , index: number) => {
const value = toHEXValue(index === 3 ? Math.round(color * 255) : color)

obj[colorIndex[index]] = value.length === 1 ? `0${value}` : value
return obj
}, {})

return RGBAObj
}

export const RGBAToHSL = (rgba : string) => {
const colors:number[] = parseRGBAColorStr(rgba)

const mappedRGB = colors.map(color => color / 255)

if (mappedRGB.length > 3) { mappedRGB.pop() }

const channel = {
min: Math.min(...mappedRGB),
max: Math.max(...mappedRGB),
};

const hue = calculateHue(channel, { red: mappedRGB[0], green: mappedRGB[1], blue: mappedRGB[2] })
const lightness = calculateLightness(channel)
const saturation = calculateSaturation(channel)

return {
hue,
lightness,
saturation,
alpha: colors[3]
}
}

const calculateHue = (channel, colors) => {
const delta = channel.max - channel.min

if (delta === 0) return 0

let baseHue = (colors.red - colors.green) / delta + 4

if (channel.max === colors.red) {
baseHue = (colors.green - colors.blue) / delta % 6
} else if (channel.max === colors.green) {
baseHue = (colors.blue - colors.red) / delta + 2
}

const roundHue = Math.round(baseHue * 60)

return roundHue < 0 ? roundHue + 360 : roundHue
}

const calculateLightness = (channel):number => +(((channel.max + channel.min) / 2) * 100).toFixed(1)

const calculateSaturation = (channel):number => {
const delta = channel.max - channel.min

if (delta === 0) return 0

const lightness = (channel.max + channel.min) / 2

const saturation = delta / (1 - Math.abs(2 * lightness - 1))

return +(saturation * 100).toFixed(1)
}
5 changes: 5 additions & 0 deletions packages/tools/lib/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Hex from './colors/hex'
import { RGBAToHexA } from './colors/rgbaConverter'
import type { RGBA } from './types/RGBA'

export { Hex, RGBAToHexA, RGBA }
Loading