diff --git a/assets/chat/css/command-menus/_index.scss b/assets/chat/css/command-menus/_index.scss new file mode 100644 index 00000000..083c8d7b --- /dev/null +++ b/assets/chat/css/command-menus/_index.scss @@ -0,0 +1,58 @@ +@use '~@destinygg/libstiny' as dgg; + +@use 'poll'; + +.command-menu { + display: none; + position: absolute; + right: 0; + bottom: 0; + left: 0; + z-index: 132; + border: 1px solid dgg.$semantic-border-default; + border-radius: dgg.$semantic-radii-x-small dgg.$semantic-radii-x-small 0 0; + background-color: dgg.$semantic-background-default; + padding: dgg.$space-2; + + &--shown { + display: block; + } + + &__title { + display: flex; + justify-content: center; + margin-bottom: dgg.$space-2; + border-bottom: 1px solid dgg.$semantic-border-default; + padding-bottom: dgg.$space-2; + color: dgg.$semantic-foreground-default; + font: dgg.$body-500-bold; + } + + &__content { + display: flex; + flex-direction: column; + justify-content: center; + } + + &__section { + padding: dgg.$space-2; + + &:not(:last-child) { + border-bottom: 1px solid dgg.$semantic-border-default; + } + } + + &__actions { + display: flex; + justify-content: space-between; + border-top: 1px solid dgg.$semantic-border-default; + padding: dgg.$space-2 0; + } + + &__input { + display: flex; + justify-content: center; + margin-bottom: dgg.$space-2; + width: 100%; + } +} diff --git a/assets/chat/css/command-menus/_poll.scss b/assets/chat/css/command-menus/_poll.scss new file mode 100644 index 00000000..e9074b5c --- /dev/null +++ b/assets/chat/css/command-menus/_poll.scss @@ -0,0 +1,13 @@ +@use '~@destinygg/libstiny' as dgg; + +#command-menu-poll { + .command-menu-poll-answer { + &:nth-child(-n + 2) .input__suffix { + display: none; + } + + .input__suffix { + padding: dgg.$space-1; + } + } +} diff --git a/assets/chat/css/style.scss b/assets/chat/css/style.scss index cae4cfee..bda1f9ea 100644 --- a/assets/chat/css/style.scss +++ b/assets/chat/css/style.scss @@ -1,14 +1,17 @@ @use 'sass:color'; +@use '~@destinygg/libstiny'; + @use '~normalize.css/normalize'; @use '~tippy.js/dist/tippy'; @use '~tippy.js/dist/svg-arrow'; @use 'abstracts' as a; @use 'chat'; +@use 'command-menus'; +@use 'components'; @use 'menus'; @use 'messages'; -@use 'components'; @import url('https://fonts.googleapis.com/css?family=Roboto:400,500,600,700'); diff --git a/assets/chat/js/autocomplete.js b/assets/chat/js/autocomplete.js index dbbba009..a4c4ffab 100644 --- a/assets/chat/js/autocomplete.js +++ b/assets/chat/js/autocomplete.js @@ -128,9 +128,10 @@ function selectHelper(ac) { } class ChatAutoComplete { - constructor() { + constructor(chat) { + this.chat = chat; /** @member jQuery */ - this.ui = $(`
`); + this.ui = this.chat.ui.find('#chat-auto-complete'); this.ui.on('click', 'li', (e) => this.select(parseInt(e.currentTarget.getAttribute('data-index'), 10)), ); @@ -145,7 +146,6 @@ class ChatAutoComplete { bind(chat) { this.chat = chat; this.input = chat.input; - this.ui.insertBefore(chat.input); let originval = ''; let shiftdown = false; let keypressed = false; diff --git a/assets/chat/js/chat.js b/assets/chat/js/chat.js index e4ac0dbc..88dc08f1 100644 --- a/assets/chat/js/chat.js +++ b/assets/chat/js/chat.js @@ -33,6 +33,7 @@ import { ChatUserInfoMenu, ChatEventActionMenu, } from './menus'; +import { IconsController } from './icons'; import ChatEventBar from './event-bar/EventBar'; import ChatAutoComplete from './autocomplete'; import ChatInputHistory from './history'; @@ -41,6 +42,7 @@ import ChatStore from './store'; import Settings from './settings'; import ChatWindow from './window'; import { ChatPoll, parseQuestionAndTime } from './poll'; +import { CommandMenuPoll } from './command-menus'; import { isMuteActive, MutedTimer } from './mutedtimer'; import EmoteService from './emotes'; import UserFeatures from './features'; @@ -92,14 +94,17 @@ class Chat { this.flairsMap = new Map(); this.emoteService = new EmoteService(); + this.icons = new IconsController(); + this.user = new ChatUser(); this.users = new Map(); this.whispers = new Map(); this.windows = new Map(); this.settings = new Map(settingsdefault); this.commands = new ChatCommands(); - this.autocomplete = new ChatAutoComplete(); + this.autocomplete = null; this.menus = new Map(); + this.commandMenus = new Map(); this.taggednicks = new Map(); this.taggednotes = new Map(); this.ignoring = new Set(); @@ -291,6 +296,8 @@ class Chat { this.ui.prependTo(appendTo || 'body'); $(MessageTemplateHTML).prependTo('body'); + this.icons.renderIcons(); + // We use this style sheet to apply GUI updates via css (e.g. user focus) this.css = (() => { const link = document.createElement('style'); @@ -317,6 +324,7 @@ class Chat { this.loginscrn = this.ui.find('#chat-login-screen'); this.loadingscrn = this.ui.find('#chat-loading'); this.windowselect = this.ui.find('#chat-windows-select'); + this.autocomplete = new ChatAutoComplete(this); this.inputhistory = new ChatInputHistory(this); this.userfocus = new ChatUserFocus(this, this.css); this.mainwindow = new ChatWindow('main').into(this); @@ -392,6 +400,11 @@ class Chat { ); this.menus.set('event-action-menu', eventActionMenu); + this.commandMenus.set( + 'poll', + new CommandMenuPoll(this.ui.find('#command-menu-poll'), this), + ); + this.autocomplete.bind(this); // Chat input @@ -407,7 +420,6 @@ class Chat { e.stopPropagation(); this.control.emit('SEND', this.input.val().toString().trim()); this.adjustInputHeight(); - this.input.focus(); } }); @@ -1674,19 +1686,8 @@ class Chat { } cmdPOLL(parts, command) { - const slashCommand = `/${command.toLowerCase()}`; const textOnly = parts.join(' '); - try { - // Assume the command's format is invalid if an exception is thrown. - parseQuestionAndTime(textOnly); - } catch { - MessageBuilder.info( - `Usage: ${slashCommand} ?