fceruti
Surface Boxicon - a component library that wraps the boxicons library (My first library :))
Hey everyone!
For a personal project I’m working, I need to use boxicons in surface templates. Since the package didn’t exist, I decided to take the matter into my own hands. The results are here:
https://github.com/fceruti/surface-boxicon
I feel like a leveled up or something.
PS: The library is very small, so I’d very happy if you could check it out and point out things you would have don’t better. Anything. Even style pointers are most welcomed.
Most Liked
msaraiva
Hi @fceruti. Nice work!
One thing to keep in mind is that defining modules is more expensive than defining multiple function clauses so since all components have the same props, I believe you would have a more consistent API, along with faster compilation, if you define a single component with name and maybe also a type prop to differentiate each icon. Something like:
def render(%{name: "video-plus", type="solid"} = assigns) do
~F[<svg ... width={@size} height={@size} class={@class} .../></svg>]
end
def render(%{name: "video-plus", type="regular"} = assigns) do
~F[<svg ... width={@size} height={@size} class={@class} .../></svg>]
end
def render(%{name: "bell", type="solid"} = assigns) do
~F[<svg ... width={@size} height={@size} class={@class} .../></svg>]
end
def render(%{name: "bell", type="regular"} = assigns) do
~F[<svg ... width={@size} height={@size} class={@class} .../></svg>]
end
...
Then you could use it like:
<BoxIcon name="bell" type="solid"/>
fceruti
OK, so I managed to both finished the book and the library 
I added a way to load less functions using configuration
config :surface_boxicon,
icons: [
regular: ["calendar", "chvron-down"],
solid: ["hand", "file-md"],
logos: ["docker"]
]
But it turned out to be completely unnecessary, the Module is compiling super fast with all the icons. The current Boxicon module looks like this:
defmodule Boxicon
...
def render(assigns) do
~F[<svg xmlns="http://www.w3.org/2000/svg" width={"#{@size}"} height={"#{@size}"} class={"#{@class}"} viewBox="0 0 24 24">{render_content(@type, @name)}</svg>]
end
for %Boxicon.Source{type: type, name: name, content: content} <- @icons do
defp render_content(unquote(Atom.to_string(type)), unquote(name)),
do: unquote(Phoenix.HTML.raw(content))
end
defp render_content(_, _), do: ""
end
I’m not sure why this is the case, but maybe the compiler is having an easier time dealing with string signatures instead of maps. If I create one render function per icon, pattern matching on the assigns map, I go back to lousy compile times.
fceruti
Since this thread was first published, I migrated my code from Surface to vanilla LiveView.
Here is a new package for everyone using heex files: Boxicons Heex
I think the API to use it, it’s pretty clever:
<Box.icons
type="regular"
name="calendar"
size="64"
class="icon green"
/>
Have a nice day!
PS: It’s updated to use boxicons 2.1.1
kip
You wouldn’t necessarily need to implement any macros, but meta programming would still be useful. Something like:
defmodule Boxicon do
@doc "Type of the icon"
prop type, :string, values!: ["solid", "regular", "logos"]
@doc "Name of the icon"
prop name, :string, required: true
@doc "Width & height of the icon"
prop size, :integer, default: 24
@doc "CSS classes for the wrapping svg element"
prop class, :string, default: "icon"
@icons "populate icons from static data at compile time"
for {type, name, path} <- @icons do
def render(%{name: unquote(name), type: unquote(type)} = assigns) do
~F[<svg xmlns="http://www.w3.org/2000/svg" width={"#{@size}"} height={"#{@size}"} class={"#{@class}"} viewBox="0 0 24 24"><path d=unquote(path)/></svg>]
end
end
end
Happy to help with how to structure the data to populate @icons at compile time if you need.
Malian
@edisonywh Yes and no 
What you propose is perfectly fine and it will work! You will lose some Surface features, like compilation checks, and properties documentations.
@fceruti you can follow what @miguels did with ExHeroicons by creating a Phoenix helper, boxicon("video-plus", type: "solid") for example, and Surface will “just” uses that helper. In that case, you will be able to use the icons both with Phoenix with and without Surface.







