forked from hiway/freedive
Add colorhash
This commit is contained in:
parent
c935fbbc42
commit
beea7b0caf
6 changed files with 110 additions and 10 deletions
|
@ -13,7 +13,8 @@ config :freedive,
|
||||||
|
|
||||||
config :freedive,
|
config :freedive,
|
||||||
features: [
|
features: [
|
||||||
register_account: true
|
register_account: true,
|
||||||
|
colorhash: true
|
||||||
]
|
]
|
||||||
|
|
||||||
# Configures the endpoint
|
# Configures the endpoint
|
||||||
|
|
|
@ -18,6 +18,12 @@ if config_env() == :prod do
|
||||||
config :freedive, :features, register_account: false
|
config :freedive, :features, register_account: false
|
||||||
end
|
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 =
|
database_path =
|
||||||
System.get_env("DATABASE_PATH") ||
|
System.get_env("DATABASE_PATH") ||
|
||||||
raise """
|
raise """
|
||||||
|
|
|
@ -11,6 +11,7 @@ TLS_CERT_PATH="<%= @data_dir %>/tls.crt"
|
||||||
|
|
||||||
# Features
|
# Features
|
||||||
REGISTER_ACCOUNT_ENABLE="false"
|
REGISTER_ACCOUNT_ENABLE="false"
|
||||||
|
COLORHASH_ENABLE="true"
|
||||||
|
|
||||||
# Phoenix
|
# Phoenix
|
||||||
PHX_SERVER=true
|
PHX_SERVER=true
|
||||||
|
|
48
lib/freedive/colorhash.ex
Normal file
48
lib/freedive/colorhash.ex
Normal file
|
@ -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
|
|
@ -1,5 +1,6 @@
|
||||||
defmodule FreediveWeb.HomeLive do
|
defmodule FreediveWeb.HomeLive do
|
||||||
use FreediveWeb, :live_view
|
use FreediveWeb, :live_view
|
||||||
|
import Freedive.Colorhash
|
||||||
|
|
||||||
def render(assigns) do
|
def render(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
|
@ -14,11 +15,19 @@ defmodule FreediveWeb.HomeLive do
|
||||||
<a>System</a>
|
<a>System</a>
|
||||||
</.panel_tabs>
|
</.panel_tabs>
|
||||||
<.panel_tabs is-hidden-tablet>
|
<.panel_tabs is-hidden-tablet>
|
||||||
<a class="is-active"><Lucideicons.infinity aria-hidden="true" /></a>
|
<a class="is-active">
|
||||||
<a><Lucideicons.binary aria-hidden="true" /></a>
|
<Lucideicons.infinity style={"color: #{hsl("all", css: true)}"} aria-hidden="true" />
|
||||||
<a><Lucideicons.hard_drive aria-hidden="true" /></a>
|
</a>
|
||||||
<a><Lucideicons.earth aria-hidden="true" /></a>
|
<a>
|
||||||
<a><Lucideicons.bot aria-hidden="true" /></a>
|
<Lucideicons.binary style={"color: #{hsl("compute", css: true)}"} aria-hidden="true" />
|
||||||
|
</a>
|
||||||
|
<a>
|
||||||
|
<Lucideicons.hard_drive style={"color: #{hsl("storage", css: true)}"} aria-hidden="true" />
|
||||||
|
</a>
|
||||||
|
<a>
|
||||||
|
<Lucideicons.earth style={"color: #{hsl("network", css: true)}"} aria-hidden="true" />
|
||||||
|
</a>
|
||||||
|
<a><Lucideicons.bot style={"color: #{hsl("system", css: true)}"} aria-hidden="true" /></a>
|
||||||
</.panel_tabs>
|
</.panel_tabs>
|
||||||
|
|
||||||
<.panel_block>
|
<.panel_block>
|
||||||
|
@ -37,25 +46,37 @@ defmodule FreediveWeb.HomeLive do
|
||||||
</.panel_block>
|
</.panel_block>
|
||||||
<.link patch={~p"/users/settings"} class="panel-block pt-1">
|
<.link patch={~p"/users/settings"} class="panel-block pt-1">
|
||||||
<span class="panel-icon">
|
<span class="panel-icon">
|
||||||
<Lucideicons.user_cog aria-hidden="true" />
|
<Lucideicons.user_cog
|
||||||
|
style={"color: #{hsl("account settings", css: true)}"}
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span class="mt-2 ml-2">Account settings</span>
|
<span class="mt-2 ml-2">Account settings</span>
|
||||||
</.link>
|
</.link>
|
||||||
<.link patch={~p"/services"} class="panel-block pt-1">
|
<.link patch={~p"/services"} class="panel-block pt-1">
|
||||||
<span class="panel-icon">
|
<span class="panel-icon">
|
||||||
<Lucideicons.puzzle aria-hidden="true" />
|
<Lucideicons.puzzle
|
||||||
|
style={"color: #{hsl("system services", css: true)}"}
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
<div class="mt-2 ml-2">System services</div>
|
<div class="mt-2 ml-2">System services</div>
|
||||||
</.link>
|
</.link>
|
||||||
<.link patch={~p"/packages"} class="panel-block pt-1">
|
<.link patch={~p"/packages"} class="panel-block pt-1">
|
||||||
<span class="panel-icon">
|
<span class="panel-icon">
|
||||||
<Lucideicons.package aria-hidden="true" />
|
<Lucideicons.package
|
||||||
|
style={"color: #{hsl("system packages", css: true)}"}
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span class="mt-2 ml-2">System packages</span>
|
<span class="mt-2 ml-2">System packages</span>
|
||||||
</.link>
|
</.link>
|
||||||
<.link patch={~p"/updates"} class="panel-block pt-1">
|
<.link patch={~p"/updates"} class="panel-block pt-1">
|
||||||
<span class="panel-icon">
|
<span class="panel-icon">
|
||||||
<Lucideicons.hard_drive_download aria-hidden="true" />
|
<Lucideicons.hard_drive_download
|
||||||
|
style={"color: #{hsl("system software updates", css: true)}"}
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span class="mt-2 ml-2">System software updates</span>
|
<span class="mt-2 ml-2">System software updates</span>
|
||||||
</.link>
|
</.link>
|
||||||
|
|
23
test/freedive/colorhash_test.exs
Normal file
23
test/freedive/colorhash_test.exs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
defmodule Freedive.ColorhashTest do
|
||||||
|
use ExUnit.Case
|
||||||
|
|
||||||
|
test "hsl" do
|
||||||
|
assert Freedive.Colorhash.hsl("foo") == {312, 80, 48}
|
||||||
|
assert Freedive.Colorhash.hsl("bar") == {38, 88, 38}
|
||||||
|
assert Freedive.Colorhash.hsl("baz") == {288, 95, 42}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "hsl with css" do
|
||||||
|
assert Freedive.Colorhash.hsl("foo", css: true) == "hsl(312, 80%, 48%)"
|
||||||
|
assert Freedive.Colorhash.hsl("bar", css: true) == "hsl(38, 88%, 38%)"
|
||||||
|
assert Freedive.Colorhash.hsl("baz", css: true) == "hsl(288, 95%, 42%)"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "hsl with disabled feature" do
|
||||||
|
Freedive.Features.disable(:colorhash)
|
||||||
|
assert Freedive.Colorhash.hsl("foo") == {0, 0, 0}
|
||||||
|
assert Freedive.Colorhash.hsl("bar") == {0, 0, 0}
|
||||||
|
assert Freedive.Colorhash.hsl("baz") == {0, 0, 0}
|
||||||
|
Freedive.Features.enable(:colorhash)
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue