Add ability to delete UI themes

This commit is contained in:
Cohee 2024-03-20 00:14:32 +02:00
parent a15ab86fd0
commit 41528d0423
3 changed files with 88 additions and 12 deletions

View File

@ -1995,6 +1995,45 @@ async function updateTheme() {
toastr.success('Theme saved.'); toastr.success('Theme saved.');
} }
async function deleteTheme() {
const themeName = power_user.theme;
if (!themeName) {
toastr.info('No theme selected.');
return;
}
const confirm = await callPopup(`Are you sure you want to delete the theme "${themeName}"?`, 'confirm', '', { okButton: 'Yes' });
if (!confirm) {
return;
}
const response = await fetch('/api/themes/delete', {
method: 'POST',
headers: getRequestHeaders(),
body: JSON.stringify({ name: themeName }),
});
if (!response.ok) {
toastr.error('Failed to delete theme. Check the console for more information.');
return;
}
const themeIndex = themes.findIndex(x => x.name == themeName);
if (themeIndex !== -1) {
themes.splice(themeIndex, 1);
$(`#themes option[value="${themeName}"]`).remove();
power_user.theme = themes[0]?.name;
saveSettingsDebounced();
if (power_user.theme) {
await applyTheme(power_user.theme);
}
toastr.success('Theme deleted.');
}
}
/** /**
* Exports the current theme to a file. * Exports the current theme to a file.
*/ */
@ -2094,7 +2133,7 @@ async function saveTheme(name = undefined) {
compact_input_area: power_user.compact_input_area, compact_input_area: power_user.compact_input_area,
}; };
const response = await fetch('/savetheme', { const response = await fetch('/api/themes/save', {
method: 'POST', method: 'POST',
headers: getRequestHeaders(), headers: getRequestHeaders(),
body: JSON.stringify(theme), body: JSON.stringify(theme),
@ -2992,6 +3031,7 @@ $(document).ready(() => {
$('#ui-preset-save-button').on('click', () => saveTheme()); $('#ui-preset-save-button').on('click', () => saveTheme());
$('#ui-preset-update-button').on('click', () => updateTheme()); $('#ui-preset-update-button').on('click', () => updateTheme());
$('#ui-preset-delete-button').on('click', () => deleteTheme());
$('#movingui-preset-save-button').on('click', saveMovingUI); $('#movingui-preset-save-button').on('click', saveMovingUI);
$('#never_resize_avatars').on('input', function () { $('#never_resize_avatars').on('input', function () {

View File

@ -261,17 +261,6 @@ app.post('/deleteuseravatar', jsonParser, function (request, response) {
return response.sendStatus(404); return response.sendStatus(404);
}); });
app.post('/savetheme', jsonParser, (request, response) => {
if (!request.body || !request.body.name) {
return response.sendStatus(400);
}
const filename = path.join(DIRECTORIES.themes, sanitize(request.body.name) + '.json');
writeFileAtomicSync(filename, JSON.stringify(request.body, null, 4), 'utf8');
return response.sendStatus(200);
});
app.post('/savemovingui', jsonParser, (request, response) => { app.post('/savemovingui', jsonParser, (request, response) => {
if (!request.body || !request.body.name) { if (!request.body || !request.body.name) {
return response.sendStatus(400); return response.sendStatus(400);
@ -499,6 +488,12 @@ redirect('/delbackground', '/api/backgrounds/delete');
redirect('/renamebackground', '/api/backgrounds/rename'); redirect('/renamebackground', '/api/backgrounds/rename');
redirect('/downloadbackground', '/api/backgrounds/upload'); // yes, the downloadbackground endpoint actually uploads one redirect('/downloadbackground', '/api/backgrounds/upload'); // yes, the downloadbackground endpoint actually uploads one
// Redirect deprecated theme API endpoints
redirect('/savetheme', '/api/themes/save');
// Theme management
app.use('/api/themes', require('./src/endpoints/themes').router);
// OpenAI API // OpenAI API
app.use('/api/openai', require('./src/endpoints/openai').router); app.use('/api/openai', require('./src/endpoints/openai').router);

41
src/endpoints/themes.js Normal file
View File

@ -0,0 +1,41 @@
const express = require('express');
const path = require('path');
const fs = require('fs');
const sanitize = require('sanitize-filename');
const writeFileAtomicSync = require('write-file-atomic').sync;
const { jsonParser } = require('../express-common');
const { DIRECTORIES } = require('../constants');
const router = express.Router();
router.post('/save', jsonParser, (request, response) => {
if (!request.body || !request.body.name) {
return response.sendStatus(400);
}
const filename = path.join(DIRECTORIES.themes, sanitize(request.body.name) + '.json');
writeFileAtomicSync(filename, JSON.stringify(request.body, null, 4), 'utf8');
return response.sendStatus(200);
});
router.post('/delete', jsonParser, function (request, response) {
if (!request.body || !request.body.name) {
return response.sendStatus(400);
}
try {
const filename = path.join(DIRECTORIES.themes, sanitize(request.body.name) + '.json');
if (!fs.existsSync(filename)) {
console.error('Theme file not found:', filename);
return response.sendStatus(404);
}
fs.rmSync(filename);
return response.sendStatus(200);
} catch (error) {
console.error(error);
return response.sendStatus(500);
}
});
module.exports = { router };