defmodule ForageWeb.Assets do
@moduledoc """
Utilities to deal with static assets required by Forage's
more advanced widgets, namely the select widgets.
Forage uses Bootstrap v4 instead of the newer Bootstrap v5.
"""
@external_resource "lib/forage_web/assets/activate-forage-select.js"
# Extract the list of supported themes from the ones in the `priv/` directory
bootswatch_themes =
File.ls!("priv/static/themes")
|> List.delete("default")
|> Enum.sort()
# Ensure the "default" theme comes first
bootstrap_themes = ["default" | bootswatch_themes]
for theme <- bootstrap_themes do
path = "priv/static/themes/#{theme}/bootstrap.min.css"
@external_resource path
end
for file <- File.ls!("priv/static/select/") do
path = "priv/select/#{file}"
@external_resource path
end
# Add the supported themes to a module attribute
@bootstrap_themes bootstrap_themes
url_for_theme = fn
# Not strictly a Bootswatch theme, but including it here is useful
"default" -> "https://getbootstrap.com/docs/4.6/getting-started/introduction/"
# Link to Boostwatch v4
theme -> "https://bootswatch.com/4/#{theme}/"
end
# Build a markdown excerpt containing a list of suppoered theme
# and their respective themes
theme_list_markdown =
bootstrap_themes
|> Enum.map(fn theme -> " - [#{theme}](#{url_for_theme.(theme)})" end)
|> Enum.join("\n")
@activate_select (
"<script>" <>
File.read!("lib/forage_web/assets/activate-forage-select.js") <>
"</script>"
)
@forage_select_assets_from_cdn """
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/css/select2.min.css"/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ttskch/select2-bootstrap4-theme/dist/select2-bootstrap4.min.css"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/js/select2.min.js"></script>
"""
@forage_select_assets_from_app """
<link rel="stylesheet" href="/_forage/select/select2.min.css"/>
<link rel="stylesheet" href="/_forage/select/select2-bootstrap4.min.css"/>
<script src="/_forage/select/jquery.min.js"></script>
<script src="/_forage/select/select2.min.js"></script>
"""
@doc """
Adds a `<script>` tag to the webpage with the javascript required to run
the forage select widgets.
Even after adding this code, you need to activate the select widget using
`ForageWeb.Assets.activate_forage_select()`
The Javascript is served from an external CDN.
"""
def forage_select_assets_from_cdn() do
{:safe, @forage_select_assets_from_cdn}
end
@doc """
Adds a `<script>` tag to the webpage with the javascript required to run
the forage select widgets.
Even after adding this code, you need to activate the select widget using
`ForageWeb.Assets.activate_forage_select()`
The Javascript is served from the phoenix application.
"""
def forage_select_assets_from_app() do
{:safe, @forage_select_assets_from_app}
end
@doc """
Add to the end of the webpage in order to activate the forage select widget.
Adds a `<script>` tag to the webpage.
"""
def activate_forage_select() do
{:safe, @activate_select}
end
@doc """
Renders the HTML `<link>` tag necessary to use a given Bootswatch theme,
which are compatible with the default bootstrap classes.
The theme is served from an external CDN.
This function includes the *default* theme, which is the default
bootstrap theme and not strictly part of bootswatch.
The following themes are supported:
#{theme_list_markdown}
This is meant to be used inside the `<head>` tag of your application.
Note: no specific endorsement of Bootswatch themes is intended.
They are included here simply because they are compatible with
the default theme and may be a simple way of adding variety
to your website.
The themes are served from the
[https://cdn.jsdelivr.net/](https://cdn.jsdelivr.net/) CDN.
## Examples
```heex
<%= ForageWeb.Assets.theme_from_cdn("superhero") %>
```
"""
def theme_from_cdn("default") do
{:safe,
~S[<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css">]}
end
def theme_from_cdn(theme) when theme in @bootstrap_themes do
{:safe,
[
~S[<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootswatch@4.6.2/dist/],
theme,
~S[/bootstrap.min.css">]
]}
end
@doc """
Renders the HTML `<link>` tag necessary to use a given Bootswatch theme,
which are compatible with the default bootstrap classes.
The theme is served from an external CDN.
This function includes the *default* theme, which is the default
bootstrap theme and not strictly part of bootswatch.
The following themes are supported:
#{theme_list_markdown}
This is meant to be used inside the `<head>` tag of your application.
Note: no specific endorsement of Bootswatch themes is intended.
They are included here simply because they are compatible with
the default theme and may be a simple way of adding variety
to your website.
## Examples
```heex
<%= ForageWeb.Assets.theme_from_app("superhero") %>
```
"""
def theme_from_app(theme) when theme in @bootstrap_themes do
{:safe,
[
~S[<link rel="stylesheet" href="/_forage/themes/],
theme,
~S[/bootstrap.min.css">]
]}
end
@doc """
Enable serving forage assets from the phoenix application
(instead of serving from a CDN).
It's meant to be used in the Phoenix application's endpoint
(just like the `Plug.Static`).
## Example
defmodule MyAppWeb.Endpoint do
use Phoenix.Endpoint, otp_app: :my_app
# ...
plug Plug.Static, ...
use ForageWeb.Assets
# ...
end
"""
defmacro __using__(_opts) do
quote do
plug Plug.Static,
at: "_forage/",
from: {:forage, "priv/static"},
gzip: false,
headers: [{"access-control-allow-origin", "*"}]
end
end
@doc """
Lists all supported bootstrap themes.
Currently, supported bootstrap themes are:
#{theme_list_markdown}
"""
def supported_bootstrap_themes() do
@bootstrap_themes
end
end