diff --git a/config/config.exs b/config/config.exs index de5dca8..c8d6154 100644 --- a/config/config.exs +++ b/config/config.exs @@ -13,7 +13,8 @@ config :freedive, config :freedive, features: [ - register_account: true + register_account: true, + colorhash: true ] # Configures the endpoint diff --git a/config/runtime.exs b/config/runtime.exs index 2c82427..9b46e51 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -18,6 +18,12 @@ if config_env() == :prod do config :freedive, :features, register_account: false end + # Colorhash feature is enabled by default. + # To disable, set the COLORHASH_ENABLE environment variable to "false". + if System.get_env("COLORHASH_ENABLE") == "false" do + config :freedive, :features, colorhash: false + end + database_path = System.get_env("DATABASE_PATH") || raise """ diff --git a/freedive.env.sample b/freedive.env.sample index cff49b5..bf2e487 100644 --- a/freedive.env.sample +++ b/freedive.env.sample @@ -11,6 +11,7 @@ TLS_CERT_PATH="<%= @data_dir %>/tls.crt" # Features REGISTER_ACCOUNT_ENABLE="false" +COLORHASH_ENABLE="true" # Phoenix PHX_SERVER=true diff --git a/lib/freedive/colorhash.ex b/lib/freedive/colorhash.ex new file mode 100644 index 0000000..da43237 --- /dev/null +++ b/lib/freedive/colorhash.ex @@ -0,0 +1,48 @@ +defmodule Freedive.Colorhash do + @moduledoc """ + Given a string returns consistent HSL color. + """ + alias Freedive.Features + + @default_hsl {0, 0, 0} + + def hsl(input, css: true) do + {hue, saturation, lightness} = hsl(input) + "hsl(#{hue}, #{saturation}%, #{lightness}%)" + end + + def hsl(input) do + if Features.enabled?(:colorhash) do + input = String.downcase(input) + 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_hsl + 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 + {50, 70}, + # 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 diff --git a/lib/freedive_web/live/home_live.ex b/lib/freedive_web/live/home_live.ex index 612ddc6..feef2b7 100644 --- a/lib/freedive_web/live/home_live.ex +++ b/lib/freedive_web/live/home_live.ex @@ -1,5 +1,6 @@ defmodule FreediveWeb.HomeLive do use FreediveWeb, :live_view + import Freedive.Colorhash def render(assigns) do ~H""" @@ -14,11 +15,19 @@ defmodule FreediveWeb.HomeLive do System <.panel_tabs is-hidden-tablet> - - - - - + + + + + + + + + + + + + <.panel_block> @@ -37,25 +46,37 @@ defmodule FreediveWeb.HomeLive do <.link patch={~p"/users/settings"} class="panel-block pt-1"> Account settings <.link patch={~p"/services"} class="panel-block pt-1">