213 lines
12 KiB
Markdown
213 lines
12 KiB
Markdown
# Lumi UI and theme system
|
|
|
|
Lumi UI is the project-native design layer used by every page rendered through the
|
|
shared EJS layout. It keeps route behavior and page-specific JavaScript separate
|
|
from visual tokens and reusable components.
|
|
|
|
## Files
|
|
|
|
- `src/web/public/lumi-tokens.css`: semantic colors, spacing, radii, shadows,
|
|
typography, compatibility aliases, and reduced-motion behavior.
|
|
- `src/web/public/lumi-layout.css`: application shell, sidebar, content
|
|
containers, responsive grids, stacks, clusters, and mobile navigation.
|
|
- `src/web/public/lumi-components.css`: buttons, forms, cards, tables, lists,
|
|
badges, alerts, tabs, modals, empty/loading/error states, stateful action
|
|
buttons, and tooltips.
|
|
- `src/web/public/lumi-state-button.js` and
|
|
`src/web/views/partials/state-button.ejs`: reusable multi-state button
|
|
behavior for submit/loading/success actions.
|
|
- `src/web/public/lumi-interactions.js`: progressive interaction layer for
|
|
server-sent events, no-auto-refresh notices, dirty settings save bars,
|
|
expandable settings containers, refresh prompts, and soft navigation.
|
|
- `src/services/web-events.js`: small role-aware Server-Sent Events bus exposed
|
|
at `GET /api/events` for authenticated users.
|
|
- `src/web/public/styles.css`: legacy and feature-specific styles that still use
|
|
the shared tokens. New general-purpose styling belongs in the Lumi UI files.
|
|
- `src/web/views/partials/page-header.ejs`: standard page title and description.
|
|
- `src/web/views/partials/theme-vars.ejs`: safe active-theme variables for shell
|
|
and standalone pages.
|
|
- `src/services/themes.js`: built-in themes, custom theme CRUD, validation,
|
|
migration, fallback handling, and active-theme selection.
|
|
|
|
Use `lumi-stack`, `lumi-cluster`, `lumi-split`, `lumi-grid`, `page-header`,
|
|
`button-group`, `card`, `panel`, `table-wrap`, `empty-state`, `loading-state`,
|
|
and `status-indicator` before adding one-off layout rules. Preserve existing IDs,
|
|
field names, data attributes, and JavaScript hooks when restyling a page.
|
|
|
|
## Interaction Rules
|
|
|
|
Pages should not self-refresh for state or progress changes. Core connection
|
|
recovery now displays a notice instead of calling `window.location.reload()`.
|
|
Server-originated events use `GET /api/events` with explicit event names such as
|
|
`server:status`, `server:warning`, `ai:model_status`, and
|
|
`data:new_available`. Admin-only events must be published with `{ role: "admin" }`.
|
|
|
|
List/data updates should announce that new data exists and show a refresh prompt.
|
|
The shared refresh prompt uses a 3-second cooldown before another refresh can be
|
|
requested. It does not replace list contents automatically.
|
|
|
|
Forms that represent page settings should add `data-lumi-settings-form`.
|
|
Action-only forms must not use that attribute. The shared dirty-state layer
|
|
tracks original values, marks changed fields with theme-aware unsaved styling,
|
|
shows a top Save changes bar, warns before accidental navigation, and clears
|
|
markers only after successful saves.
|
|
|
|
Buttons should use `partials/state-button.ejs` for submit, loading, success, or
|
|
error states. Single-state and multi-state buttons share the same Lumi button
|
|
tokens. Hidden states stay measurable with `data-state-hidden`, so the button
|
|
width is based on the widest state and state changes do not shift surrounding
|
|
layout. Use `.input-action-row` for desktop file/input + action pairs such as
|
|
ZIP updates and navigation icon uploads; the row stacks on mobile.
|
|
|
|
Destructive POST forms should provide context through `data-confirm-title`,
|
|
`data-confirm-text`, and `data-confirm-label`. Dynamic JavaScript-only
|
|
destructive actions can call `window.LumiConfirm.destructive({ title, text,
|
|
label })` to reuse the same modal. The helper keeps vague default confirmation
|
|
copy out of normal admin flows and returns focus after cancel/confirm.
|
|
|
|
Expandable settings rows use `data-lumi-expandable-settings` on a `<details>`
|
|
container. Preview text can be wired with `data-placeholder-preview="#field-id"`;
|
|
known placeholders such as `{gifter_username}`, `{item_name}`,
|
|
`{creator_username}`, and `{amount_display}` render with plausible sample values
|
|
without changing the saved template.
|
|
|
|
Soft navigation progressively enhances same-origin links by replacing
|
|
`main.content`, updating history, and fading content in place. If a fetch fails,
|
|
JavaScript is unavailable, or unsaved settings are present, navigation falls back
|
|
to normal browser behavior.
|
|
|
|
Sidebar navigation sections behave as an accordion. Opening one `.nav-section`
|
|
closes the other expanded sections while preserving the active page highlight
|
|
and `aria-expanded` state.
|
|
|
|
## Themes
|
|
|
|
Lumi ships with six read-only themes: Lumi Default, Lumi Dark, Lumi Light, High
|
|
Contrast, Midnight, and Soft Aurora. Admins select them from **Admin > Theming**.
|
|
Built-in themes cannot be renamed, edited, or deleted.
|
|
|
|
Open a theme's **More actions** section and duplicate it to create an editable
|
|
custom theme. Custom themes can be previewed in light and dark mode, saved,
|
|
applied globally, renamed, duplicated, or deleted. Deleting the active custom
|
|
theme falls back to Lumi Default.
|
|
|
|
The compact editor exposes common colors first. Advanced controls cover
|
|
background glows, raised surfaces, links, buttons, inputs, focus rings, radius,
|
|
shadow strength, and spacing scale. Typography controls use constrained font
|
|
presets plus bounded base-size, heading-scale, and control-density ranges. The
|
|
server accepts only six-digit hex colors, supported font presets, bounded metric
|
|
values, and readable text/button/input contrast.
|
|
|
|
Draft values are isolated to preview roots. The compact preview and pop-out
|
|
preview update colors, role colors, metrics, spacing, and typography before
|
|
save, but the editor shell and live site keep the active saved theme until the
|
|
admin saves/applies the custom theme. The compact preview is hidden on narrow
|
|
phone layouts; use the Preview action to open the synchronized pop-out instead.
|
|
|
|
The compact preview includes representative headings, pills, cards, buttons,
|
|
state buttons, inputs, toggles, alerts/statuses, badges, tables, modal samples,
|
|
dirty-state markers, and spacing samples. The pop-out uses a faithful Lumi page
|
|
shell with safe sample data so admins can test draft themes against dashboard,
|
|
settings, logs, AI, and component-like layouts without exposing real admin data.
|
|
|
|
Missing or invalid stored values are replaced from the custom theme's built-in
|
|
base. Existing installations with modified legacy `theme_light_*`,
|
|
`theme_dark_*`, or `theme_role_*` settings are migrated once into a custom
|
|
**Migrated Theme** and selected automatically. The legacy `/admin/theming` POST
|
|
route remains supported and writes into an editable custom theme.
|
|
|
|
Run `npm run verify:webui` to compile every EJS view and exercise built-in theme
|
|
validation plus custom duplicate, apply, edit validation, typography validation,
|
|
stateful theme actions, localhost login rendering, rename, and delete.
|
|
|
|
## Localhost Login
|
|
|
|
Development builds opened from `localhost`, `127.0.0.1`, or `::1` show a
|
|
**Localhost Login** option. It defaults to username `admin` and password `admin`
|
|
unless those settings have already been changed. The option is not inserted into
|
|
the login list, cannot be used, and does not satisfy setup requirements for
|
|
non-localhost requests.
|
|
|
|
Admins can change the localhost username and password from **Admin > Settings**
|
|
when the settings page itself is accessed through localhost. Leaving the
|
|
password field blank keeps the existing password.
|
|
|
|
## Lumi AI Settings And Feedback
|
|
|
|
Lumi AI's main Selected model dropdown lists only installed/downloaded models.
|
|
If the configured model is missing, the settings page shows a warning and saving
|
|
requires selecting an installed model. Main context, gate context, and output
|
|
token budgets use shared presets from Tiny (256) through Extra extended
|
|
(32768). Unsupported freeform values are rejected server-side.
|
|
|
|
AI feedback supports `feedback_kind` values `strict_correction` and
|
|
`instruction_based`; instruction-based feedback is the default because most
|
|
reviews are guidance for future replies rather than exact replacement answers.
|
|
Feedback tags include `wrong_tool_usage` for cases where the model called the
|
|
wrong tool or failed to call an expected tool. Review, edit, and implementation
|
|
views show both the kind and tag so admins can tell direct answer corrections
|
|
from broader tool-calling or instruction guidance.
|
|
|
|
Model/runtime downloads and the combined Start/Restart runtime control use the
|
|
Lumi state button behavior. Enhanced browsers start downloads and runtime
|
|
actions through fetch, update button state/progress in place, and avoid hard
|
|
page refreshes; the underlying POST routes remain available for non-JavaScript
|
|
fallbacks.
|
|
|
|
## Homepage Content
|
|
|
|
Admins configure homepage external link buttons from Admin > Settings with the
|
|
Homepage content builder. It writes the existing `homepage_link_buttons` JSON
|
|
setting behind the scenes. Each entry may include `enabled`, `label`,
|
|
`description`, `url`, `icon_mode`, `icon_url`, `fetched_favicon_url`,
|
|
`permission` (`public`, `user`, `mod`, `admin`), and `sort_order`. Entries can
|
|
be added, duplicated, moved up/down, removed with contextual confirmation,
|
|
enabled/disabled, and previewed in place. Links open in a new tab with
|
|
`rel="noopener noreferrer"` and are filtered server-side by permission.
|
|
|
|
Admins configure priority-based hero entries with the same builder; it writes
|
|
the existing `homepage_hero_entries` JSON setting behind the scenes. The
|
|
homepage renders the first enabled, available entry the current user can access.
|
|
Hero entries support type, priority/order, permission, source/embed/image URLs,
|
|
video IDs, availability mode, mutually exclusive autoplay modes, duration
|
|
fields, fallback behavior, and a live card preview. The builder shows
|
|
video-only controls only for stream/video types and image/embed/source fields
|
|
only when they apply. Slow external availability checks are intentionally
|
|
avoided; entries fail closed if required local configuration is missing.
|
|
|
|
## Admin Dashboard And Logs
|
|
|
|
The admin dashboard polls `GET /api/admin/dashboard-metrics` for process
|
|
uptime, memory, plugin counts, content counts, and recent log severity totals.
|
|
The dashboard renders lightweight SVG graphs using Lumi tokens and does not add
|
|
a frontend framework dependency.
|
|
|
|
The logs page keeps server-side range/severity/limit filters and adds a labeled
|
|
responsive filter bar with search, reset, refresh, and download actions. Search
|
|
filters the loaded entries client-side; changing range, severity, or limit
|
|
reloads the same `/admin/logs` route with query parameters.
|
|
|
|
## Updates And Local-Only Files
|
|
|
|
Admin update and ZIP upload controls use the same state-button and
|
|
input-action-row patterns as other Lumi actions. Git update actions have
|
|
contextual confirmation copy because they can restart the process. ZIP update
|
|
forms still submit to the existing `/admin/updates/bot` and
|
|
`/admin/updates/plugin` routes and keep the existing snapshot behavior.
|
|
|
|
The repository ignores local-only coordination and credential artifacts such as
|
|
`codex-guidelines`, `Twitch.png`, and `twitch-credentials-lumi.png`. Plugin
|
|
runtime data stays excluded from source control; runtime folders are recreated
|
|
by the plugin data-directory initializer.
|
|
|
|
## Visual references
|
|
|
|
- [Home, desktop](screenshots/lumi-home-desktop.png)
|
|
- [Home, 360px mobile](screenshots/lumi-home-mobile.png)
|
|
- [Custom theme editor, desktop](screenshots/lumi-theme-editor-desktop.png)
|
|
- [Custom theme editor, 360px mobile](screenshots/lumi-theme-editor-mobile.png)
|
|
|
|
The broad sidebar and content structure remains in place. Theme controls moved
|
|
from one long raw color form into the Theme Studio library and grouped custom
|
|
editor; no navigation destination or non-theme control was relocated.
|