Metadata-Version: 2.4
Name: splent_feature_theme
Version: 0.15.0
License-Expression: LGPL-3.0-or-later
Requires-Python: >=3.13
Description-Content-Type: text/markdown
License-File: COPYING
License-File: COPYING.LESSER
Requires-Dist: splent_framework>=1.20.0
Dynamic: license-file

# splent_feature_theme

The public shell of a [SPLENT](https://splent.io) product (`public_base.html`),
the design tokens it is drawn with, a library of composable blocks, and the
Appearance and Menus editors of the admin panel.

The theme never hardcodes a product name, palette or font. The product gives
its identity through configuration, and its palette through `THEME_TOKENS` or
a skin feature; the admin panel can change both at runtime. What this feature
provides and requires is listed in the `[tool.splent.contract]` section of
`pyproject.toml`, which `splent feature:contract --write` keeps in sync with
the source.

## Menu entries

The editors register two entries in the Administration section of the
application shell's menu registry. Neither names roles: each takes the ones
its screen asks for (`routes.PANEL_ROLES`, administrators), so nobody is
offered a door that answers 403.

| Key | Label | Order | Icon | Opens |
|---|---|---|---|---|
| `theme_appearance` | Appearance | 40 | `sliders` | `theme.admin_appearance` |
| `theme_menus` | Menus | 50 | `menu` | `theme.admin_menus` |

A product hides or reorders them by key in `[tool.splent.layout.menu]`.

```toml
# the product's pyproject.toml
[tool.splent.layout.menu]
hide = ["theme_menus"]
```

The `layout.authenticated_sidebar` hooks that drew the same two entries stay
for one minor, for the shells that still render slots. A shell draws the
registry or the slots, never both.

## Configuration

Declared in `[tool.splent.config]`. A product overrides them in its own
`[tool.splent.config]`. The Appearance editor wins over all of them where it
has a field for the value.

| Key | Default | What it does |
|---|---|---|
| `SITE_NAME` | the package name | What the site calls itself in the header, the browser tab and the footer. |
| `SITE_TAGLINE` | empty | The line under the name. |
| `SITE_LOGO` | empty | The header logo, a path inside the product's static folder. Empty draws no logo. |
| `SITE_BRAND_MODE` | `both` | How the header brand renders: `logo`, `text` or `both`. |
| `SITE_LOGO_SIZE` | `40` | The logo height in pixels. |
| `SITE_BREADCRUMBS` | `deep` | Where the automatic breadcrumb trail appears: `deep`, `all` or `off`. |
| `THEME_TOKENS` | the theme's defaults | The palette and fonts, a JSON object of token name to CSS value. |

`THEME_TOKENS` takes the names of `DEFAULT_TOKENS` in `tokens.py` and goes
over them, so a product writes only what it changes. An empty `font_url`
loads no web font, and the fonts named in `font_body`, `font_heading` and
`font_display` then come from the reader's system.

```toml
# the product's pyproject.toml
[tool.splent.config]
SITE_NAME = "uvlhub"
SITE_LOGO = "media/logos/default.svg"
SITE_BRAND_MODE = "logo"
THEME_TOKENS = '{"primary": "#287FB9", "font_url": "", "font_body": "system-ui, sans-serif"}'
```

A `THEME_TOKENS` that is not valid JSON, is not an object, names a token the
theme does not have or gives one a value that is not a string stops the boot
with a message that says which. A skin that sets `THEME_TOKENS` in its
`init_feature` replaces the product's whole.

## Use it in a product

```bash
splent feature:add splent_feature_theme
```

## Develop

```bash
splent feature:test splent_feature_theme
splent feature:contract splent_feature_theme
```
