mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
UI Theme import/export
This commit is contained in:
@@ -3114,8 +3114,17 @@
|
|||||||
<div id="user-settings-block-content" class="flex-container spaceEvenly">
|
<div id="user-settings-block-content" class="flex-container spaceEvenly">
|
||||||
<div name="UserSettingsFirstColumn" id="UI-Theme-Block" class="flex-container flexFlowColumn wide100p">
|
<div name="UserSettingsFirstColumn" id="UI-Theme-Block" class="flex-container flexFlowColumn wide100p">
|
||||||
<div id="UI-presets-block" class="flex-container flexFlowColumn">
|
<div id="UI-presets-block" class="flex-container flexFlowColumn">
|
||||||
<h4>
|
<h4 class="title_restorable">
|
||||||
<span data-i18n="UI Theme Preset">Theme Preset</span>
|
<span data-i18n="UI Theme">UI Theme</span>
|
||||||
|
<div class="flex-container">
|
||||||
|
<div id="ui_preset_import_button" class="menu_button menu_button_icon margin0" title="Import a theme file" data-i18n="[title]Import a theme file">
|
||||||
|
<i class="fa-solid fa-file-import"></i>
|
||||||
|
</div>
|
||||||
|
<div id="ui_preset_export_button" class="menu_button menu_button_icon margin0" title="Export a theme file" data-i18n="[title]Export a theme file">
|
||||||
|
<i class="fa-solid fa-file-export"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<input type="file" id="ui_preset_import_file" accept=".json" hidden>
|
||||||
</h4>
|
</h4>
|
||||||
<div class="flex-container flexnowrap alignitemscenter">
|
<div class="flex-container flexnowrap alignitemscenter">
|
||||||
<select id="themes" class="margin0">
|
<select id="themes" class="margin0">
|
||||||
|
@@ -38,7 +38,7 @@ import { tags } from './tags.js';
|
|||||||
import { tokenizers } from './tokenizers.js';
|
import { tokenizers } from './tokenizers.js';
|
||||||
import { BIAS_CACHE } from './logit-bias.js';
|
import { BIAS_CACHE } from './logit-bias.js';
|
||||||
|
|
||||||
import { countOccurrences, debounce, delay, isOdd, resetScrollHeight, shuffle, sortMoments, stringToRange, timestampToMoment } from './utils.js';
|
import { countOccurrences, debounce, delay, download, getFileText, isOdd, resetScrollHeight, shuffle, sortMoments, stringToRange, timestampToMoment } from './utils.js';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
loadPowerUserSettings,
|
loadPowerUserSettings,
|
||||||
@@ -1981,10 +1981,51 @@ async function updateTheme() {
|
|||||||
toastr.success('Theme saved.');
|
toastr.success('Theme saved.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exports the current theme to a file.
|
||||||
|
*/
|
||||||
|
async function exportTheme() {
|
||||||
|
const themeFile = await saveTheme(power_user.theme);
|
||||||
|
const fileName = `${themeFile.name}.json`;
|
||||||
|
download(JSON.stringify(themeFile, null, 4), fileName, 'application/json');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Imports a theme from a file.
|
||||||
|
* @param {File} file File to import.
|
||||||
|
* @returns {Promise<void>} A promise that resolves when the theme is imported.
|
||||||
|
*/
|
||||||
|
async function importTheme(file) {
|
||||||
|
if (!file) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileText = await getFileText(file);
|
||||||
|
const parsed = JSON.parse(fileText);
|
||||||
|
|
||||||
|
if (!parsed.name) {
|
||||||
|
throw new Error('Missing name');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (themes.some(t => t.name === parsed.name)) {
|
||||||
|
throw new Error('Theme with that name already exists');
|
||||||
|
}
|
||||||
|
|
||||||
|
themes.push(parsed);
|
||||||
|
await applyTheme(parsed.name);
|
||||||
|
await saveTheme(parsed.name);
|
||||||
|
const option = document.createElement('option');
|
||||||
|
option.selected = true;
|
||||||
|
option.value = parsed.name;
|
||||||
|
option.innerText = parsed.name;
|
||||||
|
$('#themes').append(option);
|
||||||
|
saveSettingsDebounced();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves the current theme to the server.
|
* Saves the current theme to the server.
|
||||||
* @param {string|undefined} name Theme name. If undefined, a popup will be shown to enter a name.
|
* @param {string|undefined} name Theme name. If undefined, a popup will be shown to enter a name.
|
||||||
* @returns {Promise<void>} A promise that resolves when the theme is saved.
|
* @returns {Promise<object>} A promise that resolves when the theme is saved.
|
||||||
*/
|
*/
|
||||||
async function saveTheme(name = undefined) {
|
async function saveTheme(name = undefined) {
|
||||||
if (typeof name !== 'string') {
|
if (typeof name !== 'string') {
|
||||||
@@ -2056,6 +2097,8 @@ async function saveTheme(name = undefined) {
|
|||||||
power_user.theme = name;
|
power_user.theme = name;
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return theme;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveMovingUI() {
|
async function saveMovingUI() {
|
||||||
@@ -3278,6 +3321,30 @@ $(document).ready(() => {
|
|||||||
reloadCurrentChat();
|
reloadCurrentChat();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#ui_preset_import_button').on('click', function () {
|
||||||
|
$('#ui_preset_import_file').trigger('click');
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#ui_preset_import_file').on('change', async function() {
|
||||||
|
const inputElement = this instanceof HTMLInputElement && this;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const file = inputElement?.files?.[0];
|
||||||
|
await importTheme(file);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error importing UI theme', error);
|
||||||
|
toastr.error(String(error), 'Failed to import UI theme');
|
||||||
|
} finally {
|
||||||
|
if (inputElement) {
|
||||||
|
inputElement.value = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#ui_preset_export_button').on('click', async function () {
|
||||||
|
await exportTheme();
|
||||||
|
});
|
||||||
|
|
||||||
$(document).on('click', '#debug_table [data-debug-function]', function () {
|
$(document).on('click', '#debug_table [data-debug-function]', function () {
|
||||||
const functionId = $(this).data('debug-function');
|
const functionId = $(this).data('debug-function');
|
||||||
const functionRecord = debug_functions.find(f => f.functionId === functionId);
|
const functionRecord = debug_functions.find(f => f.functionId === functionId);
|
||||||
|
Reference in New Issue
Block a user