Skip to content

Commit 9126889

Browse files
committed
implement a extendable color palette and improve config
1 parent 2ccac95 commit 9126889

File tree

7 files changed

+291
-48
lines changed

7 files changed

+291
-48
lines changed

lib/scenic/color.ex

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
#
55

66
defmodule Scenic.Color do
7+
alias Scenic.Themes
8+
79
@named_colors %{
810
alice_blue: {0xF0, 0xF8, 0xFF},
911
antique_white: {0xFA, 0xEB, 0xD7},
@@ -173,7 +175,7 @@ defmodule Scenic.Color do
173175
174176
Most of the time, you will use one of the pre-defined named colors from the
175177
Named Colors table. However, there are times when you want to work with
176-
other color formats ranging from simple grayscale to rgb to hsl.
178+
other color formats ranging from simple grayscale to rgb to hsl.
177179
178180
The following formats are all supported by the `Scenic.Color` module.
179181
The values of r, g, b, and a are integers between 0 and 255.
@@ -616,7 +618,7 @@ defmodule Scenic.Color do
616618
@doc """
617619
Return map of all named colors and their values
618620
"""
619-
def named(), do: @named_colors
621+
def named(), do: Themes.get_palette()
620622

621623
# --------------------------------------------------------
622624
# @doc """

lib/scenic/component/button.ex

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,12 @@ defmodule Scenic.Component.Button do
167167
nil -> Themes.preset({:scenic, :primary})
168168
{:scenic, :dark} -> Themes.preset({:scenic, :primary})
169169
{:scenic, :light} -> Themes.preset({:scenic, :primary})
170-
theme -> theme
170+
theme ->
171+
case Themes.normalize(theme) do
172+
nil -> Themes.preset({:scenic, :primary})
173+
theme -> theme
174+
end
171175
end
172-
|> Themes.normalize()
173176

174177
# font related info
175178
font = Keyword.get(styles, :font, @default_font)

lib/scenic/palette.ex

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
defmodule Scenic.Palette do
2+
@palette %{
3+
alice_blue: {0xF0, 0xF8, 0xFF},
4+
antique_white: {0xFA, 0xEB, 0xD7},
5+
aqua: {0x00, 0xFF, 0xFF},
6+
aquamarine: {0x7F, 0xFF, 0xD4},
7+
azure: {0xF0, 0xFF, 0xFF},
8+
beige: {0xF5, 0xF5, 0xDC},
9+
bisque: {0xFF, 0xE4, 0xC4},
10+
black: {0x00, 0x00, 0x00},
11+
blanched_almond: {0xFF, 0xEB, 0xCD},
12+
blue: {0x00, 0x00, 0xFF},
13+
blue_violet: {0x8A, 0x2B, 0xE2},
14+
brown: {0xA5, 0x2A, 0x2A},
15+
burly_wood: {0xDE, 0xB8, 0x87},
16+
cadet_blue: {0x5F, 0x9E, 0xA0},
17+
chartreuse: {0x7F, 0xFF, 0x00},
18+
chocolate: {0xD2, 0x69, 0x1E},
19+
coral: {0xFF, 0x7F, 0x50},
20+
cornflower_blue: {0x64, 0x95, 0xED},
21+
cornsilk: {0xFF, 0xF8, 0xDC},
22+
crimson: {0xDC, 0x14, 0x3C},
23+
cyan: {0x00, 0xFF, 0xFF},
24+
dark_blue: {0x00, 0x00, 0x8B},
25+
dark_cyan: {0x00, 0x8B, 0x8B},
26+
dark_golden_rod: {0xB8, 0x86, 0x0B},
27+
dark_gray: {0xA9, 0xA9, 0xA9},
28+
dark_grey: {0xA9, 0xA9, 0xA9},
29+
dark_green: {0x00, 0x64, 0x00},
30+
dark_khaki: {0xBD, 0xB7, 0x6B},
31+
dark_magenta: {0x8B, 0x00, 0x8B},
32+
dark_olive_green: {0x55, 0x6B, 0x2F},
33+
dark_orange: {0xFF, 0x8C, 0x00},
34+
dark_orchid: {0x99, 0x32, 0xCC},
35+
dark_red: {0x8B, 0x00, 0x00},
36+
dark_salmon: {0xE9, 0x96, 0x7A},
37+
dark_sea_green: {0x8F, 0xBC, 0x8F},
38+
dark_slate_blue: {0x48, 0x3D, 0x8B},
39+
dark_slate_gray: {0x2F, 0x4F, 0x4F},
40+
dark_slate_grey: {0x2F, 0x4F, 0x4F},
41+
dark_turquoise: {0x00, 0xCE, 0xD1},
42+
dark_violet: {0x94, 0x00, 0xD3},
43+
deep_pink: {0xFF, 0x14, 0x93},
44+
deep_sky_blue: {0x00, 0xBF, 0xFF},
45+
dim_gray: {0x69, 0x69, 0x69},
46+
dim_grey: {0x69, 0x69, 0x69},
47+
dodger_blue: {0x1E, 0x90, 0xFF},
48+
fire_brick: {0xB2, 0x22, 0x22},
49+
floral_white: {0xFF, 0xFA, 0xF0},
50+
forest_green: {0x22, 0x8B, 0x22},
51+
fuchsia: {0xFF, 0x00, 0xFF},
52+
gainsboro: {0xDC, 0xDC, 0xDC},
53+
ghost_white: {0xF8, 0xF8, 0xFF},
54+
gold: {0xFF, 0xD7, 0x00},
55+
golden_rod: {0xDA, 0xA5, 0x20},
56+
gray: {0x80, 0x80, 0x80},
57+
grey: {0x80, 0x80, 0x80},
58+
green: {0x00, 0x80, 0x00},
59+
green_yellow: {0xAD, 0xFF, 0x2F},
60+
honey_dew: {0xF0, 0xFF, 0xF0},
61+
hot_pink: {0xFF, 0x69, 0xB4},
62+
indian_red: {0xCD, 0x5C, 0x5C},
63+
indigo: {0x4B, 0x00, 0x82},
64+
ivory: {0xFF, 0xFF, 0xF0},
65+
khaki: {0xF0, 0xE6, 0x8C},
66+
lavender: {0xE6, 0xE6, 0xFA},
67+
lavender_blush: {0xFF, 0xF0, 0xF5},
68+
lawn_green: {0x7C, 0xFC, 0x00},
69+
lemon_chiffon: {0xFF, 0xFA, 0xCD},
70+
light_blue: {0xAD, 0xD8, 0xE6},
71+
light_coral: {0xF0, 0x80, 0x80},
72+
light_cyan: {0xE0, 0xFF, 0xFF},
73+
light_golden_rod: {0xFA, 0xFA, 0xD2},
74+
light_golden_rod_yellow: {0xFA, 0xFA, 0xD2},
75+
light_gray: {0xD3, 0xD3, 0xD3},
76+
light_grey: {0xD3, 0xD3, 0xD3},
77+
light_green: {0x90, 0xEE, 0x90},
78+
light_pink: {0xFF, 0xB6, 0xC1},
79+
light_salmon: {0xFF, 0xA0, 0x7A},
80+
light_sea_green: {0x20, 0xB2, 0xAA},
81+
light_sky_blue: {0x87, 0xCE, 0xFA},
82+
light_slate_gray: {0x77, 0x88, 0x99},
83+
light_slate_grey: {0x77, 0x88, 0x99},
84+
light_steel_blue: {0xB0, 0xC4, 0xDE},
85+
light_yellow: {0xFF, 0xFF, 0xE0},
86+
lime: {0x00, 0xFF, 0x00},
87+
lime_green: {0x32, 0xCD, 0x32},
88+
linen: {0xFA, 0xF0, 0xE6},
89+
magenta: {0xFF, 0x00, 0xFF},
90+
maroon: {0x80, 0x00, 0x00},
91+
medium_aqua_marine: {0x66, 0xCD, 0xAA},
92+
medium_blue: {0x00, 0x00, 0xCD},
93+
medium_orchid: {0xBA, 0x55, 0xD3},
94+
medium_purple: {0x93, 0x70, 0xDB},
95+
medium_sea_green: {0x3C, 0xB3, 0x71},
96+
medium_slate_blue: {0x7B, 0x68, 0xEE},
97+
medium_spring_green: {0x00, 0xFA, 0x9A},
98+
medium_turquoise: {0x48, 0xD1, 0xCC},
99+
medium_violet_red: {0xC7, 0x15, 0x85},
100+
midnight_blue: {0x19, 0x19, 0x70},
101+
mint_cream: {0xF5, 0xFF, 0xFA},
102+
misty_rose: {0xFF, 0xE4, 0xE1},
103+
moccasin: {0xFF, 0xE4, 0xB5},
104+
navajo_white: {0xFF, 0xDE, 0xAD},
105+
navy: {0x00, 0x00, 0x80},
106+
old_lace: {0xFD, 0xF5, 0xE6},
107+
olive: {0x80, 0x80, 0x00},
108+
olive_drab: {0x6B, 0x8E, 0x23},
109+
orange: {0xFF, 0xA5, 0x00},
110+
orange_red: {0xFF, 0x45, 0x00},
111+
orchid: {0xDA, 0x70, 0xD6},
112+
pale_golden_rod: {0xEE, 0xE8, 0xAA},
113+
pale_green: {0x98, 0xFB, 0x98},
114+
pale_turquoise: {0xAF, 0xEE, 0xEE},
115+
pale_violet_red: {0xDB, 0x70, 0x93},
116+
papaya_whip: {0xFF, 0xEF, 0xD5},
117+
peach_puff: {0xFF, 0xDA, 0xB9},
118+
peru: {0xCD, 0x85, 0x3F},
119+
pink: {0xFF, 0xC0, 0xCB},
120+
plum: {0xDD, 0xA0, 0xDD},
121+
powder_blue: {0xB0, 0xE0, 0xE6},
122+
purple: {0x80, 0x00, 0x80},
123+
rebecca_purple: {0x66, 0x33, 0x99},
124+
red: {0xFF, 0x00, 0x00},
125+
rosy_brown: {0xBC, 0x8F, 0x8F},
126+
royal_blue: {0x41, 0x69, 0xE1},
127+
saddle_brown: {0x8B, 0x45, 0x13},
128+
salmon: {0xFA, 0x80, 0x72},
129+
sandy_brown: {0xF4, 0xA4, 0x60},
130+
sea_green: {0x2E, 0x8B, 0x57},
131+
sea_shell: {0xFF, 0xF5, 0xEE},
132+
sienna: {0xA0, 0x52, 0x2D},
133+
silver: {0xC0, 0xC0, 0xC0},
134+
sky_blue: {0x87, 0xCE, 0xEB},
135+
slate_blue: {0x6A, 0x5A, 0xCD},
136+
slate_gray: {0x70, 0x80, 0x90},
137+
slate_grey: {0x70, 0x80, 0x90},
138+
snow: {0xFF, 0xFA, 0xFA},
139+
spring_green: {0x00, 0xFF, 0x7F},
140+
steel_blue: {0x46, 0x82, 0xB4},
141+
tan: {0xD2, 0xB4, 0x8C},
142+
teal: {0x00, 0x80, 0x80},
143+
thistle: {0xD8, 0xBF, 0xD8},
144+
tomato: {0xFF, 0x63, 0x47},
145+
turquoise: {0x40, 0xE0, 0xD0},
146+
violet: {0xEE, 0x82, 0xEE},
147+
wheat: {0xF5, 0xDE, 0xB3},
148+
white: {0xFF, 0xFF, 0xFF},
149+
white_smoke: {0xF5, 0xF5, 0xF5},
150+
yellow: {0xFF, 0xFF, 0x00},
151+
yellow_green: {0x9A, 0xCD, 0x32}
152+
}
153+
154+
def get(), do: @palette
155+
end

lib/scenic/themes.ex

Lines changed: 96 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
defmodule Scenic.Themes do
2+
alias Scenic.Palette
23
@moduledoc """
34
Manages theme libraries by registering your map of themes to a library key.
45
By registering themes in this way you can safely pull in themes from external libraries,
@@ -31,7 +32,7 @@ defmodule Scenic.Themes do
3132
schema [:surface] # add additional required keys to your theme
3233
3334
use Scenic.Themes,
34-
sources: [
35+
[
3536
{:scenic, Scenic.Themes"},
3637
{:my_app, load()}
3738
]
@@ -49,40 +50,73 @@ defmodule Scenic.Themes do
4950
5051
Now themes are passed around scenic in the form of `{:library_name, :theme_name}` as opposed to just :theme_name.
5152
"""
52-
@callback load() :: {map, list} | map
53+
@callback load() :: keyword
5354
@optional_callbacks load: 0
5455

55-
defmacro __using__(using_opts \\ []) do
56+
defmacro __using__(sources \\ []) do
5657
quote do
5758
alias Scenic.Primitive.Style.Paint.Color
5859
@behaviour Scenic.Themes
59-
@sources Keyword.get(unquote(using_opts), :sources, [])
60+
@opts_schema [
61+
name: [required: true, type: :atom],
62+
themes: [required: true, type: :any],
63+
schema: [required: false, type: :any],
64+
palette: [required: false, type: :any]
65+
]
6066
@default_schema [:text, :background, :border, :active, :thumb, :focus]
61-
62-
@library_themes Enum.reduce(@sources, %{}, fn
63-
{lib, module}, acc when is_atom(module) ->
64-
case module.load() do
65-
{themes, schema} ->
66-
Map.put_new(acc, lib, {themes, List.flatten([@default_schema | schema])})
67-
themes ->
68-
Map.put_new(acc, lib, {themes, @default_schema})
69-
end
70-
{lib, {themes, schema}}, acc ->
71-
Map.put_new(acc, lib, {themes, List.flatten([@default_schema | schema])})
72-
{lib, themes}, acc ->
73-
Map.put_new(acc, lib, {themes, @default_schema})
74-
_, acc -> acc
67+
@palette %{}
68+
69+
@library_themes Enum.reduce(unquote(sources), %{}, fn lib_opts, acc ->
70+
case NimbleOptions.validate(lib_opts, @opts_schema) do
71+
{:ok, lib_opts} ->
72+
name = lib_opts[:name]
73+
themes = lib_opts[:themes]
74+
schema = lib_opts[:schema] || []
75+
palette = lib_opts[:palette] || %{}
76+
@palette Map.merge(@palette, palette)
77+
case themes do
78+
themes when is_map(themes) ->
79+
# not a module so we can load in the settings directly
80+
Map.put_new(acc, name, {themes, List.flatten([@default_schema | schema])})
81+
themes ->
82+
# this is a module so we have to load the settings
83+
lib_opts = themes.load()
84+
themes = lib_opts[:themes]
85+
schema = lib_opts[:schema] || []
86+
palette = lib_opts[:palette] || %{}
87+
IO.inspect palette
88+
@palette Map.merge(@palette, palette)
89+
Map.put_new(acc, name, {themes, List.flatten([@default_schema | schema])})
90+
end
91+
{:error, error} ->
92+
raise Exception.message(error)
93+
end
7594
end)
7695

96+
# validate the passed options
7797
def validate(theme)
7898
def validate({lib, theme_name} = lib_theme) when is_atom(theme_name) do
79-
{_, schema} = Map.get(@library_themes, lib)
80-
case normalize(lib_theme) do
81-
theme ->
99+
case Map.get(@library_themes, lib) do
100+
{themes, schema} ->
82101
# validate against the schema
83-
case validate(theme, schema) do
84-
{:ok, _} -> {:ok, lib_theme}
85-
error -> error
102+
case Map.get(themes, theme_name) do
103+
nil ->
104+
{
105+
:error,
106+
"""
107+
#{IO.ANSI.red()}Invalid theme specification
108+
Received: #{inspect(theme_name)}
109+
#{IO.ANSI.yellow()}
110+
The theme could not be found in library #{inspect(lib)}.
111+
Ensure you got the name correct.
112+
#{IO.ANSI.default_color()}
113+
"""
114+
}
115+
theme ->
116+
case validate(theme, schema) do
117+
{:ok, _} -> {:ok, lib_theme}
118+
error -> error
119+
end
86120
end
87121
nil ->
88122
{
@@ -177,10 +211,23 @@ defmodule Scenic.Themes do
177211
}
178212
end
179213

214+
@doc false
215+
def get_schema(lib) do
216+
case Map.get(@library_themes, lib) do
217+
{_, schema} -> schema
218+
nil -> nil
219+
end
220+
end
221+
222+
@doc false
223+
def get_palette() do
224+
@palette
225+
end
226+
180227
@doc false
181228
def normalize({lib, theme_name}) when is_atom(theme_name) do
182229
case Map.get(@library_themes, lib) do
183-
{themes, schema} -> Map.get(themes, theme_name)
230+
{themes, _schema} -> Map.get(themes, theme_name)
184231
nil -> nil
185232
end
186233
end
@@ -236,10 +283,8 @@ defmodule Scenic.Themes do
236283
Example Themes module that includes an optional alias:
237284
238285
defmodule MyApplication.Themes do
239-
use Scenic.Assets.Static,
240-
otp_app: :my_application,
241-
alias: [
242-
scenic: Scenic.Themes,
286+
use Scenic.Themes, [
287+
[name: scenic: themes: Scenic.Themes],
243288
]
244289
end
245290
@@ -251,15 +296,34 @@ defmodule Scenic.Themes do
251296
end
252297
end
253298

254-
@doc false
299+
@spec validate({atom, atom} | {atom, map} | map) :: {:ok, term} | {:error, term}
300+
@doc """
301+
Validate a theme
302+
"""
255303
def validate(theme), do: module().validate(theme)
256304

305+
@spec get_schema(atom) :: list
306+
@doc """
307+
Retrieve a library's schema
308+
"""
309+
def get_schema(lib), do: module().get_schema(lib)
310+
311+
@spec normalize({atom, atom} | map) :: map | nil
257312
@doc false
258313
def normalize(theme), do: module().normalize(theme)
259314

260-
@doc false
315+
@spec preset({atom, atom} | map) :: map | nil
316+
@doc """
317+
Get a theme.
318+
"""
261319
def preset(theme), do: module().preset(theme)
262320

321+
@spec get_palette() :: map
322+
@doc """
323+
Get the palette of colors.
324+
"""
325+
def get_palette(), do: module().get_palette()
326+
263327
@theme_light %{
264328
text: :black,
265329
background: :white,
@@ -300,5 +364,5 @@ defmodule Scenic.Themes do
300364
}
301365

302366
@doc false
303-
def load(), do: @themes
367+
def load(), do: [name: :scenic, themes: @themes, palette: Palette.get()]
304368
end

0 commit comments

Comments
 (0)