Repository: h2oai/wave
File: py/examples/theme_generator.py (Python)

Code before:
from pygments.style import Style
from pygments.token import Name, String, Operator, Punctuation

import math

py_lexer = get_lexer_by_name('python')


def to_grayscale(color: float) -> float:
    color /= 255
    return color / 12.92 if color <= 0.03928 else math.pow((color + 0.055) / 1.055, 2.4)


def get_luminance(r: float, g: float, b: float) -> float:
    return to_grayscale(r) * 0.2126 + to_grayscale(g) * 0.7152 + to_grayscale(b) * 0.0722


# Source: https://www.delftstack.com/howto/python/python-hex-to-rgb/.
def hex_to_rgb(hex_color: str) -> Tuple[int, ...]:
    if len(hex_color) == 3:
        hex_color = f'{hex_color[0]}{hex_color[0]}{hex_color[1]}{hex_color[1]}{hex_color[2]}{hex_color[2]}'
    return tuple(int(hex_color[i:i + 2], 16) for i in (0, 2, 4))


# Source: https://stackoverflow.com/questions/9733288/how-to-programmatically-calculate-the-contrast-ratio-between-two-colors. # noqa
def get_contrast(color1: str, color2: str, q: Q, min_contrast=4.5):
    rgb1 = hex_to_rgb(q.client[color1].lstrip('#'))
    rgb2 = hex_to_rgb(q.client[color2].lstrip('#'))
    lum1 = get_luminance(rgb1[0], rgb1[1], rgb1[2])
    lum2 = get_luminance(rgb2[0], rgb2[1], rgb2[2])
    brightest = max(lum1, lum2)
    darkest = min(lum1, lum2)
    contrast = (brightest + 0.05) / (darkest + 0.05)
    if contrast < min_contrast:
        return False
    else:
        return True
    
def update_contrast_check(color1: str, color2: str, q:Q, min_contrast=4.5):
    rgb1 = hex_to_rgb(q.client[color1].lstrip('#'))
    rgb2 = hex_to_rgb(q.client[color2].lstrip('#'))
    lum1 = get_luminance(rgb1[0], rgb1[1], rgb1[2])
    lum2 = get_luminance(rgb2[0], rgb2[1], rgb2[2])
    brightest = max(lum1, lum2)
    darkest = min(lum1, lum2)
    contrast = (brightest + 0.05) / (darkest + 0.05)
    if contrast < min_contrast:
        q.page['form'][f'{color1}_{color2}'].type = 'error'
        q.page['form'][f'{color1}_{color2}'].text = f'Improve contrast between **{color1}** and **{color2}**.'
    else:
        q.page['form'][f'{color1}_{color2}'].type = 'success'

Review comment (suggestion):
I suppose this function deprecates the original `get_contrast`. If so, `get_contrast` should be removed as it's not used anymore.

Code after:
from pygments.style import Style
from pygments.token import Name, String, Operator, Punctuation

import math

py_lexer = get_lexer_by_name('python')


def to_grayscale(color: float) -> float:
    color /= 255
    return color / 12.92 if color <= 0.03928 else math.pow((color + 0.055) / 1.055, 2.4)


def get_luminance(r: float, g: float, b: float) -> float:
    return to_grayscale(r) * 0.2126 + to_grayscale(g) * 0.7152 + to_grayscale(b) * 0.0722


# Source: https://www.delftstack.com/howto/python/python-hex-to-rgb/.
def hex_to_rgb(hex_color: str) -> Tuple[int, ...]:
    if len(hex_color) == 3:
        hex_color = f'{hex_color[0]}{hex_color[0]}{hex_color[1]}{hex_color[1]}{hex_color[2]}{hex_color[2]}'
    return tuple(int(hex_color[i:i + 2], 16) for i in (0, 2, 4))


# Source: https://stackoverflow.com/questions/9733288/how-to-programmatically-calculate-the-contrast-ratio-between-two-colors. # noqa
def update_contrast_check(color1: str, color2: str, q:Q, min_contrast=4.5):
    rgb1 = hex_to_rgb(q.client[color1].lstrip('#'))
    rgb2 = hex_to_rgb(q.client[color2].lstrip('#'))
    lum1 = get_luminance(rgb1[0], rgb1[1], rgb1[2])
    lum2 = get_luminance(rgb2[0], rgb2[1], rgb2[2])
    brightest = max(lum1, lum2)
    darkest = min(lum1, lum2)
    contrast = (brightest + 0.05) / (darkest + 0.05)
    if contrast < min_contrast:
        q.page['form'][f'{color1}_{color2}'].type = 'error'
        q.page['form'][f'{color1}_{color2}'].text = f'Improve contrast between **{color1}** and **{color2}**.'
    else:
        q.page['form'][f'{color1}_{color2}'].type = 'success'
        q.page['form'][f'{color1}_{color2}'].text = f'Contrast between **{color1}** and **{color2}** is great!'


def get_theme_code(q: Q):
    contents = f'''
ui.theme(
    name='<theme-name>',
    primary='{q.client.primary}',
    text='{q.client.text}',
    card='{q.client.card}',
    page='{q.client.page}',
)
'''