mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
add QR popout
This commit is contained in:
@ -11,7 +11,6 @@ import { SettingsUi } from './src/ui/SettingsUi.js';
|
||||
|
||||
|
||||
|
||||
//TODO popout QR button bar (allow separate popouts for each QR set?)
|
||||
//TODO move advanced QR options into own UI class
|
||||
//TODO slash commands
|
||||
//TODO easy way to CRUD QRs and sets
|
||||
|
@ -63,6 +63,7 @@ export class QuickReply {
|
||||
const root = document.createElement('div'); {
|
||||
this.dom = root;
|
||||
root.classList.add('qr--button');
|
||||
root.classList.add('menu_button');
|
||||
if (this.hasContext) {
|
||||
root.classList.add('qr--hasCtx');
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ export class QuickReplySettings {
|
||||
|
||||
/**@type {Boolean}*/ isEnabled = false;
|
||||
/**@type {Boolean}*/ isCombined = false;
|
||||
/**@type {Boolean}*/ isPopout = false;
|
||||
/**@type {QuickReplyConfig}*/ config;
|
||||
/**@type {QuickReplyConfig}*/ _chatConfig;
|
||||
get chatConfig() {
|
||||
@ -77,6 +78,7 @@ export class QuickReplySettings {
|
||||
return {
|
||||
isEnabled: this.isEnabled,
|
||||
isCombined: this.isCombined,
|
||||
isPopout: this.isPopout,
|
||||
config: this.config,
|
||||
};
|
||||
}
|
||||
|
@ -1,9 +1,13 @@
|
||||
import { animation_duration } from '../../../../../script.js';
|
||||
import { dragElement } from '../../../../RossAscends-mods.js';
|
||||
import { loadMovingUIState } from '../../../../power-user.js';
|
||||
import { QuickReplySettings } from '../QuickReplySettings.js';
|
||||
|
||||
export class ButtonUi {
|
||||
/**@type {QuickReplySettings}*/ settings;
|
||||
|
||||
/**@type {HTMLElement}*/ dom;
|
||||
/**@type {HTMLElement}*/ popoutDom;
|
||||
|
||||
|
||||
|
||||
@ -16,6 +20,46 @@ export class ButtonUi {
|
||||
|
||||
|
||||
render() {
|
||||
if (this.settings.isPopout) {
|
||||
return this.renderPopout();
|
||||
}
|
||||
return this.renderBar();
|
||||
}
|
||||
unrender() {
|
||||
this.dom?.remove();
|
||||
this.dom = null;
|
||||
this.popoutDom?.remove();
|
||||
this.popoutDom = null;
|
||||
}
|
||||
|
||||
show() {
|
||||
if (!this.settings.isEnabled) return;
|
||||
if (this.settings.isPopout) {
|
||||
document.body.append(this.render());
|
||||
loadMovingUIState();
|
||||
$(this.render()).fadeIn(animation_duration);
|
||||
dragElement($(this.render()));
|
||||
} else {
|
||||
const sendForm = document.querySelector('#send_form');
|
||||
if (sendForm.children.length > 0) {
|
||||
sendForm.children[0].insertAdjacentElement('beforebegin', this.render());
|
||||
} else {
|
||||
sendForm.append(this.render());
|
||||
}
|
||||
}
|
||||
}
|
||||
hide() {
|
||||
this.unrender();
|
||||
}
|
||||
refresh() {
|
||||
this.hide();
|
||||
this.show();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
renderBar() {
|
||||
if (!this.dom) {
|
||||
let buttonHolder;
|
||||
const root = document.createElement('div'); {
|
||||
@ -24,6 +68,18 @@ export class ButtonUi {
|
||||
root.id = 'qr--bar';
|
||||
root.classList.add('flex-container');
|
||||
root.classList.add('flexGap5');
|
||||
const popout = document.createElement('div'); {
|
||||
popout.id = 'qr--popoutTrigger';
|
||||
popout.classList.add('menu_button');
|
||||
popout.classList.add('fa-solid');
|
||||
popout.classList.add('fa-window-restore');
|
||||
popout.addEventListener('click', ()=>{
|
||||
this.settings.isPopout = true;
|
||||
this.refresh();
|
||||
this.settings.save();
|
||||
});
|
||||
root.append(popout);
|
||||
}
|
||||
if (this.settings.isCombined) {
|
||||
const buttons = document.createElement('div'); {
|
||||
buttonHolder = buttons;
|
||||
@ -39,25 +95,66 @@ export class ButtonUi {
|
||||
}
|
||||
return this.dom;
|
||||
}
|
||||
unrender() {
|
||||
this.dom?.remove();
|
||||
this.dom = null;
|
||||
}
|
||||
|
||||
show() {
|
||||
if (!this.settings.isEnabled) return;
|
||||
const sendForm = document.querySelector('#send_form');
|
||||
if (sendForm.children.length > 0) {
|
||||
sendForm.children[0].insertAdjacentElement('beforebegin', this.render());
|
||||
} else {
|
||||
sendForm.append(this.render());
|
||||
|
||||
|
||||
|
||||
renderPopout() {
|
||||
if (!this.popoutDom) {
|
||||
let buttonHolder;
|
||||
const root = document.createElement('div'); {
|
||||
this.popoutDom = root;
|
||||
root.id = 'qr--popout';
|
||||
root.classList.add('qr--popout');
|
||||
root.classList.add('draggable');
|
||||
const head = document.createElement('div'); {
|
||||
head.classList.add('qr--header');
|
||||
root.append(head);
|
||||
const controls = document.createElement('div'); {
|
||||
controls.classList.add('qr--controls');
|
||||
controls.classList.add('panelControlBar');
|
||||
controls.classList.add('flex-container');
|
||||
const drag = document.createElement('div'); {
|
||||
drag.id = 'qr--popoutheader';
|
||||
drag.classList.add('fa-solid');
|
||||
drag.classList.add('fa-grip');
|
||||
drag.classList.add('drag-grabber');
|
||||
drag.classList.add('hoverglow');
|
||||
controls.append(drag);
|
||||
}
|
||||
const close = document.createElement('div'); {
|
||||
close.classList.add('qr--close');
|
||||
close.classList.add('fa-solid');
|
||||
close.classList.add('fa-circle-xmark');
|
||||
close.classList.add('hoverglow');
|
||||
close.addEventListener('click', ()=>{
|
||||
this.settings.isPopout = false;
|
||||
this.refresh();
|
||||
this.settings.save();
|
||||
});
|
||||
controls.append(close);
|
||||
}
|
||||
head.append(controls);
|
||||
}
|
||||
}
|
||||
const body = document.createElement('div'); {
|
||||
buttonHolder = body;
|
||||
body.classList.add('qr--body');
|
||||
if (this.settings.isCombined) {
|
||||
const buttons = document.createElement('div'); {
|
||||
buttonHolder = buttons;
|
||||
buttons.classList.add('qr--buttons');
|
||||
body.append(buttons);
|
||||
}
|
||||
}
|
||||
[...this.settings.config.setList, ...(this.settings.chatConfig?.setList ?? [])]
|
||||
.filter(link=>link.isVisible)
|
||||
.forEach(link=>buttonHolder.append(link.set.render()))
|
||||
;
|
||||
root.append(body);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
hide() {
|
||||
this.unrender();
|
||||
}
|
||||
refresh() {
|
||||
this.hide();
|
||||
this.show();
|
||||
return this.popoutDom;
|
||||
}
|
||||
}
|
||||
|
@ -10,9 +10,37 @@
|
||||
max-width: 100%;
|
||||
overflow-x: auto;
|
||||
order: 1;
|
||||
padding-right: 2.5em;
|
||||
position: relative;
|
||||
}
|
||||
#qr--bar > .qr--buttons {
|
||||
#qr--bar > #qr--popoutTrigger {
|
||||
position: absolute;
|
||||
right: 0.25em;
|
||||
top: 0.25em;
|
||||
}
|
||||
#qr--popout {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0;
|
||||
z-index: 31;
|
||||
}
|
||||
#qr--popout > .qr--header {
|
||||
flex: 0 0 auto;
|
||||
height: 2em;
|
||||
position: relative;
|
||||
}
|
||||
#qr--popout > .qr--header > .qr--controls > .qr--close {
|
||||
height: 15px;
|
||||
aspect-ratio: 1 / 1;
|
||||
font-size: 20px;
|
||||
opacity: 0.5;
|
||||
transition: all 250ms;
|
||||
}
|
||||
#qr--popout > .qr--body {
|
||||
overflow-y: auto;
|
||||
}
|
||||
#qr--bar > .qr--buttons,
|
||||
#qr--popout > .qr--body > .qr--buttons {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
@ -21,12 +49,13 @@
|
||||
gap: 5px;
|
||||
width: 100%;
|
||||
}
|
||||
#qr--bar > .qr--buttons > .qr--buttons {
|
||||
#qr--bar > .qr--buttons > .qr--buttons,
|
||||
#qr--popout > .qr--body > .qr--buttons > .qr--buttons {
|
||||
display: contents;
|
||||
}
|
||||
#qr--bar > .qr--buttons .qr--button {
|
||||
#qr--bar > .qr--buttons .qr--button,
|
||||
#qr--popout > .qr--body > .qr--buttons .qr--button {
|
||||
color: var(--SmartThemeBodyColor);
|
||||
background-color: var(--black50a);
|
||||
border: 1px solid var(--SmartThemeBorderColor);
|
||||
border-radius: 10px;
|
||||
padding: 3px 5px;
|
||||
@ -38,14 +67,17 @@
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
#qr--bar > .qr--buttons .qr--button:hover {
|
||||
#qr--bar > .qr--buttons .qr--button:hover,
|
||||
#qr--popout > .qr--body > .qr--buttons .qr--button:hover {
|
||||
opacity: 1;
|
||||
filter: brightness(1.2);
|
||||
}
|
||||
#qr--bar > .qr--buttons .qr--button > .qr--button-expander {
|
||||
#qr--bar > .qr--buttons .qr--button > .qr--button-expander,
|
||||
#qr--popout > .qr--body > .qr--buttons .qr--button > .qr--button-expander {
|
||||
display: none;
|
||||
}
|
||||
#qr--bar > .qr--buttons .qr--button.qr--hasCtx > .qr--button-expander {
|
||||
#qr--bar > .qr--buttons .qr--button.qr--hasCtx > .qr--button-expander,
|
||||
#qr--popout > .qr--body > .qr--buttons .qr--button.qr--hasCtx > .qr--button-expander {
|
||||
display: block;
|
||||
}
|
||||
.qr--button-expander {
|
||||
|
@ -10,8 +10,38 @@
|
||||
max-width: 100%;
|
||||
overflow-x: auto;
|
||||
order: 1;
|
||||
padding-right: 2.5em;
|
||||
position: relative;
|
||||
|
||||
> #qr--popoutTrigger {
|
||||
position: absolute;
|
||||
right: 0.25em;
|
||||
top: 0.25em;
|
||||
}
|
||||
}
|
||||
#qr--popout {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0;
|
||||
z-index: 31;
|
||||
> .qr--header {
|
||||
flex: 0 0 auto;
|
||||
height: 2em;
|
||||
position: relative;
|
||||
> .qr--controls {
|
||||
> .qr--close {
|
||||
height: 15px;
|
||||
aspect-ratio: 1 / 1;
|
||||
font-size: 20px;
|
||||
opacity: 0.5;
|
||||
transition: all 250ms;
|
||||
}
|
||||
}
|
||||
}
|
||||
> .qr--body {
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
#qr--bar, #qr--popout > .qr--body {
|
||||
> .qr--buttons {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@ -27,7 +57,7 @@
|
||||
|
||||
.qr--button {
|
||||
color: var(--SmartThemeBodyColor);
|
||||
background-color: var(--black50a);
|
||||
// background-color: var(--black50a);
|
||||
border: 1px solid var(--SmartThemeBorderColor);
|
||||
border-radius: 10px;
|
||||
padding: 3px 5px;
|
||||
|
Reference in New Issue
Block a user