Merge pull request #3284 from SillyTavern/css-var-slash-command

Add `/css-var` slash command
This commit is contained in:
Cohee
2025-01-09 22:49:14 +02:00
committed by GitHub
5 changed files with 108 additions and 6 deletions

View File

@@ -4,7 +4,7 @@ import { eventSource, event_types, saveSettings, saveSettingsDebounced, getReque
import { showLoader } from './loader.js';
import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js';
import { renderTemplate, renderTemplateAsync } from './templates.js';
import { delay, isSubsetOf, setValueByPath } from './utils.js';
import { delay, isSubsetOf, sanitizeSelector, setValueByPath } from './utils.js';
import { getContext } from './st-context.js';
import { isAdmin } from './user.js';
import { t } from './i18n.js';
@@ -509,10 +509,11 @@ function addExtensionStyle(name, manifest) {
return new Promise((resolve, reject) => {
const url = `/scripts/extensions/${name}/${manifest.css}`;
const id = sanitizeSelector(`${name}-css`);
if ($(`link[id="${name}"]`).length === 0) {
if ($(`link[id="${id}"]`).length === 0) {
const link = document.createElement('link');
link.id = name;
link.id = id;
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = url;
@@ -540,11 +541,12 @@ function addExtensionScript(name, manifest) {
return new Promise((resolve, reject) => {
const url = `/scripts/extensions/${name}/${manifest.js}`;
const id = sanitizeSelector(`${name}-js`);
let ready = false;
if ($(`script[id="${name}"]`).length === 0) {
if ($(`script[id="${id}"]`).length === 0) {
const script = document.createElement('script');
script.id = name;
script.id = id;
script.type = 'module';
script.src = url;
script.async = true;

View File

@@ -277,7 +277,7 @@ function makeMovable(id = 'gallery') {
const newElement = $(template);
newElement.css('background-color', 'var(--SmartThemeBlurTintColor)');
newElement.attr('forChar', id);
newElement.attr('id', `${id}`);
newElement.attr('id', id);
newElement.find('.drag-grabber').attr('id', `${id}header`);
newElement.find('.dragTitle').text('Image Gallery');
//add a div for the gallery

View File

@@ -3962,6 +3962,95 @@ $(document).ready(() => {
</div>
`,
}));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'css-var',
/** @param {{to: string, varname: string }} args @param {string} value @returns {string} */
callback: (args, value) => {
// Map enum to target selector
const targetSelector = {
chat: '#chat',
background: '#bg1',
gallery: '#gallery',
zoomedAvatar: 'div.zoomed_avatar',
}[args.to || 'chat'];
if (!targetSelector) {
toastr.error(`Invalid target: ${args.to}`);
return;
}
if (!args.varname) {
toastr.error('CSS variable name is required');
return;
}
if (!args.varname.startsWith('--')) {
toastr.error('CSS variable names must start with "--"');
return;
}
const elements = document.querySelectorAll(targetSelector);
if (elements.length === 0) {
toastr.error(`No elements found for ${args.to ?? 'chat'} with selector "${targetSelector}"`);
return;
}
elements.forEach(element => {
element.style.setProperty(args.varname, value);
});
console.info(`Set CSS variable "${args.varname}" to "${value}" on "${targetSelector}"`);
},
namedArgumentList: [
SlashCommandNamedArgument.fromProps({
name: 'varname',
description: 'CSS variable name (starting with double dashes)',
typeList: [ARGUMENT_TYPE.STRING],
isRequired: true,
}),
SlashCommandNamedArgument.fromProps({
name: 'to',
description: 'The target element to which the CSS variable will be applied',
typeList: [ARGUMENT_TYPE.STRING],
enumList: [
new SlashCommandEnumValue('chat', null, enumTypes.enum, enumIcons.message),
new SlashCommandEnumValue('background', null, enumTypes.enum, enumIcons.image),
new SlashCommandEnumValue('zoomedAvatar', null, enumTypes.enum, enumIcons.character),
new SlashCommandEnumValue('gallery', null, enumTypes.enum, enumIcons.image),
],
defaultValue: 'chat',
}),
],
unnamedArgumentList: [
SlashCommandArgument.fromProps({
description: 'CSS variable value',
typeList: [ARGUMENT_TYPE.STRING],
isRequired: true,
}),
],
helpString: `
<div>
Sets a CSS variable to a specified value on a target element.
<br />
Only setting of variable names is supported. They have to be prefixed with double dashes ("--exampleVar").
Setting actual CSS properties is not supported. Custom CSS in the theme settings can be used for that.
<br /><br />
<b>This value will be gone after a page reload!</b>
</div>
<div>
<strong>Example:</strong>
<ul>
<li>
<pre><code>/css-var varname="--SmartThemeBodyColor" #ff0000</code></pre>
Sets the text color of the chat to red
</li>
<li>
<pre><code>/css-var to=zoomedAvatar varname="--SmartThemeBlurStrength" 0</code></pre>
Remove the blur from the zoomed avatar
</li>
</ul>
</div>
`,
}));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'movingui',
callback: setmovingUIPreset,

View File

@@ -37,6 +37,7 @@ export const enumIcons = {
voice: '🎤',
server: '🖥️',
popup: '🗔',
image: '🖼️',
true: '✔️',
false: '❌',

View File

@@ -67,6 +67,16 @@ export function escapeHtml(str) {
return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
}
/**
* Make string safe for use as a CSS selector.
* @param {string} str String to sanitize
* @param {string} replacement Replacement for invalid characters
* @returns {string} Sanitized string
*/
export function sanitizeSelector(str, replacement = '_') {
return String(str).replace(/[^a-z0-9_-]/ig, replacement);
}
export function isValidUrl(value) {
try {
new URL(value);