8.1 KiB
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.jsandsrc/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 atGET /api/eventsfor 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.
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.
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.
The live preview updates colors, role colors, metrics, and typography before save. The editor also shows contrast warnings for the current preview mode, offers a reset-to-base action for inherited custom themes, and provides an optional desktop pop-out preview window that stays synchronized with the editor.
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 size is a preset dropdown: Small (2048), Medium (4096), Large (8192), and Extended (16384). Unsupported freeform context values are rejected server-side.
AI feedback supports feedback_kind values strict_correction and
instruction_based. 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.
Homepage Content
Admins can define homepage external link buttons in homepage_link_buttons from
Admin > Settings. Each entry may include enabled, label, description,
url, icon_url, permission (public, user, mod, admin), and
sort_order. Links open in a new tab with rel="noopener noreferrer" and are
filtered server-side by permission.
Admins can define priority-based hero entries in homepage_hero_entries.
Supported types are twitch_stream, youtube_video, youtube_channel,
discord_server_overview, static_image, custom_embed, custom_link, and
none. The homepage renders the first enabled, available entry the current user
can access. Hero entries support priority/order, permission, source/embed/image
URLs, video IDs, availability mode, autoplay mode metadata, and duration fields.
Slow external availability checks are intentionally avoided; entries fail
closed if required local configuration is missing.
Visual references
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.