# `PhoenixKit.Email.Branding`
[🔗](https://github.com/BeamLabEU/phoenix_kit/blob/v2.55.1/lib/phoenix_kit/email/branding.ex#L1)

The site's branding as email variables: its logo and its accent colour.

`PhoenixKit.Email.Content.resolve/5` binds both in every part of a message
built from a file or a default — the body, `_layout`, `_header` and
`_footer` — so a host's files and core's own layout read the same values.

| placeholder | value |
|---|---|
| `{{logo_url}}` | an absolute URL of the project logo, or `""` |
| `{{accent_color}}` | the `email_accent_color` setting as `#rrggbb`, or `#18181b` |

Both are read on every send, so a changed setting shows in the next email
without a restart.

A caller may bind either variable itself; `merge/2` keeps its value only
when it is valid — a `#rrggbb` colour, an empty or `http(s)://` logo URL —
and uses the site's otherwise, on every path a template can read it.

## The logo

The logo is the one already set under Settings (`Settings.get_logo_uuid/0`:
the project logo, else the site icon). Its URL carries the permanent
signed token, so it keeps working in an email opened weeks later. A logo
stored in a **private** library would need a time-window token that
expires long before the email is read, so none is minted: `logo_url` is
empty and core's header prints the site's name instead.

A logo in the trash, or one that no longer exists, gives no URL either.

### Which file of the logo

The first finished one, in this order, that every email client shows —
PNG, JPEG or GIF:

    small  →  medium  →  large  →  original

A transparent logo's JPEG-configured sizes are written as PNG
(`VariantGenerator.output_format/3`), or as WebP when the host sets
`config :phoenix_kit, :variant_alpha_format, "webp"`. Outlook for Windows
shows no WebP, so a WebP size is passed over — usually for the original,
when that is a PNG. A logo with no such file (an SVG with WebP sizes, or
sizes still being made) gives no URL, and core's header prints the site's
name. Sizes made before transparent images were written as PNG are JPEG,
so such a logo arrives on a white background until its sizes are
regenerated. The URL carries the file's version, so a mail client may
cache it for good.

## The accent colour

A six-digit hex colour (`#1d4ed8`), checked on every read: anything else —
unset, `red`, `#abc`, a value with a `;` in it — reads as the neutral
default, so a bad value can never reach a `style` attribute.

# `accent_color`

```elixir
@spec accent_color() :: String.t()
```

The accent colour setting, normalised by `normalize_color/1`.

# `accent_color_key`

```elixir
@spec accent_color_key() :: String.t()
```

The settings key that holds the accent colour.

# `configured_accent_color`

```elixir
@spec configured_accent_color() :: String.t() | nil
```

The accent colour setting as `#rrggbb`, or `nil` when it is unset or not a
valid colour — the "has the site chosen a colour?" question core's layout
asks before drawing its accent bar.

# `default_accent_color`

```elixir
@spec default_accent_color() :: String.t()
```

The accent colour used when none (or no valid one) is set.

# `logo_url`

```elixir
@spec logo_url() :: String.t()
```

An absolute URL of the project logo for an email, or `""` when there is no
logo, it is in the trash or no longer exists, it sits in a private library,
it has no file every mail client shows (see "Which file of the logo"), or
the lookup fails.

# `merge`

```elixir
@spec merge(%{required(String.t()) =&gt; term()}, %{required(String.t()) =&gt; String.t()}) ::
  %{
    required(String.t()) =&gt; term()
  }
```

`variables` (string keys) with the branding variables added: a caller's own
`logo_url` or `accent_color` is kept only when valid (see `valid_color?/1`
and `valid_logo_url?/1`), otherwise `branding`'s value is used. A kept
colour is normalised.

# `normalize_color`

```elixir
@spec normalize_color(term()) :: String.t()
```

`value` as a lower-case `#rrggbb` colour, or the default accent colour when
it is not a six-digit hex colour.

    iex> PhoenixKit.Email.Branding.normalize_color(" #1D4ED8 ")
    "#1d4ed8"

    iex> PhoenixKit.Email.Branding.normalize_color("red;background:url(x)")
    "#18181b"

# `text_color_on`

```elixir
@spec text_color_on(String.t()) :: String.t()
```

The text colour that reads on `background` (a colour as `normalize_color/1`
returns it): white on a dark colour, near-black on a light one — whichever
contrasts more, by WCAG relative luminance.

# `valid_color?`

```elixir
@spec valid_color?(term()) :: boolean()
```

Whether `value` is a six-digit hex colour (surrounding whitespace allowed).

    iex> PhoenixKit.Email.Branding.valid_color?("#1d4ed8")
    true

    iex> PhoenixKit.Email.Branding.valid_color?("#1d4ed8;x:y")
    false

# `valid_logo_url?`

```elixir
@spec valid_logo_url?(term()) :: boolean()
```

Whether `value` can stand as a logo URL: empty (no logo), or an absolute
`http(s)://` address.

# `variables`

```elixir
@spec variables() :: %{required(String.t()) =&gt; String.t()}
```

Both branding variables, keyed as the templates read them.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
