{% extends "admin/_layout.html" %} {% from "_macros.html" import icon %} {% set section = "customization" %} {% block title %}Customization - {{ brand.name }}{% endblock %} {% block heading %}Customization{% endblock %} {% block admin_content %}

What this installation is called and what it looks like. Every box below ships with a default; leaving one alone means it is not stored, so a later release can still improve the wording. Clearing a box gives you the shipped version back rather than nothing.

{% if error %}
{{ icon("warning", "icon--sm") }} {{ error }}
{% endif %} {% if saved %}
{{ icon("check", "icon--sm") }} {{ saved }}
{% endif %} {# --- Identity ------------------------------------------------------------- #}

Identity

Shown in the sidebar, in every page title, in the launcher when this is installed as an app, and to the model — it is told which installation it is answering in. Empty means LLeMbas.

One line, used in the page description. The sign-in page has a line of its own under Wording below.

{% if current.logo_path %}

{% endif %}

Replaces the leaf mark everywhere it appears. PNG, JPEG, WEBP or GIF, under 2 MB, square. SVG is deliberately not accepted: these files are served to people who are not signed in, and an SVG can carry a script. The launcher icons are made from this automatically.

{% if current.favicon_path %}

{% endif %}

Optional. Without one, a logo you upload is used at 32px, and without that the shipped leaf.

{# --- Wording -------------------------------------------------------------- #}

Wording

The lines with a bit of character in them. They live in the empty states, the error pages and the sign-in screen — never in the functional interface, where a button says what it does. Replace them with your own, or leave them.

{% for entry in flavour %}

{{ entry.hint }}

{% endfor %}
{# --- Themes --------------------------------------------------------------- #} {# One block per theme that exists, plus a single blank one to add the next. It used to be three blocks, always rendered, whether or not anybody had made a theme -- so a fresh instance opened on fifty-seven empty colour boxes under three identical headings, and the fourth theme was unreachable without editing the template. The spare-block pattern is the no-JavaScript way to do "add another": fill the blank one, save, and the page comes back with your theme and a new blank. There is no button to press and nothing to clone, which is why this still works with scripting off. The colours live in a
so a block is a heading and three fields until you ask for them. Nineteen inputs is the right number to *offer* and the wrong number to *show*: everything left empty inherits from the base, so most themes set four or five. Saving replaces the whole list, which is what makes removing one a matter of clearing its id -- and why the blocks may have gaps in their numbering without anything caring. `save_themes` skips an index with no id and counts from the keys it was actually sent. #}

Themes

A theme is a set of colours, not a stylesheet — nothing in this interface hard-codes one, so a third palette composes with everything. Pick which built-in it starts from and change only what you want; everything left empty is inherited. The soft variants behind focus rings and selected rows are worked out from the accent, so you do not have to.

{# The spare block is offered until the cap, so the form cannot grow without end and the page cannot stop offering one while there is room. #} {% set slots = custom_themes | length + (1 if custom_themes | length < max_themes else 0) %} {% for index in range(slots) %} {% set existing = custom_themes[index] if index < custom_themes | length else none %}

{{ existing.label or existing.id if existing else "Add a theme" }}

{% if existing %} Lowercase letters, digits and hyphens. Clear it to remove this theme. {% else %} Lowercase letters, digits and hyphens. Give it one to make a theme. {% endif %}

{# Open on a theme that has set something, so an existing override is never hidden behind a disclosure somebody has to know to open. #} Colours {% if existing and existing.tokens %} {{ existing.tokens | length }} set {% else %} all inherited {% endif %}
{% for name, description in tokens %}

--{{ name }}

{% endfor %}
{% endfor %} {% if custom_themes | length >= max_themes %}

That is {{ max_themes }} themes, which is the limit. Clear one's id and save to make room for another.

{% endif %}
{# --- Stylesheet ----------------------------------------------------------- #}

Stylesheet

Served as /branding.css after everything else, so these rules win. It is a file rather than a block inside the page on purpose: a stylesheet has no markup around it to escape from. Reach for the themes above first — a colour set there follows both palettes, and a rule here follows neither.

Up to 40,000 characters. Nothing here is validated: a rule that does not parse is dropped by the browser, quietly, as it would be in any stylesheet.

{% endblock %}