create transparentifyColor function

This commit is contained in:
Samuel Newman
2025-06-11 20:51:27 +03:00
parent 9828490fd0
commit 1a3107dba7
3 changed files with 79 additions and 3 deletions
+48
View File
@@ -0,0 +1,48 @@
import {jest} from '@jest/globals'
import {logger} from '#/logger'
import {transparentifyColor} from '../colorGeneration'
jest.mock('#/logger', () => ({
logger: {warn: jest.fn()},
}))
describe('transparentifyColor', () => {
beforeEach(() => {
jest.clearAllMocks()
})
it('converts hsl() to hsla()', () => {
const result = transparentifyColor('hsl(120 100% 50%)', 0.5)
expect(result).toBe('hsla(120 100% 50%, 0.5)')
})
it('converts hsl() to hsla() - fully transparent', () => {
const result = transparentifyColor('hsl(120 100% 50%)', 0)
expect(result).toBe('hsla(120 100% 50%, 0)')
})
it('converts rgb() to rgba()', () => {
const result = transparentifyColor('rgb(255 0 0)', 0.75)
expect(result).toBe('rgba(255 0 0, 0.75)')
})
it('expands 3-digit hex and appends alpha channel', () => {
const result = transparentifyColor('#abc', 0.4)
expect(result).toBe('#aabbcc66')
})
it('appends alpha to 6-digit hex', () => {
const result = transparentifyColor('#aabbcc', 0.4)
expect(result).toBe('#aabbcc66')
})
it('returns the original string and warns for unsupported formats', () => {
const unsupported = 'blue'
const result = transparentifyColor(unsupported, 0.5)
expect(result).toBe(unsupported)
expect(logger.warn).toHaveBeenCalledWith(
`Could not make '${unsupported}' transparent`,
)
})
})
+28
View File
@@ -1,3 +1,5 @@
import {logger} from '#/logger'
export const BLUE_HUE = 211 export const BLUE_HUE = 211
export const RED_HUE = 346 export const RED_HUE = 346
export const GREEN_HUE = 152 export const GREEN_HUE = 152
@@ -19,3 +21,29 @@ export function generateScale(start: number, end: number) {
export const defaultScale = generateScale(6, 100) export const defaultScale = generateScale(6, 100)
// dim shifted 6% lighter // dim shifted 6% lighter
export const dimScale = generateScale(12, 100) export const dimScale = generateScale(12, 100)
export function transparentifyColor(color: string, alpha: number) {
if (color.startsWith('hsl(')) {
return 'hsla(' + color.slice('hsl('.length, -1) + `, ${alpha})`
} else if (color.startsWith('rgb(')) {
return 'rgba(' + color.slice('rgb('.length, -1) + `, ${alpha})`
} else if (color.startsWith('#')) {
if (color.length === 7) {
const alphaHex = Math.round(alpha * 255).toString(16)
// Per MDN: If there is only one number, it is duplicated: e means ee
// https://developer.mozilla.org/en-US/docs/Web/CSS/hex-color
return color.slice(0, 7) + alphaHex.padStart(2, alphaHex)
} else if (color.length === 4) {
// convert to 6-digit hex before adding alpha
const [r, g, b] = color.slice(1).split('')
const alphaHex = Math.round(alpha * 255).toString(16)
return `#${r.repeat(2)}${g.repeat(2)}${b.repeat(2)}${alphaHex.padStart(
2,
alphaHex,
)}`
}
} else {
logger.warn(`Could not make '${color}' transparent`)
}
return color
}
@@ -10,6 +10,7 @@ import {useProfileQuery} from '#/state/queries/profile'
import {useSession} from '#/state/session' import {useSession} from '#/state/session'
import {UserAvatar} from '#/view/com/util/UserAvatar' import {UserAvatar} from '#/view/com/util/UserAvatar'
import {atoms as a, ios, native, useBreakpoints, useTheme} from '#/alf' import {atoms as a, ios, native, useBreakpoints, useTheme} from '#/alf'
import {transparentifyColor} from '#/alf/util/colorGeneration'
import {useInteractionState} from '#/components/hooks/useInteractionState' import {useInteractionState} from '#/components/hooks/useInteractionState'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
@@ -47,12 +48,11 @@ export function PostThreadComposePrompt({
]}> ]}>
{!gtMobile && ( {!gtMobile && (
<LinearGradient <LinearGradient
key={t.name} // android does not update when you change the colors. sigh.
start={[0.5, 0]} start={[0.5, 0]}
end={[0.5, 1]} end={[0.5, 1]}
colors={[ colors={[
// "white transparent" - the CSS transparent keyword transparentifyColor(t.atoms.bg.backgroundColor, 0),
// is black transparent
'rgba(255, 255, 255, 0)',
t.atoms.bg.backgroundColor, t.atoms.bg.backgroundColor,
]} ]}
locations={[0.15, 0.4]} locations={[0.15, 0.4]}