diff --git a/public/scripts/extensions/quick-reply/index.js b/public/scripts/extensions/quick-reply/index.js index ee1a71836..461e918b3 100644 --- a/public/scripts/extensions/quick-reply/index.js +++ b/public/scripts/extensions/quick-reply/index.js @@ -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 diff --git a/public/scripts/extensions/quick-reply/src/QuickReply.js b/public/scripts/extensions/quick-reply/src/QuickReply.js index be30e7ad9..8e262cee2 100644 --- a/public/scripts/extensions/quick-reply/src/QuickReply.js +++ b/public/scripts/extensions/quick-reply/src/QuickReply.js @@ -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'); } diff --git a/public/scripts/extensions/quick-reply/src/QuickReplySettings.js b/public/scripts/extensions/quick-reply/src/QuickReplySettings.js index e89f7bd90..caf74fcc9 100644 --- a/public/scripts/extensions/quick-reply/src/QuickReplySettings.js +++ b/public/scripts/extensions/quick-reply/src/QuickReplySettings.js @@ -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, }; } diff --git a/public/scripts/extensions/quick-reply/src/ui/ButtonUi.js b/public/scripts/extensions/quick-reply/src/ui/ButtonUi.js index ede8a553f..3acb1f336 100644 --- a/public/scripts/extensions/quick-reply/src/ui/ButtonUi.js +++ b/public/scripts/extensions/quick-reply/src/ui/ButtonUi.js @@ -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; } } diff --git a/public/scripts/extensions/quick-reply/style.css b/public/scripts/extensions/quick-reply/style.css index c0f169655..91230bca3 100644 --- a/public/scripts/extensions/quick-reply/style.css +++ b/public/scripts/extensions/quick-reply/style.css @@ -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 { diff --git a/public/scripts/extensions/quick-reply/style.less b/public/scripts/extensions/quick-reply/style.less index a119e31fb..abf8cb359 100644 --- a/public/scripts/extensions/quick-reply/style.less +++ b/public/scripts/extensions/quick-reply/style.less @@ -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;