defmodule Liliform.Colorhash do @moduledoc """ Given a string returns HSL color. """ alias Freedive.Features @seed "zeni" @default_color {0, 0, 0} @doc """ Given a string returns HSL color as a CSS string. """ def hsl(input) do {hue, saturation, lightness} = hsl(input, raw: true) "hsl(#{hue}, #{saturation}%, #{lightness}%)" end @doc """ Given a string returns HSL color. """ def hsl(input, raw: true) do if Features.enabled?(:colorhash) do input = String.downcase(input) <> @seed hash = :erlang.phash2(input, 2_147_483_647) hue = calculate_hue(hash) saturation = 80 + rem(hash, 21) lightness = 30 + rem(hash, 31) {hue, saturation, lightness} else @default_color end end @doc """ Calculates hue avoiding low contrast colors. """ def calculate_hue(hash) do base_hue = rem(hash, 360) # Ranges to exclude (yellow to light green, cyan) excluded_ranges = [ # yellow {40, 80}, # cyan {175, 185} ] # Adjust the hue to skip over excluded ranges Enum.reduce(excluded_ranges, base_hue, fn {start, stop}, acc_hue -> if acc_hue >= start and acc_hue <= stop, do: stop + (acc_hue - start + 1), else: acc_hue end) end end