webui: add custom CSS injection via config (#23904)
* webui: add custom CSS injection via config register a customCSS setting in the Developer section under Custom JSON, syncable so it rides the existing ui-config pass through. inject the value into a single style element in the head, reactive on the setting. lets an operator theme a prebuilt binary through --ui-config without rebuilding, and lets a user set it from the settings panel. * ui: address review from @niutech and @allozaur, rename custom JSON key and CSS field * ui: address review from @allozaur, move custom CSS injection to a style tag in svelte:head * ui: inject custom CSS through a svelte action instead of a bound element move the textContent write into a use: action on the head style node. the action is the idiomatic way to touch a node, so the no-dom-manipulating lint rule is satisfied without a disable. value stays text through textContent, never parsed as HTML. * Update tools/ui/src/lib/constants/settings-keys.ts Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> * ui: address review from @allozaur, rename custom config key to customJson with migration rename the custom config key to customJson across the type, the chat request builder, the settings save check and the custom tools reader, keeping the custom API param name unchanged. add a non destructive migration that copies the legacy custom key to customJson at startup. only render the head style tag when custom CSS is set. --------- Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com>
This commit is contained in:
co-authored by
Aleksander Grygier
parent
aa46bda89b
commit
d749821db3
@@ -470,11 +470,36 @@ const themeMigration: Migration = {
|
||||
|
||||
// Migration Registry & Runner
|
||||
|
||||
const CUSTOM_JSON_MIGRATION_ID = 'custom-json-key-v1';
|
||||
|
||||
const customJsonKeyMigration: Migration = {
|
||||
id: CUSTOM_JSON_MIGRATION_ID,
|
||||
description: 'Copy legacy custom config key to customJson (non-destructive)',
|
||||
|
||||
async run(): Promise<void> {
|
||||
const configRaw = localStorage.getItem(CONFIG_LOCALSTORAGE_KEY);
|
||||
if (configRaw === null) return;
|
||||
|
||||
const config = JSON.parse(configRaw);
|
||||
|
||||
if (!('custom' in config)) return;
|
||||
if (SETTINGS_KEYS.CUSTOM_JSON in config) return;
|
||||
|
||||
config[SETTINGS_KEYS.CUSTOM_JSON] = config.custom;
|
||||
localStorage.setItem(CONFIG_LOCALSTORAGE_KEY, JSON.stringify(config));
|
||||
|
||||
// Non-destructive: keep the legacy custom key for downgrade compatibility
|
||||
if (import.meta.env.DEV && import.meta.env.VITE_DEBUG)
|
||||
console.log(`[Migration] Custom JSON: copied custom to customJson (preserved old key)`);
|
||||
}
|
||||
};
|
||||
|
||||
const migrations: Migration[] = [
|
||||
localStorageMigration,
|
||||
idxdbMigration,
|
||||
legacyMessageMigration,
|
||||
themeMigration
|
||||
themeMigration,
|
||||
customJsonKeyMigration
|
||||
];
|
||||
|
||||
export const MigrationService = {
|
||||
|
||||
Reference in New Issue
Block a user