From 596fd3312682f2569c178305ebd2361fb40665ab Mon Sep 17 00:00:00 2001 From: terncode <52113450+terncode@users.noreply.github.com> Date: Sat, 31 Aug 2019 16:52:45 +0200 Subject: [PATCH 01/17] Add chat log colors, timestamp, filter & emoji box Chat log names are now based off the ponies coat and mane. Added a timestamp infront of each message. There now is a filter on the top right of the chat box, with it you can filter the past log. Use no prefix for normal non-case sensitive search, use # for case sensitive search and finally use / for RegExp search. When party or whisper messages are received, the respective tab is highlighted. Added an emoji picker, it is displayed when the chat bar is activated. Co-authored-by: Stubenhocker1399 --- .../components/shared/chat-box/chat-box.pug | 8 + .../components/shared/chat-box/chat-box.scss | 191 +++++++++----- src/ts/components/shared/chat-box/chat-box.ts | 24 +- .../components/shared/chat-log/chat-log.pug | 1 + .../components/shared/chat-log/chat-log.scss | 216 ++++++++-------- src/ts/components/shared/chat-log/chat-log.ts | 240 +++++++++++++++++- 6 files changed, 509 insertions(+), 171 deletions(-) diff --git a/src/ts/components/shared/chat-box/chat-box.pug b/src/ts/components/shared/chat-box/chat-box.pug index d14a4f4..d8cca68 100644 --- a/src/ts/components/shared/chat-box/chat-box.pug +++ b/src/ts/components/shared/chat-box/chat-box.pug @@ -5,6 +5,14 @@ aria-label="Chat message") .chat-box-type(#typeBox (click)="toggleChatType()") | #[span(#typePrefix)][#[span.chat-box-type-name(#typeName)]]: + .emotes.emoji-box([style.display]="emojiBoxState") + ul + li(*ngFor="let e of emotes" (click)="addEmoji(e.symbol)" + ) + span.emote-sample.mr-2 + emote-box([emote]="e.names[0]") + + emote-box.game-button.chat-emoji-button([emote]="btnEmoji" (click)="openBox()" (mouseenter)="onMouseEnter($event)") button.game-button.chat-send-button((click)="send($event)" title="Send message" aria-label="Send message") fa-icon([icon]="sendIcon") diff --git a/src/ts/components/shared/chat-box/chat-box.scss b/src/ts/components/shared/chat-box/chat-box.scss index 611fb1e..3cb5212 100644 --- a/src/ts/components/shared/chat-box/chat-box.scss +++ b/src/ts/components/shared/chat-box/chat-box.scss @@ -1,88 +1,155 @@ @import '../../../../styles/partials/variables'; .chat-box { - max-width: 500px; - height: 37px; - position: absolute; - bottom: 0; - left: 0; - right: 0; + max-width: 500px; + height: 37px; + position: absolute; + bottom: 0; + left: 0; + right: 0; } .chat-open-button { - display: block; - position: absolute; - left: 0; - bottom: 0; - z-index: 2; - width: 42px; - height: 40px; + display: block; + position: absolute; + left: 0; + bottom: 0; + z-index: 2; + width: 42px; + height: 40px; } .chat-send-button { - position: absolute; - right: 0; - top: 0; - padding: 0 8px; + position: absolute; + right: 0; + top: 0; + padding: 0 8px; } .chat-input { - opacity: 0.6; - background: black; - color: white; - border: none; - z-index: 1; - padding: 8px; - font-size: 14px; - padding-right: 35px; - padding-left: 90px; - border-radius: $border-radius-base; - outline: none; - width: 100%; + opacity: 0.6; + background: black; + color: white; + border: none; + z-index: 1; + padding: 8px; + font-size: 14px; + padding-right: 35px; + padding-left: 90px; + border-radius: $border-radius-base; + outline: none; + width: 100%; } .chat-box-type { - position: absolute; - left: 42px; - top: 8px; - font-size: 14px; - user-select: none; + position: absolute; + left: 42px; + top: 8px; + font-size: 14px; + user-select: none; cursor: pointer; - - .chat-party > &, .chat-party-think > & { - color: $chat-party; + + .chat-party > &, .chat-party-think > & { + color: $chat-party; } - - .chat-say > &, .chat-think > & { - color: $chat-color; + + .chat-say > &, .chat-think > & { + color: $chat-color; } - - .chat-sup > & { - color: $supporter-1; + + .chat-sup > & { + color: $supporter-1; } - - .chat-sup1 > & { - color: $supporter-1; + + .chat-sup1 > & { + color: $supporter-1; } - - .chat-sup2 > & { - color: $supporter-2; + + .chat-sup2 > & { + color: $supporter-2; } - - .chat-sup3 > & { - color: $supporter-3; - } - - .chat-whisper > & { - color: $chat-whisper; + + .chat-sup3 > & { + color: $supporter-3; } + + .chat-whisper > & { + color: $chat-whisper; + } } .chat-box-type-name { - display: inline-block; - max-width: 120px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - vertical-align: bottom; + display: inline-block; + max-width: 120px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + vertical-align: bottom; +} + +.chat-emoji-button { + position: absolute; + right: 30px; + bottom: 3px; + padding: 0; + margin: 0; + -webkit-filter: grayscale(100%); + filter: grayscale(100%); + + &:hover { + bottom: 4px; + -webkit-filter: grayscale(0); + filter: grayscale(0%); + } +} + +.emoji-box { + display: flex; + padding: 10px; + position: absolute; + background-color: #000000; + opacity: 0.95; + bottom: 40px; + left: 0; + right: 0; + width: 100%; + height: 190px; + overflow-y: auto; + + &::-webkit-scrollbar { + width: 7px; + } + + &::-webkit-scrollbar-thumb { + background: rgb(77, 77, 77); + border-radius: 14px; + } +} + +.emoji-box ul { + margin-bottom: 0; +} + +.emoji-box li { + display: inline; + list-style: none; + column-width: 180px; +} + +.emote-sample { + user-select: none; + display: inline-block; + width: 29px; + height: 29px; + text-align: center; + margin-bottom: 3px; + cursor: pointer; + &:hover { + background: rgba(0, 255, 255, 0.2); + border-radius: 2px; + } +} + +.emote-sample emote-box { + line-height: 2; } diff --git a/src/ts/components/shared/chat-box/chat-box.ts b/src/ts/components/shared/chat-box/chat-box.ts index 909afc7..2cdacac 100644 --- a/src/ts/components/shared/chat-box/chat-box.ts +++ b/src/ts/components/shared/chat-box/chat-box.ts @@ -9,7 +9,7 @@ import { faComment, faAngleDoubleRight } from '../../../client/icons'; import { isInParty } from '../../../client/partyUtils'; import { handleActionCommand } from '../../../client/playerActions'; import { hasHeadAnimation } from '../../../common/pony'; -import { AutocompleteState, autocompleteMesssage, replaceEmojis } from '../../../client/emoji'; +import { AutocompleteState, autocompleteMesssage, replaceEmojis, emojis } from '../../../client/emoji'; import { replaceNodes } from '../../../client/htmlUtils'; import { invalidEnumReturn } from '../../../common/utils'; import { findMatchingEntityNames, findEntityOrMockByAnyMeans, findBestEntityByName } from '../../../client/handlers'; @@ -45,6 +45,8 @@ export class ChatBox implements AfterViewInit, OnDestroy { readonly maxSayLength = SAY_MAX_LENGTH; readonly commentIcon = faComment; readonly sendIcon = faAngleDoubleRight; + readonly emotes = emojis.map(e => e); + emojiBoxState = 'none'; @ViewChild('inputElement', { static: true }) inputElement!: ElementRef; @ViewChild('typeBox', { static: true }) typeBox!: ElementRef; @ViewChild('typePrefix', { static: true }) typePrefix!: ElementRef; @@ -54,6 +56,7 @@ export class ChatBox implements AfterViewInit, OnDestroy { isOpen = false; message: string | undefined = ''; chatType = ChatType.Say; + btnEmoji = emojis[0].names[0]; private pasted = false; private lastMessages: string[] = []; private state: AutocompleteState = {}; @@ -92,6 +95,18 @@ export class ChatBox implements AfterViewInit, OnDestroy { ngOnDestroy() { this.subscriptions.forEach(s => s.unsubscribe()); } + addEmoji(emoji: string) { + this.emojiBoxState = 'none'; + if (!this.message) this.message = emoji; + else if (this.input.maxLength > this.message.length) { + this.message += emoji; + } + } + openBox() { + if (this.emojiBoxState === 'none') + this.emojiBoxState = 'inline-block'; + else this.emojiBoxState = 'none'; + } send(_event: Event | undefined) { let chatType = this.chatType; let message = replaceEmojis(cleanMessage(this.message || '')).substr(0, SAY_MAX_LENGTH); @@ -136,7 +151,6 @@ export class ChatBox implements AfterViewInit, OnDestroy { this.lastMessages.shift(); } } - this.close(); } } @@ -259,6 +273,7 @@ export class ChatBox implements AfterViewInit, OnDestroy { } private close() { if (this.isOpen) { + this.emojiBoxState = 'none'; this.input.blur(); this.isOpen = false; this.chatBox.nativeElement.hidden = true; @@ -273,6 +288,11 @@ export class ChatBox implements AfterViewInit, OnDestroy { this.open(); } } + onMouseEnter(event: MouseEvent) { + if (!event.target) return; + const value = emojis[Math.floor(Math.random() * emojis.length)]; + this.btnEmoji = value.names[0]; + } toggleChatType() { const chatTypes = getChatTypes(this.game); this.chatType = chatTypes[(chatTypes.indexOf(this.chatType) + 1) % chatTypes.length]; diff --git a/src/ts/components/shared/chat-log/chat-log.pug b/src/ts/components/shared/chat-log/chat-log.pug index 3bc0af1..2d1aa0e 100644 --- a/src/ts/components/shared/chat-log/chat-log.pug +++ b/src/ts/components/shared/chat-log/chat-log.pug @@ -13,6 +13,7 @@ | Party a.link-plain.chat-log-tab(#whisperTab tabindex (click)="switchTab('whisper')") | Whisper + input.link-plain.chat-log-tab.chat-log-filter(#filterTab type="text" [style.background-color]="filterColor" (keyup.enter)="(unFocus())" (keyup.esc)="(unFocus())" [placeholder]="'Filter'" (keyup)="filterChat()") .chat-log-scroll-outer() .chat-log-scroll-inner(#scroll) .chat-log-scroll-inner-inner(#lines) diff --git a/src/ts/components/shared/chat-log/chat-log.scss b/src/ts/components/shared/chat-log/chat-log.scss index 62796ae..f7dbcc4 100644 --- a/src/ts/components/shared/chat-log/chat-log.scss +++ b/src/ts/components/shared/chat-log/chat-log.scss @@ -10,150 +10,166 @@ $resizer-size: 12px; $resizer-offset: $resizer-size / 2; .chat-log { - display: flex; - position: absolute; - bottom: 0; - left: 0; - right: 0; - min-width: 200px; - max-width: 100%; - max-height: calc(100vh - 220px); - min-height: 120px; + display: flex; + position: absolute; + bottom: 0; + left: 0; + right: 0; + min-width: 200px; + max-width: 100%; + max-height: calc(100vh - 220px); + min-height: 120px; } .chat-log-buttons { - flex-direction: column-reverse; - width: $chat-log-buttons-width; - padding: 5px 3px; - padding-bottom: 30px; - z-index: 2; + flex-direction: column-reverse; + width: $chat-log-buttons-width; + padding: 5px 3px; + padding-bottom: 30px; + z-index: 2; } .chat-log-toggle { - position: absolute; - bottom: 5px; - left: 4px; - z-index: 3; + position: absolute; + bottom: 5px; + left: 4px; + z-index: 3; } .has-unread .main-bubble { - color: $chat-whisper; + color: $chat-whisper; } .whispers-count { - color: white; - font-weight: bold; - text-align: center; - position: absolute; - left: 6px; - top: 9px; - width: 16px; - font-size: 10px; - display: flex; - justify-content: center; - align-items: center; - line-height: 1rem; + color: white; + font-weight: bold; + text-align: center; + position: absolute; + left: 6px; + top: 9px; + width: 16px; + font-size: 10px; + display: flex; + justify-content: center; + align-items: center; + line-height: 1rem; } .whisper-icon { - position: absolute; - top: 0; - left: 0; - font-size: 14px; - color: $chat-whisper !important; + position: absolute; + top: 0; + left: 0; + font-size: 14px; + color: $chat-whisper !important; } .chat-log-content { - position: relative; - display: flex; - background: $chat-log-bg; - padding: 5px 0; - padding-left: 40px; - margin-left: -$chat-log-buttons-width; - border-radius: $border-radius-base; - word-break: break-word; - white-space: pre-line; - line-height: 20px; - height: 100%; - width: 100%; + position: relative; + display: flex; + background: $chat-log-bg; + padding: 5px 0; + padding-left: 40px; + margin-left: -$chat-log-buttons-width; + border-radius: $border-radius-base; + word-break: break-word; + white-space: pre-line; + line-height: 20px; + height: 100%; + width: 100%; } .chat-log-tabs { - position: absolute; - top: -$chat-log-tabs-height; - left: 30px; - display: flex; - user-select: none; + position: absolute; + top: -$chat-log-tabs-height; + left: 30px; + display: flex; + user-select: none; + text-shadow: 0px 0px 4px #000000; } .chat-log-tab { - background: $chat-log-bg-faded; - padding: 5px 10px 0; - margin-left: 10px; - height: $chat-log-tabs-height; - border-top-left-radius: $border-radius-base; - border-top-right-radius: $border-radius-base; - color: white; + background: $chat-log-bg-faded; + padding: 5px 10px 0; + margin-left: 10px; + height: $chat-log-tabs-height; + border-top-left-radius: $border-radius-base; + border-top-right-radius: $border-radius-base; + color: white; overflow: hidden; - - &.active { - background: $chat-log-bg; - } + + &.active { + background: $chat-log-bg; + } } .chat-log-scroll-outer { - overflow: hidden; - width: 100%; + overflow: hidden; + width: 100%; } .chat-log-scroll-inner { - width: calc(100% + 50px); - height: 100%; - overflow-x: hidden; - overflow-y: scroll; - -webkit-overflow-scrolling: touch; + width: calc(100% + 50px); + height: 100%; + overflow-x: hidden; + overflow-y: scroll; + -webkit-overflow-scrolling: touch; } .chat-log-scroll-inner-inner { - display: flex; - flex-direction: column; - justify-content: flex-end; - min-height: 100%; - padding: 0 5px; + display: flex; + flex-direction: column; + justify-content: flex-end; + min-height: 100%; + padding: 0 5px; } .chat-log-resize-top { - position: absolute; - top: -$resizer-offset; - right: $resizer-offset; - height: $resizer-size; - left: 250px; - cursor: ns-resize; + position: absolute; + top: -$resizer-offset; + right: $resizer-offset; + height: $resizer-size; + left: 250px; + cursor: ns-resize; } .chat-log-resize-top-right { - position: absolute; - top: -($resizer-offset + 1); - right: -($resizer-offset + 1); - width: $resizer-size + 4; - height: $resizer-size + 4; - cursor: nesw-resize; + position: absolute; + top: -($resizer-offset + 1); + right: -($resizer-offset + 1); + width: $resizer-size + 4; + height: $resizer-size + 4; + cursor: nesw-resize; } .chat-log-resize-right { - position: absolute; - top: $resizer-offset; - right: -$resizer-offset; - width: $resizer-size; - bottom: $resizer-offset; - cursor: ew-resize; + position: absolute; + top: $resizer-offset; + right: -$resizer-offset; + width: $resizer-size; + bottom: $resizer-offset; + cursor: ew-resize; } .resize-icon { - font-size: 18px; - position: absolute; - top: -3px; - right: 1px; - transform: rotate(45deg); - color: rgba(255, 255, 255, 0.2); + font-size: 18px; + position: absolute; + top: -3px; + right: 1px; + transform: rotate(45deg); + color: rgba(255, 255, 255, 0.2); +} + +.chat-log-filter { + border: none; + width: 100px; +} + +@media only screen and (max-width: 360px) { + .chat-log-filter { + position: absolute; + left: 0; + bottom: 35px; + width: 100%; + border-radius: 2px; + } } diff --git a/src/ts/components/shared/chat-log/chat-log.ts b/src/ts/components/shared/chat-log/chat-log.ts index 1ac6223..6b1264d 100644 --- a/src/ts/components/shared/chat-log/chat-log.ts +++ b/src/ts/components/shared/chat-log/chat-log.ts @@ -8,9 +8,10 @@ import { MessageType, isPartyMessage, ChatMessage, Pony, FakeEntity, isWhisper, import { SettingsService } from '../../services/settingsService'; import { AgDragEvent } from '../directives/agDrag'; import { element, textNode, removeAllNodes, replaceNodes } from '../../../client/htmlUtils'; -import { DEFAULT_CHATLOG_OPACITY, PONY_TYPE } from '../../../common/constants'; +import { DEFAULT_CHATLOG_OPACITY, PONY_TYPE, SECOND } from '../../../common/constants'; import { faCaretUp, faArrowDown } from '../../../client/icons'; import { sampleMessages } from '../../../common/debugData'; +import { findEntityById } from '../../../common/worldMap'; interface IndexEntryUser { id: number; @@ -26,6 +27,8 @@ interface ChatLogLineDOM { entry: ChatLogMessage; root: HTMLElement; label: HTMLElement; + time: HTMLElement; + timeContent: HTMLElement; labelText: Text; name: HTMLElement; nameContent: HTMLElement; @@ -98,11 +101,19 @@ export function createChatLogLineDOM(clickLabel: ClickHandler, clickName: ClickH line.root = element('div', 'chat-line', [ element('span', 'chat-line-lead'), + line.time = element('span', 'chat-line-name', [ + textNode(`[`), + line.timeContent = element( + 'span', 'chat-line-time-content', [textNode('')], undefined), + line.index = element('span', 'chat-line-time-index', [line.indexText = textNode('')]), + textNode('] '), + ]), line.label = element( 'span', 'chat-line-label mr-1', [line.labelText = textNode('')], undefined, { click: () => clickLabel(line.entry) }), + line.prefixText = textNode(''), line.name = element('span', 'chat-line-name', [ - textNode('['), + textNode(`[`), line.nameContent = element( 'span', 'chat-line-name-content', [textNode('')], undefined, { click: () => clickName(line.entry) }), line.index = element('span', 'chat-line-name-index', [line.indexText = textNode('')], { title: 'duplicate name' }), @@ -125,12 +136,32 @@ export function updateChatLogLine(line: ChatLogLineDOM, entry: ChatLogMessage) { line.labelText.nodeValue = label ? `[${label}]` : ''; updateChatLogName(line, entry); + updateTime(line); line.prefixText.nodeValue = prefix || ''; line.suffixText.nodeValue = suffix ? ` ${suffix}: ` : ': '; replaceNodes(line.message, message); } +function updateTime(line: ChatLogLineDOM) { + line.time.style.display = 'inline'; + replaceNodes(line.timeContent, getCurrentTime()); +} + +function getCurrentTime() { + const date = new Date(); + const hours = date.getHours().toString(); + const minutes = date.getMinutes().toString(); + const seconds = date.getSeconds().toString(); + return `${hours.length === 1 ? `0${hours}` : hours}:${minutes.length === 1 ? `0${minutes}` : minutes}:${seconds.length === 1 ? `0${seconds}` : seconds}`; +} + +function setNameColors(line: ChatLogLineDOM | undefined, colors?: string[] | null) { + if (!colors || !line) return; + if (colors[1]) line.name.style.color = colors[1]; + if (colors[0]) line.nameContent.style.color = colors[0]; +} + function updateChatLogName(line: ChatLogLineDOM, { name, index }: ChatLogMessage) { if (name) { line.name.style.display = 'inline'; @@ -171,7 +202,6 @@ function findUserIndex(users: IndexEntryUser[], id: number, crc: number | undefi return i; } } - return -1; } @@ -189,6 +219,7 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { @ViewChild('localTab', { static: true }) localTab!: ElementRef; @ViewChild('partyTab', { static: true }) partyTab!: ElementRef; @ViewChild('whisperTab', { static: true }) whisperTab!: ElementRef; + @ViewChild('filterTab', { static: true }) filterTab!: ElementRef; @ViewChild('toggleButton', { static: true }) toggleButton!: ElementRef; @ViewChild('count', { static: true }) countElement!: ElementRef; @ViewChild('content', { static: true }) contentElement!: ElementRef; @@ -210,6 +241,9 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { private indexes = new Map(); private messageCounter = 0; private lastOpacity = 0; + private autoClear: null | NodeJS.Timeout = null; + private autoUnfocus: null | NodeJS.Timeout = null; + filterColor = this.inactiveBg; constructor( private game: PonyTownGame, private settingsService: SettingsService, @@ -277,6 +311,8 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { } } ngAfterViewInit() { + const canvas = document.getElementById('canvas') as HTMLCanvasElement; + canvas.addEventListener('click', () => this.unFocus()); this.game.findEntityFromChatLog = this.findEntityFromMessages; this.game.findEntityFromChatLogByName = this.findEntityFromMessagesByName; @@ -414,6 +450,165 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { return index; } + + filterChat() { + this.clearTimeOutAutoClear(); + this.clearTimeOutAutoUnfocus(); + let value = this.filterTab.nativeElement.value; + if (!value) { + this.clearTimeOutAutoClear(); + this.unFocus(); + this.showHideChatLogLines('', false); + return; + } + else this.filterColor = this.bg; + + this.autoClear = setTimeout(() => { + this.filterTab.nativeElement.value = ''; + this.filterChat(); + this.unFocus(); + }, SECOND * 30); + + this.autoUnfocus = setTimeout(() => { + this.unFocus(); + }, SECOND * 3); + + let toLowerCase = false; + + if (value.startsWith('#')) value = value.slice(1); + else if (value.startsWith('/')) { + value = value.slice(1); + try { + const regExp = new RegExp(value); + this.showHideChatLogLines(regExp, toLowerCase); + this.filterTab.nativeElement.style.color = ''; + } catch (err) { + this.filterTab.nativeElement.style.color = '#ff6666'; + } + return; + } + else { + value = value.toLowerCase(); + toLowerCase = true; + } + this.showHideChatLogLines(value, toLowerCase); + } + + showHideChatLogLines(content: string | RegExp, caseSensitive: boolean) { + const lines = this.linesElement.getElementsByTagName('div'); + + for (let i = 0; i < lines.length; i++) { + let textContent = lines[i].textContent; + + if (textContent) { + textContent = textContent.slice(10); + + if (typeof content === 'string') { + if (caseSensitive) + textContent.toLowerCase().includes(content) ? lines[i].hidden = false : lines[i].hidden = true; + else + textContent.includes(content) ? lines[i].hidden = false : lines[i].hidden = true; + } else { + textContent.match(content) ? lines[i].hidden = false : lines[i].hidden = true; + } + } + } + } + + unhideAllLines() { + const lines = this.linesElement.getElementsByTagName('div'); + for (let i = 0; i < lines.length; i++) { + lines[i].hidden = false; + } + } + + private getRGB(hex: string) { + const bigint = parseInt(hex, 16); + const r = (bigint >> 16) & 255; + const g = (bigint >> 8) & 255; + const b = bigint & 255; + return [r, g, b]; + } + + private RGBToHSL(rgb: number[]) { + let r = rgb[0] / 255; + let g = rgb[1] / 255; + let b = rgb[2] / 255; + let max = Math.max(r, g, b); + let min = Math.min(r, g, b); + let delta = max - min; + let h = 0; + let s; + let l; + + if (max === min) h = 0; + else if (r === max) h = (g - b) / delta; + else if (g === max) h = 2 + (b - r) / delta; + else if (b === max) h = 4 + (r - g) / delta; + + h = Math.min(h * 60, 360); + + if (h < 0) h += 360; + + l = (min + max) / 2; + + if (max === min) s = 0; + else if (l <= 0.5) s = delta / (max + min); + else s = delta / (2 - max - min); + h = Math.floor(h); + s = Math.floor(s * 100); + l = Math.floor(l * 100); + + if (l < 45) l = 45; + //if (s > 60) s = 60; + return `hsl(${h}, ${s}%, ${l}%)`; + } + + fixColor(color: string) { + if (color === 'ff') color = '000000'; + if (color === '0') color = 'ffffff'; + return color; + } + + private getCharaterColors(id: number | undefined) { + if (!id) return null; + const entity = findEntityById(this.game.map, id) as Pony; + if (!entity || !entity.palettePonyInfo) return null; + let colors = []; + let body = entity.palettePonyInfo.body; + let mane = entity.palettePonyInfo.mane; + if (body && body.palette && body.palette.colors[1]) { + let bodyColor = this.fixColor(body.palette.colors[1].toString(16).substr(0, 6)); + const RGB = this.getRGB(bodyColor); + colors.push(this.RGBToHSL(RGB)); + } + if (mane && mane.palette && mane.palette.colors[1]) { + let maneColor = this.fixColor(mane.palette.colors[1].toString(16).substr(0, 6)); + const RGB = this.getRGB(maneColor); + colors.push(this.RGBToHSL(RGB)); + } else if (colors && colors[0]) { + colors.push((colors[0])); + } + return colors; + } + + clearTimeOutAutoClear() { + if (this.autoClear) clearTimeout(this.autoClear); + this.autoClear = null; + this.filterColor = this.inactiveBg; + } + + clearTimeOutAutoUnfocus() { + if (this.autoUnfocus) clearTimeout(this.autoUnfocus); + this.autoUnfocus = null; + } + + unFocus() { + this.clearTimeOutAutoUnfocus(); + if (this.filterTab.nativeElement) + this.filterTab.nativeElement.blur(); + } + addMessage(message: ChatMessage) { if (message.name && message.message) { const entry = this.createEntry(message); @@ -422,14 +617,19 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { const open = this.open; const scrolledToEnd = open ? this.scrolledToEnd : false; const tab = this.activeTab; + let colors: string[] | null = null; + colors = this.getCharaterColors(message.id); + this.addEntryToList(this.local, GENERAL_CHAT_LIMIT, open && tab === 'local', entry); + setNameColors(entry.dom, colors); if (party || whisper) { const partyEntry = { ...entry }; partyEntry.dom = undefined; partyEntry.label = whisper ? partyEntry.label : undefined; this.addEntryToList(this.party, PARTY_CHAT_LIMIT, open && tab === 'party', partyEntry); + setNameColors(partyEntry.dom, colors); } if (whisper) { @@ -437,6 +637,7 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { whisperEntry.dom = undefined; whisperEntry.label = undefined; this.addEntryToList(this.whisper, WHISPER_CHAT_LIMIT, open && tab === 'whisper', whisperEntry); + setNameColors(whisperEntry.dom, colors); } if (message.type === MessageType.Whisper && !this.open) { @@ -447,12 +648,21 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { this.scrollToEnd(); } + if (tab !== 'whisper' && isWhisper(message.type)) { + this.whisperTab.nativeElement.classList.add('unread'); + this.whisperTab.nativeElement.style.backgroundColor = `rgba(225, 161, 223, ${this.opacity / 100})`; + } + if (tab !== 'party' && party) { + this.partyTab.nativeElement.classList.add('unread'); + this.partyTab.nativeElement.style.backgroundColor = `rgba(184, 227, 255, ${this.opacity / 100})`; + } + this.filterChat(); this.messageCounter++; } } + private addEntryToList(list: ChatLogMessage[], limit: number, isOpen: boolean, entry: ChatLogMessage) { let removedDom: ChatLogLineDOM | undefined; - while (list.length >= limit) { const removed = list.shift(); @@ -465,7 +675,6 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { removed.dom = undefined; } } - list.push(entry); if (isOpen) { @@ -474,11 +683,13 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { this.linesElement.appendChild(entry.dom.root); } } + toggle() { this.settings.chatlogClosed = !this.settings.chatlogClosed; this.settingsService.saveBrowserSettings(); this.updateOpen(); } + switchTab(tab: Tab) { if (this.activeTab !== tab) { this.settings.chatlogTab = tab; @@ -488,31 +699,39 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { this.updateTabs(); } } + private updateTabs() { this.setActiveTab(this.localTab.nativeElement, this.activeTab === 'local'); this.setActiveTab(this.partyTab.nativeElement, this.activeTab === 'party'); this.setActiveTab(this.whisperTab.nativeElement, this.activeTab === 'whisper'); } + private setActiveTab(tab: HTMLElement, active: boolean) { if (active) { tab.classList.add('active'); + tab.classList.remove('unread'); tab.style.backgroundColor = this.bg; } else { tab.classList.remove('active'); - tab.style.backgroundColor = this.inactiveBg; + if (!tab.classList.contains('unread')) + tab.style.backgroundColor = this.inactiveBg; } } + scrollToEnd() { // requestAnimationFrame(this.scrollHandler); this.scrollToEndAtFrame = true; } + scrollHandler = () => { this.scrollingToEnd = true; this.scroll.nativeElement.scrollTop = 99999; } + clickNameHandler = (message: ChatLogMessage) => { this.zone.run(() => this.nameClick.emit(message)); } + clickLabel = (message: ChatLogMessage) => { this.zone.run(() => { if (message.label) { @@ -520,9 +739,11 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { } }); } + private clearList() { removeAllNodes(this.linesElement); } + private regenerateList() { this.clearList(); @@ -531,12 +752,14 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { this.messages.forEach(entry => { if (!entry.dom) { entry.dom = createChatLogLineDOM(this.clickLabel, this.clickNameHandler); + setNameColors(entry.dom, this.getCharaterColors(entry.entityId)); updateChatLogLine(entry.dom, entry); } lines.appendChild(entry.dom.root); }); } + drag({ x, y, type, event }: AgDragEvent, resizeY: boolean, resizeX: boolean) { event.preventDefault(); @@ -548,7 +771,7 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { } if (resizeX) { - this.settings.chatlogWidth = clamp(x - this.startX, 200, 2000); + this.settings.chatlogWidth = clamp(x - this.startX, 200 + 74.7, 2000); } if (resizeY) { @@ -566,6 +789,7 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { this.scrollToEnd(); } } + private setUnread(value: number) { if (this.unread !== value) { this.unread = value; @@ -581,11 +805,13 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { } } } + private findEntityFromMessages = (id: number): FakeEntity | undefined => { return findEntityFromMessages(id, this.whisper) || findEntityFromMessages(id, this.party) || findEntityFromMessages(id, this.local); } + private findEntityFromMessagesByName = (name: string): FakeEntity | undefined => { return findEntityFromMessagesByName(name, this.game.playerId, this.whisper) || findEntityFromMessagesByName(name, this.game.playerId, this.party) || From df3f1f409d08ff25614d1f6bfda153f5975f01bb Mon Sep 17 00:00:00 2001 From: Terncode Date: Sat, 7 Sep 2019 13:44:25 +0200 Subject: [PATCH 02/17] Fixed color bug --- src/ts/components/shared/chat-log/chat-log.ts | 231 +++++++++++++++++- 1 file changed, 225 insertions(+), 6 deletions(-) diff --git a/src/ts/components/shared/chat-log/chat-log.ts b/src/ts/components/shared/chat-log/chat-log.ts index 1ac6223..9367fb3 100644 --- a/src/ts/components/shared/chat-log/chat-log.ts +++ b/src/ts/components/shared/chat-log/chat-log.ts @@ -8,9 +8,10 @@ import { MessageType, isPartyMessage, ChatMessage, Pony, FakeEntity, isWhisper, import { SettingsService } from '../../services/settingsService'; import { AgDragEvent } from '../directives/agDrag'; import { element, textNode, removeAllNodes, replaceNodes } from '../../../client/htmlUtils'; -import { DEFAULT_CHATLOG_OPACITY, PONY_TYPE } from '../../../common/constants'; +import { DEFAULT_CHATLOG_OPACITY, PONY_TYPE, SECOND } from '../../../common/constants'; import { faCaretUp, faArrowDown } from '../../../client/icons'; import { sampleMessages } from '../../../common/debugData'; +import { findEntityById } from '../../../common/worldMap'; interface IndexEntryUser { id: number; @@ -26,6 +27,8 @@ interface ChatLogLineDOM { entry: ChatLogMessage; root: HTMLElement; label: HTMLElement; + time: HTMLElement; + timeContent: HTMLElement; labelText: Text; name: HTMLElement; nameContent: HTMLElement; @@ -93,16 +96,25 @@ CLASSES[MessageType.WhisperTo] = 'chat-line-whisper'; CLASSES[MessageType.WhisperAnnouncement] = 'chat-line-whisper-announcement'; CLASSES[MessageType.WhisperToAnnouncement] = 'chat-line-whisper-announcement'; + export function createChatLogLineDOM(clickLabel: ClickHandler, clickName: ClickHandler): ChatLogLineDOM { const line: ChatLogLineDOM = {} as any; line.root = element('div', 'chat-line', [ element('span', 'chat-line-lead'), + line.time = element('span', 'chat-line-name', [ + textNode(`[`), + line.timeContent = element( + 'span', 'chat-line-time-content', [textNode('')], undefined), + line.index = element('span', 'chat-line-time-index', [line.indexText = textNode('')]), + textNode('] '), + ]), line.label = element( 'span', 'chat-line-label mr-1', [line.labelText = textNode('')], undefined, { click: () => clickLabel(line.entry) }), + line.prefixText = textNode(''), line.name = element('span', 'chat-line-name', [ - textNode('['), + textNode(`[`), line.nameContent = element( 'span', 'chat-line-name-content', [textNode('')], undefined, { click: () => clickName(line.entry) }), line.index = element('span', 'chat-line-name-index', [line.indexText = textNode('')], { title: 'duplicate name' }), @@ -125,13 +137,34 @@ export function updateChatLogLine(line: ChatLogLineDOM, entry: ChatLogMessage) { line.labelText.nodeValue = label ? `[${label}]` : ''; updateChatLogName(line, entry); + updateTime(line); line.prefixText.nodeValue = prefix || ''; line.suffixText.nodeValue = suffix ? ` ${suffix}: ` : ': '; replaceNodes(line.message, message); } +function updateTime(line: ChatLogLineDOM) { + line.time.style.display = 'inline'; + replaceNodes(line.timeContent, getCurrentTime()); +} + +function getCurrentTime() { + const date = new Date(); + const hours = date.getHours().toString(); + const minutes = date.getMinutes().toString(); + const seconds = date.getSeconds().toString(); + return `${hours.length === 1 ? `0${hours}` : hours}:${minutes.length === 1 ? `0${minutes}` : minutes}:${seconds.length === 1 ? `0${seconds}` : seconds}`; +} + +function setNameColors(line: ChatLogLineDOM | undefined, colors?: string[] | null) { + if (!colors || !line) return; + if (colors[1]) line.name.style.color = colors[1]; + if (colors[0]) line.nameContent.style.color = colors[0]; +} + function updateChatLogName(line: ChatLogLineDOM, { name, index }: ChatLogMessage) { + if (name) { line.name.style.display = 'inline'; replaceNodes(line.nameContent, name); @@ -171,7 +204,6 @@ function findUserIndex(users: IndexEntryUser[], id: number, crc: number | undefi return i; } } - return -1; } @@ -189,6 +221,7 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { @ViewChild('localTab', { static: true }) localTab!: ElementRef; @ViewChild('partyTab', { static: true }) partyTab!: ElementRef; @ViewChild('whisperTab', { static: true }) whisperTab!: ElementRef; + @ViewChild('filterTab', { static: true }) filterTab!: ElementRef; @ViewChild('toggleButton', { static: true }) toggleButton!: ElementRef; @ViewChild('count', { static: true }) countElement!: ElementRef; @ViewChild('content', { static: true }) contentElement!: ElementRef; @@ -210,6 +243,9 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { private indexes = new Map(); private messageCounter = 0; private lastOpacity = 0; + private autoClear: null | NodeJS.Timeout = null; + private autoUnfocus: null | NodeJS.Timeout = null; + filterColor = this.inactiveBg; constructor( private game: PonyTownGame, private settingsService: SettingsService, @@ -277,6 +313,8 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { } } ngAfterViewInit() { + const canvas = document.getElementById('canvas') as HTMLCanvasElement; + canvas.addEventListener('click', () => this.unFocus()); this.game.findEntityFromChatLog = this.findEntityFromMessages; this.game.findEntityFromChatLogByName = this.findEntityFromMessagesByName; @@ -414,6 +452,170 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { return index; } + + filterChat() { + this.clearTimeOutAutoClear(); + this.clearTimeOutAutoUnfocus(); + let value = this.filterTab.nativeElement.value; + if (!value) { + this.clearTimeOutAutoClear(); + this.unFocus(); + this.showHideChatLogLines('', false); + return; + } + else this.filterColor = this.bg; + + this.autoClear = setTimeout(() => { + this.filterTab.nativeElement.value = ''; + this.filterChat(); + this.unFocus(); + }, SECOND * 30); + + this.autoUnfocus = setTimeout(() => { + this.unFocus(); + }, SECOND * 3); + + let toLowerCase = false; + + if (value.startsWith('#')) value = value.slice(1); + else if (value.startsWith('/')) { + value = value.slice(1); + try { + const regExp = new RegExp(value); + this.showHideChatLogLines(regExp, toLowerCase); + this.filterTab.nativeElement.style.color = ''; + } catch (err) { + this.filterTab.nativeElement.style.color = '#ff6666'; + } + return; + } + else { + value = value.toLowerCase(); + toLowerCase = true; + } + this.showHideChatLogLines(value, toLowerCase); + + } + showHideChatLogLines(content: string | RegExp, caseSensitive: boolean) { + const lines = this.linesElement.getElementsByTagName('div'); + + for (let i = 0; i < lines.length; i++) { + let textContent = lines[i].textContent; + + if (textContent) { + textContent = textContent.slice(10); + + if (typeof content === 'string') { + if (caseSensitive) + textContent.toLowerCase().includes(content) ? lines[i].hidden = false : lines[i].hidden = true; + else + textContent.includes(content) ? lines[i].hidden = false : lines[i].hidden = true; + } else { + textContent.match(content) ? lines[i].hidden = false : lines[i].hidden = true; + } + } + } + } + + unhideAllLines() { + const lines = this.linesElement.getElementsByTagName('div'); + for (let i = 0; i < lines.length; i++) { + lines[i].hidden = false; + } + } + private getRGB(hex: string) { + const bigint = parseInt(hex, 16); + const r = (bigint >> 16) & 255; + const g = (bigint >> 8) & 255; + const b = bigint & 255; + return [r, g, b]; + } + + private RGBToHSL(rgb: number[]) { + let r = rgb[0] / 255; + let g = rgb[1] / 255; + let b = rgb[2] / 255; + let max = Math.max(r, g, b); + let min = Math.min(r, g, b); + let delta = max - min; + let h = 0; + let s; + let l; + + if (max === min) h = 0; + else if (r === max) h = (g - b) / delta; + else if (g === max) h = 2 + (b - r) / delta; + else if (b === max) h = 4 + (r - g) / delta; + + h = Math.min(h * 60, 360); + + if (h < 0) h += 360; + + l = (min + max) / 2; + + if (max === min) s = 0; + else if (l <= 0.5) s = delta / (max + min); + else s = delta / (2 - max - min); + h = Math.floor(h); + s = Math.floor(s * 100); + l = Math.floor(l * 100); + + if (l < 40) { + if (l > 20 && l < 40) { + l += 20; + if (s > 11) s -= 11; + } else { + l = 40; + if (s > 11) s = 0; + } + } + + return `hsl(${h}, ${s}%, ${l}%)`; + } + fixColor(color: string) { + while (color.length <= 7) { + color = `0${color}`; + } + color = color.replace(/0/g, '1'); + return color.substr(0, 6); + } + + private getCharaterColors(id: number | undefined) { + if (!id) return null; + const entity = findEntityById(this.game.map, id) as Pony; + if (!entity || !entity.palettePonyInfo) return null; + let colors = []; + let body = entity.palettePonyInfo.body; + let mane = entity.palettePonyInfo.mane; + if (body && body.palette && body.palette.colors[1]) { + let bodyColor = this.fixColor(body.palette.colors[1].toString(16)); + const RGB = this.getRGB(bodyColor); + colors.push(this.RGBToHSL(RGB)); + } + if (mane && mane.palette && mane.palette.colors[1]) { + let maneColor = this.fixColor(mane.palette.colors[1].toString(16)); + const RGB = this.getRGB(maneColor); + colors.push(this.RGBToHSL(RGB)); + } else if (colors && colors[0]) { + colors.push((colors[0])); + } + return colors; + + } + clearTimeOutAutoClear() { + if (this.autoClear) clearTimeout(this.autoClear); + this.autoClear = null; + this.filterColor = this.inactiveBg; + } + clearTimeOutAutoUnfocus() { + if (this.autoUnfocus) clearTimeout(this.autoUnfocus); + this.autoUnfocus = null; + } + unFocus() { + this.clearTimeOutAutoUnfocus(); + if (this.filterTab.nativeElement) + this.filterTab.nativeElement.blur(); + } addMessage(message: ChatMessage) { if (message.name && message.message) { const entry = this.createEntry(message); @@ -422,14 +624,19 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { const open = this.open; const scrolledToEnd = open ? this.scrolledToEnd : false; const tab = this.activeTab; + let colors: string[] | null = null; + colors = this.getCharaterColors(message.id); + this.addEntryToList(this.local, GENERAL_CHAT_LIMIT, open && tab === 'local', entry); + setNameColors(entry.dom, colors); if (party || whisper) { const partyEntry = { ...entry }; partyEntry.dom = undefined; partyEntry.label = whisper ? partyEntry.label : undefined; this.addEntryToList(this.party, PARTY_CHAT_LIMIT, open && tab === 'party', partyEntry); + setNameColors(partyEntry.dom, colors); } if (whisper) { @@ -437,6 +644,7 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { whisperEntry.dom = undefined; whisperEntry.label = undefined; this.addEntryToList(this.whisper, WHISPER_CHAT_LIMIT, open && tab === 'whisper', whisperEntry); + setNameColors(whisperEntry.dom, colors); } if (message.type === MessageType.Whisper && !this.open) { @@ -447,6 +655,15 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { this.scrollToEnd(); } + if (tab !== 'whisper' && isWhisper(message.type)) { + this.whisperTab.nativeElement.classList.add('unread'); + this.whisperTab.nativeElement.style.backgroundColor = `rgba(225, 161, 223, ${this.opacity / 100})`; + } + if (tab !== 'party' && party) { + this.partyTab.nativeElement.classList.add('unread'); + this.partyTab.nativeElement.style.backgroundColor = `rgba(184, 227, 255, ${this.opacity / 100})`; + } + this.filterChat(); this.messageCounter++; } } @@ -465,7 +682,6 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { removed.dom = undefined; } } - list.push(entry); if (isOpen) { @@ -496,10 +712,12 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { private setActiveTab(tab: HTMLElement, active: boolean) { if (active) { tab.classList.add('active'); + tab.classList.remove('unread'); tab.style.backgroundColor = this.bg; } else { tab.classList.remove('active'); - tab.style.backgroundColor = this.inactiveBg; + if (!tab.classList.contains('unread')) + tab.style.backgroundColor = this.inactiveBg; } } scrollToEnd() { @@ -531,6 +749,7 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { this.messages.forEach(entry => { if (!entry.dom) { entry.dom = createChatLogLineDOM(this.clickLabel, this.clickNameHandler); + setNameColors(entry.dom, this.getCharaterColors(entry.entityId)); updateChatLogLine(entry.dom, entry); } @@ -548,7 +767,7 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { } if (resizeX) { - this.settings.chatlogWidth = clamp(x - this.startX, 200, 2000); + this.settings.chatlogWidth = clamp(x - this.startX, 200 + 74.7, 2000); } if (resizeY) { From fdaa43279cc9fa8bb3dc30d56054f532df1a8c0e Mon Sep 17 00:00:00 2001 From: Stubenhocker1399 Date: Sat, 7 Sep 2019 14:09:19 +0200 Subject: [PATCH 03/17] Increase filter placeholder text contrast --- src/ts/components/shared/chat-log/chat-log.scss | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ts/components/shared/chat-log/chat-log.scss b/src/ts/components/shared/chat-log/chat-log.scss index f7dbcc4..4a5592d 100644 --- a/src/ts/components/shared/chat-log/chat-log.scss +++ b/src/ts/components/shared/chat-log/chat-log.scss @@ -162,6 +162,9 @@ $resizer-offset: $resizer-size / 2; .chat-log-filter { border: none; width: 100px; + &::placeholder { + color: #ccc; + } } @media only screen and (max-width: 360px) { From edfbe9c7dee4f8ecb3b3df2d2c82aa5d1c2a290b Mon Sep 17 00:00:00 2001 From: Stubenhocker1399 Date: Sat, 7 Sep 2019 14:31:09 +0200 Subject: [PATCH 04/17] Cleanup file changes --- .../components/shared/chat-box/chat-box.scss | 214 ++++++++--------- src/ts/components/shared/chat-box/chat-box.ts | 1 + .../components/shared/chat-log/chat-log.scss | 226 +++++++++--------- src/ts/components/shared/chat-log/chat-log.ts | 25 +- 4 files changed, 225 insertions(+), 241 deletions(-) diff --git a/src/ts/components/shared/chat-box/chat-box.scss b/src/ts/components/shared/chat-box/chat-box.scss index 3cb5212..533c587 100644 --- a/src/ts/components/shared/chat-box/chat-box.scss +++ b/src/ts/components/shared/chat-box/chat-box.scss @@ -1,155 +1,155 @@ @import '../../../../styles/partials/variables'; .chat-box { - max-width: 500px; - height: 37px; - position: absolute; - bottom: 0; - left: 0; - right: 0; + max-width: 500px; + height: 37px; + position: absolute; + bottom: 0; + left: 0; + right: 0; } .chat-open-button { - display: block; - position: absolute; - left: 0; - bottom: 0; - z-index: 2; - width: 42px; - height: 40px; + display: block; + position: absolute; + left: 0; + bottom: 0; + z-index: 2; + width: 42px; + height: 40px; } .chat-send-button { - position: absolute; - right: 0; - top: 0; - padding: 0 8px; + position: absolute; + right: 0; + top: 0; + padding: 0 8px; } .chat-input { - opacity: 0.6; - background: black; - color: white; - border: none; - z-index: 1; - padding: 8px; - font-size: 14px; - padding-right: 35px; - padding-left: 90px; - border-radius: $border-radius-base; - outline: none; - width: 100%; + opacity: 0.6; + background: black; + color: white; + border: none; + z-index: 1; + padding: 8px; + font-size: 14px; + padding-right: 35px; + padding-left: 90px; + border-radius: $border-radius-base; + outline: none; + width: 100%; } .chat-box-type { - position: absolute; - left: 42px; - top: 8px; - font-size: 14px; - user-select: none; + position: absolute; + left: 42px; + top: 8px; + font-size: 14px; + user-select: none; cursor: pointer; - - .chat-party > &, .chat-party-think > & { - color: $chat-party; + + .chat-party > &, .chat-party-think > & { + color: $chat-party; } - - .chat-say > &, .chat-think > & { - color: $chat-color; + + .chat-say > &, .chat-think > & { + color: $chat-color; } - - .chat-sup > & { - color: $supporter-1; + + .chat-sup > & { + color: $supporter-1; } - - .chat-sup1 > & { - color: $supporter-1; + + .chat-sup1 > & { + color: $supporter-1; } - - .chat-sup2 > & { - color: $supporter-2; + + .chat-sup2 > & { + color: $supporter-2; } - - .chat-sup3 > & { - color: $supporter-3; + + .chat-sup3 > & { + color: $supporter-3; + } + + .chat-whisper > & { + color: $chat-whisper; } - - .chat-whisper > & { - color: $chat-whisper; - } } .chat-box-type-name { - display: inline-block; - max-width: 120px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - vertical-align: bottom; + display: inline-block; + max-width: 120px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + vertical-align: bottom; } .chat-emoji-button { - position: absolute; - right: 30px; - bottom: 3px; - padding: 0; - margin: 0; - -webkit-filter: grayscale(100%); + position: absolute; + right: 30px; + bottom: 3px; + padding: 0; + margin: 0; + -webkit-filter: grayscale(100%); filter: grayscale(100%); - - &:hover { - bottom: 4px; - -webkit-filter: grayscale(0); - filter: grayscale(0%); - } + + &:hover { + bottom: 4px; + -webkit-filter: grayscale(0); + filter: grayscale(0%); + } } .emoji-box { - display: flex; - padding: 10px; - position: absolute; - background-color: #000000; - opacity: 0.95; - bottom: 40px; - left: 0; - right: 0; - width: 100%; - height: 190px; + display: flex; + padding: 10px; + position: absolute; + background-color: #000000; + opacity: 0.95; + bottom: 40px; + left: 0; + right: 0; + width: 100%; + height: 190px; overflow-y: auto; - &::-webkit-scrollbar { - width: 7px; - } + &::-webkit-scrollbar { + width: 7px; + } - &::-webkit-scrollbar-thumb { - background: rgb(77, 77, 77); - border-radius: 14px; - } + &::-webkit-scrollbar-thumb { + background: rgb(77, 77, 77); + border-radius: 14px; + } } .emoji-box ul { - margin-bottom: 0; + margin-bottom: 0; } .emoji-box li { - display: inline; - list-style: none; - column-width: 180px; + display: inline; + list-style: none; + column-width: 180px; } .emote-sample { - user-select: none; - display: inline-block; - width: 29px; - height: 29px; - text-align: center; - margin-bottom: 3px; - cursor: pointer; - &:hover { - background: rgba(0, 255, 255, 0.2); - border-radius: 2px; - } + user-select: none; + display: inline-block; + width: 29px; + height: 29px; + text-align: center; + margin-bottom: 3px; + cursor: pointer; + &:hover { + background: rgba(0, 255, 255, 0.2); + border-radius: 2px; + } } .emote-sample emote-box { - line-height: 2; + line-height: 2; } diff --git a/src/ts/components/shared/chat-box/chat-box.ts b/src/ts/components/shared/chat-box/chat-box.ts index 2cdacac..4181c66 100644 --- a/src/ts/components/shared/chat-box/chat-box.ts +++ b/src/ts/components/shared/chat-box/chat-box.ts @@ -151,6 +151,7 @@ export class ChatBox implements AfterViewInit, OnDestroy { this.lastMessages.shift(); } } + this.close(); } } diff --git a/src/ts/components/shared/chat-log/chat-log.scss b/src/ts/components/shared/chat-log/chat-log.scss index 4a5592d..1cd13eb 100644 --- a/src/ts/components/shared/chat-log/chat-log.scss +++ b/src/ts/components/shared/chat-log/chat-log.scss @@ -10,169 +10,169 @@ $resizer-size: 12px; $resizer-offset: $resizer-size / 2; .chat-log { - display: flex; - position: absolute; - bottom: 0; - left: 0; - right: 0; - min-width: 200px; - max-width: 100%; - max-height: calc(100vh - 220px); - min-height: 120px; + display: flex; + position: absolute; + bottom: 0; + left: 0; + right: 0; + min-width: 200px; + max-width: 100%; + max-height: calc(100vh - 220px); + min-height: 120px; } .chat-log-buttons { - flex-direction: column-reverse; - width: $chat-log-buttons-width; - padding: 5px 3px; - padding-bottom: 30px; - z-index: 2; + flex-direction: column-reverse; + width: $chat-log-buttons-width; + padding: 5px 3px; + padding-bottom: 30px; + z-index: 2; } .chat-log-toggle { - position: absolute; - bottom: 5px; - left: 4px; - z-index: 3; + position: absolute; + bottom: 5px; + left: 4px; + z-index: 3; } .has-unread .main-bubble { - color: $chat-whisper; + color: $chat-whisper; } .whispers-count { - color: white; - font-weight: bold; - text-align: center; - position: absolute; - left: 6px; - top: 9px; - width: 16px; - font-size: 10px; - display: flex; - justify-content: center; - align-items: center; - line-height: 1rem; + color: white; + font-weight: bold; + text-align: center; + position: absolute; + left: 6px; + top: 9px; + width: 16px; + font-size: 10px; + display: flex; + justify-content: center; + align-items: center; + line-height: 1rem; } .whisper-icon { - position: absolute; - top: 0; - left: 0; - font-size: 14px; - color: $chat-whisper !important; + position: absolute; + top: 0; + left: 0; + font-size: 14px; + color: $chat-whisper !important; } .chat-log-content { - position: relative; - display: flex; - background: $chat-log-bg; - padding: 5px 0; - padding-left: 40px; - margin-left: -$chat-log-buttons-width; - border-radius: $border-radius-base; - word-break: break-word; - white-space: pre-line; - line-height: 20px; - height: 100%; - width: 100%; + position: relative; + display: flex; + background: $chat-log-bg; + padding: 5px 0; + padding-left: 40px; + margin-left: -$chat-log-buttons-width; + border-radius: $border-radius-base; + word-break: break-word; + white-space: pre-line; + line-height: 20px; + height: 100%; + width: 100%; } .chat-log-tabs { - position: absolute; - top: -$chat-log-tabs-height; - left: 30px; - display: flex; - user-select: none; - text-shadow: 0px 0px 4px #000000; + position: absolute; + top: -$chat-log-tabs-height; + left: 30px; + display: flex; + user-select: none; + text-shadow: 0px 0px 4px #000000; } .chat-log-tab { - background: $chat-log-bg-faded; - padding: 5px 10px 0; - margin-left: 10px; - height: $chat-log-tabs-height; - border-top-left-radius: $border-radius-base; - border-top-right-radius: $border-radius-base; - color: white; + background: $chat-log-bg-faded; + padding: 5px 10px 0; + margin-left: 10px; + height: $chat-log-tabs-height; + border-top-left-radius: $border-radius-base; + border-top-right-radius: $border-radius-base; + color: white; overflow: hidden; - - &.active { - background: $chat-log-bg; - } + + &.active { + background: $chat-log-bg; + } } .chat-log-scroll-outer { - overflow: hidden; - width: 100%; + overflow: hidden; + width: 100%; } .chat-log-scroll-inner { - width: calc(100% + 50px); - height: 100%; - overflow-x: hidden; - overflow-y: scroll; - -webkit-overflow-scrolling: touch; + width: calc(100% + 50px); + height: 100%; + overflow-x: hidden; + overflow-y: scroll; + -webkit-overflow-scrolling: touch; } .chat-log-scroll-inner-inner { - display: flex; - flex-direction: column; - justify-content: flex-end; - min-height: 100%; - padding: 0 5px; + display: flex; + flex-direction: column; + justify-content: flex-end; + min-height: 100%; + padding: 0 5px; } .chat-log-resize-top { - position: absolute; - top: -$resizer-offset; - right: $resizer-offset; - height: $resizer-size; - left: 250px; - cursor: ns-resize; + position: absolute; + top: -$resizer-offset; + right: $resizer-offset; + height: $resizer-size; + left: 250px; + cursor: ns-resize; } .chat-log-resize-top-right { - position: absolute; - top: -($resizer-offset + 1); - right: -($resizer-offset + 1); - width: $resizer-size + 4; - height: $resizer-size + 4; - cursor: nesw-resize; + position: absolute; + top: -($resizer-offset + 1); + right: -($resizer-offset + 1); + width: $resizer-size + 4; + height: $resizer-size + 4; + cursor: nesw-resize; } .chat-log-resize-right { - position: absolute; - top: $resizer-offset; - right: -$resizer-offset; - width: $resizer-size; - bottom: $resizer-offset; - cursor: ew-resize; + position: absolute; + top: $resizer-offset; + right: -$resizer-offset; + width: $resizer-size; + bottom: $resizer-offset; + cursor: ew-resize; } .resize-icon { - font-size: 18px; - position: absolute; - top: -3px; - right: 1px; - transform: rotate(45deg); - color: rgba(255, 255, 255, 0.2); + font-size: 18px; + position: absolute; + top: -3px; + right: 1px; + transform: rotate(45deg); + color: rgba(255, 255, 255, 0.2); } .chat-log-filter { - border: none; - width: 100px; - &::placeholder { - color: #ccc; - } + border: none; + width: 100px; + &::placeholder { + color: #ccc; + } } @media only screen and (max-width: 360px) { - .chat-log-filter { - position: absolute; - left: 0; - bottom: 35px; - width: 100%; - border-radius: 2px; - } + .chat-log-filter { + position: absolute; + left: 0; + bottom: 35px; + width: 100%; + border-radius: 2px; + } } diff --git a/src/ts/components/shared/chat-log/chat-log.ts b/src/ts/components/shared/chat-log/chat-log.ts index 7e40e95..1c16c8d 100644 --- a/src/ts/components/shared/chat-log/chat-log.ts +++ b/src/ts/components/shared/chat-log/chat-log.ts @@ -96,14 +96,13 @@ CLASSES[MessageType.WhisperTo] = 'chat-line-whisper'; CLASSES[MessageType.WhisperAnnouncement] = 'chat-line-whisper-announcement'; CLASSES[MessageType.WhisperToAnnouncement] = 'chat-line-whisper-announcement'; - export function createChatLogLineDOM(clickLabel: ClickHandler, clickName: ClickHandler): ChatLogLineDOM { const line: ChatLogLineDOM = {} as any; line.root = element('div', 'chat-line', [ element('span', 'chat-line-lead'), line.time = element('span', 'chat-line-name', [ - textNode(`[`), + textNode('['), line.timeContent = element( 'span', 'chat-line-time-content', [textNode('')], undefined), line.index = element('span', 'chat-line-time-index', [line.indexText = textNode('')]), @@ -111,7 +110,6 @@ export function createChatLogLineDOM(clickLabel: ClickHandler, clickName: ClickH ]), line.label = element( 'span', 'chat-line-label mr-1', [line.labelText = textNode('')], undefined, { click: () => clickLabel(line.entry) }), - line.prefixText = textNode(''), line.name = element('span', 'chat-line-name', [ textNode(`[`), @@ -164,7 +162,6 @@ function setNameColors(line: ChatLogLineDOM | undefined, colors?: string[] | nul } function updateChatLogName(line: ChatLogLineDOM, { name, index }: ChatLogMessage) { - if (name) { line.name.style.display = 'inline'; replaceNodes(line.nameContent, name); @@ -204,6 +201,7 @@ function findUserIndex(users: IndexEntryUser[], id: number, crc: number | undefi return i; } } + return -1; } @@ -596,7 +594,6 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { } return colors; } - clearTimeOutAutoClear() { if (this.autoClear) clearTimeout(this.autoClear); this.autoClear = null; @@ -622,7 +619,6 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { let colors: string[] | null = null; colors = this.getCharaterColors(message.id); - this.addEntryToList(this.local, GENERAL_CHAT_LIMIT, open && tab === 'local', entry); setNameColors(entry.dom, colors); @@ -662,9 +658,9 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { this.messageCounter++; } } - private addEntryToList(list: ChatLogMessage[], limit: number, isOpen: boolean, entry: ChatLogMessage) { let removedDom: ChatLogLineDOM | undefined; + while (list.length >= limit) { const removed = list.shift(); @@ -677,6 +673,7 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { removed.dom = undefined; } } + list.push(entry); if (isOpen) { @@ -685,13 +682,11 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { this.linesElement.appendChild(entry.dom.root); } } - toggle() { this.settings.chatlogClosed = !this.settings.chatlogClosed; this.settingsService.saveBrowserSettings(); this.updateOpen(); } - switchTab(tab: Tab) { if (this.activeTab !== tab) { this.settings.chatlogTab = tab; @@ -701,13 +696,11 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { this.updateTabs(); } } - private updateTabs() { this.setActiveTab(this.localTab.nativeElement, this.activeTab === 'local'); this.setActiveTab(this.partyTab.nativeElement, this.activeTab === 'party'); this.setActiveTab(this.whisperTab.nativeElement, this.activeTab === 'whisper'); } - private setActiveTab(tab: HTMLElement, active: boolean) { if (active) { tab.classList.add('active'); @@ -719,21 +712,17 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { tab.style.backgroundColor = this.inactiveBg; } } - scrollToEnd() { // requestAnimationFrame(this.scrollHandler); this.scrollToEndAtFrame = true; } - scrollHandler = () => { this.scrollingToEnd = true; this.scroll.nativeElement.scrollTop = 99999; } - clickNameHandler = (message: ChatLogMessage) => { this.zone.run(() => this.nameClick.emit(message)); } - clickLabel = (message: ChatLogMessage) => { this.zone.run(() => { if (message.label) { @@ -741,11 +730,9 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { } }); } - private clearList() { removeAllNodes(this.linesElement); } - private regenerateList() { this.clearList(); @@ -761,7 +748,6 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { lines.appendChild(entry.dom.root); }); } - drag({ x, y, type, event }: AgDragEvent, resizeY: boolean, resizeX: boolean) { event.preventDefault(); @@ -791,7 +777,6 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { this.scrollToEnd(); } } - private setUnread(value: number) { if (this.unread !== value) { this.unread = value; @@ -807,13 +792,11 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { } } } - private findEntityFromMessages = (id: number): FakeEntity | undefined => { return findEntityFromMessages(id, this.whisper) || findEntityFromMessages(id, this.party) || findEntityFromMessages(id, this.local); } - private findEntityFromMessagesByName = (name: string): FakeEntity | undefined => { return findEntityFromMessagesByName(name, this.game.playerId, this.whisper) || findEntityFromMessagesByName(name, this.game.playerId, this.party) || From 3c801987bb0f837cde866d33395fc1e61eb664f2 Mon Sep 17 00:00:00 2001 From: Terncode Date: Sun, 8 Sep 2019 18:57:30 +0200 Subject: [PATCH 05/17] Improved code --- src/ts/common/color.ts | 40 +++ src/ts/common/interfaces.ts | 1 + .../components/shared/chat-box/chat-box.pug | 10 +- .../components/shared/chat-box/chat-box.scss | 200 +++++++++----- src/ts/components/shared/chat-box/chat-box.ts | 28 +- .../components/shared/chat-log/chat-log.pug | 2 + .../components/shared/chat-log/chat-log.scss | 247 ++++++++++-------- src/ts/components/shared/chat-log/chat-log.ts | 146 ++++------- .../shared/settings-modal/settings-modal.pug | 12 +- .../shared/settings-modal/settings-modal.ts | 36 +++ 10 files changed, 452 insertions(+), 270 deletions(-) diff --git a/src/ts/common/color.ts b/src/ts/common/color.ts index f6b7040..a0b5944 100644 --- a/src/ts/common/color.ts +++ b/src/ts/common/color.ts @@ -157,6 +157,12 @@ export interface HSVA { a: number; } +export interface HSL { + h: number; + s: number; + l: number; +} + export interface RGB { r: number; g: number; @@ -493,3 +499,37 @@ export function h2rgb(h: number): RGB { b: Math.round(b * 255) }; } + +export function rgb2hsl(rgb: RGB): HSL { + const r = rgb.r / 255; + const g = rgb.g / 255; + const b = rgb.b / 255; + let max = Math.max(r, g, b); + let min = Math.min(r, g, b); + let delta = max - min; + let h = 0; + let s; + let l; + + if (max === min) h = 0; + else if (r === max) h = (g - b) / delta; + else if (g === max) h = 2 + (b - r) / delta; + else if (b === max) h = 4 + (r - g) / delta; + + h = Math.min(h * 60, 360); + if (h < 0) h += 360; + l = (min + max) / 2; + + if (max === min) s = 0; + else if (l <= 0.5) s = delta / (max + min); + else s = delta / (2 - max - min); + h = Math.floor(h); + s = Math.floor(s * 100); + l = Math.floor(l * 100); + + return { h, s, l }; +} + +export function hsl2CSS(hsl: HSL) { + return `hsl(${hsl.h},${hsl.s}%,${hsl.l}%)`; +} diff --git a/src/ts/common/interfaces.ts b/src/ts/common/interfaces.ts index 4fa653d..e9ab8b8 100644 --- a/src/ts/common/interfaces.ts +++ b/src/ts/common/interfaces.ts @@ -683,6 +683,7 @@ export interface BrowserSettings { scale?: number; walkByDefault?: boolean; brightNight?: boolean; + timestamp?: '24' | '12'; } export interface EntityTypeName { diff --git a/src/ts/components/shared/chat-box/chat-box.pug b/src/ts/components/shared/chat-box/chat-box.pug index d14a4f4..e4ba3b3 100644 --- a/src/ts/components/shared/chat-box/chat-box.pug +++ b/src/ts/components/shared/chat-box/chat-box.pug @@ -5,10 +5,18 @@ aria-label="Chat message") .chat-box-type(#typeBox (click)="toggleChatType()") | #[span(#typePrefix)][#[span.chat-box-type-name(#typeName)]]: + .emotes.emoji-box([style.display]="emojiBoxState") + ul + li(*ngFor="let e of emotes" (click)="addEmoji(e.symbol)" + ) + span.emote-sample.mr-2 + emote-box([emote]="e.names[0]") + + emote-box.game-button.chat-emoji-button([emote]="btnEmoji" (click)="toggleEmojiBox()" (mouseenter)="onMouseEnter($event)") button.game-button.chat-send-button((click)="send($event)" title="Send message" aria-label="Send message") fa-icon([icon]="sendIcon") button.game-button.chat-open-button( (click)="toggle()" (mousedown)="$event.preventDefault()" [disabled]="disabled" title="Toggle chat" aria-label="Toggle message") - fa-icon([icon]="commentIcon" [fixedWidth]="true") + fa-icon([icon]="commentIcon" [fixedWidth]="true") \ No newline at end of file diff --git a/src/ts/components/shared/chat-box/chat-box.scss b/src/ts/components/shared/chat-box/chat-box.scss index 611fb1e..dd74296 100644 --- a/src/ts/components/shared/chat-box/chat-box.scss +++ b/src/ts/components/shared/chat-box/chat-box.scss @@ -1,88 +1,148 @@ @import '../../../../styles/partials/variables'; - .chat-box { - max-width: 500px; - height: 37px; - position: absolute; - bottom: 0; - left: 0; - right: 0; + max-width: 500px; + height: 37px; + position: absolute; + bottom: 0; + left: 0; + right: 0; } .chat-open-button { - display: block; - position: absolute; - left: 0; - bottom: 0; - z-index: 2; - width: 42px; - height: 40px; + display: block; + position: absolute; + left: 0; + bottom: 0; + z-index: 2; + width: 42px; + height: 40px; } .chat-send-button { - position: absolute; - right: 0; - top: 0; - padding: 0 8px; + position: absolute; + right: 0; + top: 0; + padding: 0 8px; } .chat-input { - opacity: 0.6; - background: black; - color: white; - border: none; - z-index: 1; - padding: 8px; - font-size: 14px; - padding-right: 35px; - padding-left: 90px; - border-radius: $border-radius-base; - outline: none; - width: 100%; + opacity: 0.6; + background: black; + color: white; + border: none; + z-index: 1; + padding: 8px; + font-size: 14px; + padding-right: 35px; + padding-left: 90px; + border-radius: $border-radius-base; + outline: none; + width: 100%; } .chat-box-type { - position: absolute; - left: 42px; - top: 8px; - font-size: 14px; - user-select: none; - cursor: pointer; - - .chat-party > &, .chat-party-think > & { - color: $chat-party; - } - - .chat-say > &, .chat-think > & { - color: $chat-color; - } - - .chat-sup > & { - color: $supporter-1; - } - - .chat-sup1 > & { - color: $supporter-1; - } - - .chat-sup2 > & { - color: $supporter-2; - } - - .chat-sup3 > & { - color: $supporter-3; - } - - .chat-whisper > & { - color: $chat-whisper; - } + position: absolute; + left: 42px; + top: 8px; + font-size: 14px; + user-select: none; + cursor: pointer; + .chat-party>&, + .chat-party-think>& { + color: $chat-party; + } + .chat-say>&, + .chat-think>& { + color: $chat-color; + } + .chat-sup>& { + color: $supporter-1; + } + .chat-sup1>& { + color: $supporter-1; + } + .chat-sup2>& { + color: $supporter-2; + } + .chat-sup3>& { + color: $supporter-3; + } + .chat-whisper>& { + color: $chat-whisper; + } } .chat-box-type-name { - display: inline-block; - max-width: 120px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - vertical-align: bottom; + display: inline-block; + max-width: 120px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + vertical-align: bottom; } + +.chat-emoji-button { + user-select: none; + position: absolute; + right: 30px; + bottom: 3px; + padding: 0; + margin: 0; + -webkit-filter: grayscale(100%); + filter: grayscale(100%); + &:hover { + bottom: 4px; + -webkit-filter: grayscale(0); + filter: grayscale(0%); + } +} + +.emoji-box { + display: flex; + padding: 10px; + position: absolute; + background-color: #000000; + opacity: 0.95; + bottom: 40px; + left: 0; + right: 0; + width: 100%; + height: 190px; + overflow-y: auto; + &::-webkit-scrollbar { + width: 7px; + } + /* Add a thumb */ + &::-webkit-scrollbar-thumb { + background: rgb(77, 77, 77); + border-radius: 14px; + } +} + +.emoji-box ul { + margin-bottom: 0; +} + +.emoji-box li { + display: inline; + list-style: none; + column-width: 180px; +} + +.emote-sample { + user-select: none; + display: inline-block; + width: 29px; + height: 29px; + text-align: center; + margin-bottom: 3px; + cursor: pointer; + &:hover { + background: rgba(0, 255, 255, 0.2); + border-radius: 2px; + } +} + +.emote-sample emote-box { + line-height: 2; +} \ No newline at end of file diff --git a/src/ts/components/shared/chat-box/chat-box.ts b/src/ts/components/shared/chat-box/chat-box.ts index 909afc7..85c479a 100644 --- a/src/ts/components/shared/chat-box/chat-box.ts +++ b/src/ts/components/shared/chat-box/chat-box.ts @@ -9,10 +9,11 @@ import { faComment, faAngleDoubleRight } from '../../../client/icons'; import { isInParty } from '../../../client/partyUtils'; import { handleActionCommand } from '../../../client/playerActions'; import { hasHeadAnimation } from '../../../common/pony'; -import { AutocompleteState, autocompleteMesssage, replaceEmojis } from '../../../client/emoji'; +import { AutocompleteState, autocompleteMesssage, replaceEmojis, emojis } from '../../../client/emoji'; import { replaceNodes } from '../../../client/htmlUtils'; import { invalidEnumReturn } from '../../../common/utils'; import { findMatchingEntityNames, findEntityOrMockByAnyMeans, findBestEntityByName } from '../../../client/handlers'; +import * as _ from 'lodash'; const chatTypeNames: string[] = []; const chatTypeClasses: string[] = []; @@ -33,7 +34,7 @@ setupChatType(ChatType.Think, 'think'); setupChatType(ChatType.PartyThink, 'party think'); function isActionCommand(message: string) { - return /^\/(yawn|sneeze|achoo|laugh|lol|haha|хаха|jaja)/i.test(message); + return /^\/(yawn|sneeze|excite|tada|wink|achoo|laugh|lol|haha|хаха|jaja|hug)/i.test(message); } @Component({ @@ -45,6 +46,8 @@ export class ChatBox implements AfterViewInit, OnDestroy { readonly maxSayLength = SAY_MAX_LENGTH; readonly commentIcon = faComment; readonly sendIcon = faAngleDoubleRight; + readonly emotes = emojis; + emojiBoxState = 'none'; @ViewChild('inputElement', { static: true }) inputElement!: ElementRef; @ViewChild('typeBox', { static: true }) typeBox!: ElementRef; @ViewChild('typePrefix', { static: true }) typePrefix!: ElementRef; @@ -54,12 +57,14 @@ export class ChatBox implements AfterViewInit, OnDestroy { isOpen = false; message: string | undefined = ''; chatType = ChatType.Say; + btnEmoji = emojis[0].names[0]; private pasted = false; private lastMessages: string[] = []; private state: AutocompleteState = {}; private subscriptions: Subscription[]; private _disabled = false; constructor(private game: PonyTownGame, zone: NgZone) { + this.subscriptions = [ this.game.onChat.subscribe(() => zone.run(() => this.chat(undefined))), this.game.onToggleChat.subscribe(() => zone.run(() => this.toggle())), @@ -92,6 +97,18 @@ export class ChatBox implements AfterViewInit, OnDestroy { ngOnDestroy() { this.subscriptions.forEach(s => s.unsubscribe()); } + addEmoji(emoji: string) { + this.toggleEmojiBox(); + if (!this.message) this.message = emoji; + else if (this.input.maxLength > this.message.length) { + this.message += emoji; + } + } + toggleEmojiBox() { + if (this.emojiBoxState === 'none') + this.emojiBoxState = 'inline-block'; + else this.emojiBoxState = 'none'; + } send(_event: Event | undefined) { let chatType = this.chatType; let message = replaceEmojis(cleanMessage(this.message || '')).substr(0, SAY_MAX_LENGTH); @@ -136,7 +153,6 @@ export class ChatBox implements AfterViewInit, OnDestroy { this.lastMessages.shift(); } } - this.close(); } } @@ -259,6 +275,7 @@ export class ChatBox implements AfterViewInit, OnDestroy { } private close() { if (this.isOpen) { + this.emojiBoxState = 'none'; this.input.blur(); this.isOpen = false; this.chatBox.nativeElement.hidden = true; @@ -273,6 +290,11 @@ export class ChatBox implements AfterViewInit, OnDestroy { this.open(); } } + onMouseEnter(event: MouseEvent) { + if (!event.target) return; + const emoji = _.sample(emojis) || emojis[0]; + this.btnEmoji = emoji.names[0]; + } toggleChatType() { const chatTypes = getChatTypes(this.game); this.chatType = chatTypes[(chatTypes.indexOf(this.chatType) + 1) % chatTypes.length]; diff --git a/src/ts/components/shared/chat-log/chat-log.pug b/src/ts/components/shared/chat-log/chat-log.pug index 3bc0af1..6a3b75a 100644 --- a/src/ts/components/shared/chat-log/chat-log.pug +++ b/src/ts/components/shared/chat-log/chat-log.pug @@ -13,6 +13,7 @@ | Party a.link-plain.chat-log-tab(#whisperTab tabindex (click)="switchTab('whisper')") | Whisper + input.link-plain.chat-log-tab.chat-log-filter(#filterTab type="text" [style.background-color]="filterColor" (keyup.enter)="(unFocus())" (keyup.esc)="(unFocus())" [placeholder]="'Filter'" (keyup)="filterChat()") .chat-log-scroll-outer() .chat-log-scroll-inner(#scroll) .chat-log-scroll-inner-inner(#lines) @@ -25,3 +26,4 @@ button.game-button.chat-log-toggle(#toggleButton (click)="toggle()" title="Toggl path.main-bubble(fill="currentColor" d="M416 192c0-88.4-93.1-160-208-160S0 103.6 0 192c0 34.3 14.1 65.9 38 92-13.4 30.2-35.5 54.2-35.8 54.5-2.2 2.3-2.8 5.7-1.5 8.7S4.8 352 8 352c36.6 0 66.9-12.3 88.7-25 32.2 15.7 70.3 25 111.3 25 114.9 0 208-71.6 208-160z") path(fill="currentColor" d="M538 412c23.9-26 38-57.7 38-92 0-66.9-53.5-124.2-129.3-148.1.9 6.6 1.3 13.3 1.3 20.1 0 105.9-107.7 192-240 192-10.8 0-21.3-.8-31.7-1.9C207.8 439.6 281.8 480 368 480c41 0 79.1-9.2 111.3-25 21.8 12.7 52.1 25 88.7 25 3.2 0 6.1-1.9 7.3-4.8 1.3-2.9.7-6.3-1.5-8.7-.3-.3-22.4-24.2-35.8-54.5z") .whispers-count(#count) + \ No newline at end of file diff --git a/src/ts/components/shared/chat-log/chat-log.scss b/src/ts/components/shared/chat-log/chat-log.scss index 62796ae..d6e6195 100644 --- a/src/ts/components/shared/chat-log/chat-log.scss +++ b/src/ts/components/shared/chat-log/chat-log.scss @@ -1,159 +1,198 @@ @import '../../../../styles/partials/variables'; - $chat-log-bg: rgba(0, 0, 0, 0.2); $chat-log-bg-faded: rgba(0, 0, 0, 0.1); $chat-log-bg-hover: rgba(0, 0, 0, 0.5); $chat-log-tabs-height: 30px; $chat-log-buttons-width: 40px; - $resizer-size: 12px; $resizer-offset: $resizer-size / 2; - .chat-log { - display: flex; - position: absolute; - bottom: 0; - left: 0; - right: 0; - min-width: 200px; - max-width: 100%; - max-height: calc(100vh - 220px); - min-height: 120px; + display: flex; + position: absolute; + bottom: 0; + left: 0; + right: 0; + min-width: 200px; + max-width: 100%; + max-height: calc(100vh - 220px); + min-height: 120px; } .chat-log-buttons { - flex-direction: column-reverse; - width: $chat-log-buttons-width; - padding: 5px 3px; - padding-bottom: 30px; - z-index: 2; + flex-direction: column-reverse; + width: $chat-log-buttons-width; + padding: 5px 3px; + padding-bottom: 30px; + z-index: 2; } .chat-log-toggle { - position: absolute; - bottom: 5px; - left: 4px; - z-index: 3; + position: absolute; + bottom: 5px; + left: 4px; + z-index: 3; } .has-unread .main-bubble { - color: $chat-whisper; + color: $chat-whisper; } .whispers-count { - color: white; - font-weight: bold; - text-align: center; - position: absolute; - left: 6px; - top: 9px; - width: 16px; - font-size: 10px; - display: flex; - justify-content: center; - align-items: center; - line-height: 1rem; + color: white; + font-weight: bold; + text-align: center; + position: absolute; + left: 6px; + top: 9px; + width: 16px; + font-size: 10px; + display: flex; + justify-content: center; + align-items: center; + line-height: 1rem; } .whisper-icon { - position: absolute; - top: 0; - left: 0; - font-size: 14px; - color: $chat-whisper !important; + position: absolute; + top: 0; + left: 0; + font-size: 14px; + color: $chat-whisper !important; } .chat-log-content { - position: relative; - display: flex; - background: $chat-log-bg; - padding: 5px 0; - padding-left: 40px; - margin-left: -$chat-log-buttons-width; - border-radius: $border-radius-base; - word-break: break-word; - white-space: pre-line; - line-height: 20px; - height: 100%; - width: 100%; + position: relative; + display: flex; + background: $chat-log-bg; + padding: 5px 0; + padding-left: 40px; + margin-left: -$chat-log-buttons-width; + border-radius: $border-radius-base; + word-break: break-word; + white-space: pre-line; + line-height: 20px; + height: 100%; + width: 100%; } .chat-log-tabs { - position: absolute; - top: -$chat-log-tabs-height; - left: 30px; - display: flex; - user-select: none; + position: absolute; + top: -$chat-log-tabs-height; + left: 30px; + display: flex; + user-select: none; + text-shadow: 0px 0px 4px #000000; } .chat-log-tab { - background: $chat-log-bg-faded; - padding: 5px 10px 0; - margin-left: 10px; - height: $chat-log-tabs-height; - border-top-left-radius: $border-radius-base; - border-top-right-radius: $border-radius-base; - color: white; - overflow: hidden; - - &.active { - background: $chat-log-bg; - } + background: $chat-log-bg-faded; + padding: 5px 10px 0; + margin-left: 10px; + height: $chat-log-tabs-height; + border-top-left-radius: $border-radius-base; + border-top-right-radius: $border-radius-base; + color: white; + overflow: hidden; + &.active { + background: $chat-log-bg; + } } .chat-log-scroll-outer { - overflow: hidden; - width: 100%; + overflow: hidden; + width: 100%; } .chat-log-scroll-inner { - width: calc(100% + 50px); - height: 100%; - overflow-x: hidden; - overflow-y: scroll; - -webkit-overflow-scrolling: touch; + width: calc(100% + 50px); + height: 100%; + overflow-x: hidden; + overflow-y: scroll; + -webkit-overflow-scrolling: touch; } .chat-log-scroll-inner-inner { - display: flex; - flex-direction: column; - justify-content: flex-end; - min-height: 100%; - padding: 0 5px; + display: flex; + flex-direction: column; + justify-content: flex-end; + min-height: 100%; + padding: 0 5px; } .chat-log-resize-top { - position: absolute; - top: -$resizer-offset; - right: $resizer-offset; - height: $resizer-size; - left: 250px; - cursor: ns-resize; + position: absolute; + top: -$resizer-offset; + right: $resizer-offset; + height: $resizer-size; + left: 250px; + cursor: ns-resize; } .chat-log-resize-top-right { - position: absolute; - top: -($resizer-offset + 1); - right: -($resizer-offset + 1); - width: $resizer-size + 4; - height: $resizer-size + 4; - cursor: nesw-resize; + position: absolute; + top: -($resizer-offset + 1); + right: -($resizer-offset + 1); + width: $resizer-size + 4; + height: $resizer-size + 4; + cursor: nesw-resize; } .chat-log-resize-right { - position: absolute; - top: $resizer-offset; - right: -$resizer-offset; - width: $resizer-size; - bottom: $resizer-offset; - cursor: ew-resize; + position: absolute; + top: $resizer-offset; + right: -$resizer-offset; + width: $resizer-size; + bottom: $resizer-offset; + cursor: ew-resize; } .resize-icon { - font-size: 18px; - position: absolute; - top: -3px; - right: 1px; - transform: rotate(45deg); - color: rgba(255, 255, 255, 0.2); + font-size: 18px; + position: absolute; + top: -3px; + right: 1px; + transform: rotate(45deg); + color: rgba(255, 255, 255, 0.2); } + +.chat-log-filter { + padding-bottom: 5px; + border: none; + width: 100px; +} + +.chat-log-filter::-webkit-input-placeholder { + opacity: 1; + color: white; + text-shadow: 0px 0px 4px #000000; +} + +.chat-log-filter:-moz-placeholder { + /* Firefox 18- */ + opacity: 1; + color: white; + text-shadow: 0px 0px 4px #000000; +} + +.chat-log-filter::-moz-placeholder { + /* Firefox 19+ */ + opacity: 1; + color: white; + text-shadow: 0px 0px 4px #000000; +} + +.chat-log-filter:-ms-input-placeholder { + opacity: 1; + color: white; + text-shadow: 0px 0px 4px #000000; +} + +@media only screen and (max-width: 360px) { + .chat-log-filter { + position: absolute; + left: 0; + bottom: 35px; + width: 100%; + border-radius: 2px; + } +} \ No newline at end of file diff --git a/src/ts/components/shared/chat-log/chat-log.ts b/src/ts/components/shared/chat-log/chat-log.ts index 9367fb3..c60175a 100644 --- a/src/ts/components/shared/chat-log/chat-log.ts +++ b/src/ts/components/shared/chat-log/chat-log.ts @@ -12,6 +12,8 @@ import { DEFAULT_CHATLOG_OPACITY, PONY_TYPE, SECOND } from '../../../common/cons import { faCaretUp, faArrowDown } from '../../../client/icons'; import { sampleMessages } from '../../../common/debugData'; import { findEntityById } from '../../../common/worldMap'; +import { colorToRGBA, rgb2hsl, HSL, hsl2CSS } from '../../../common/color'; +import * as moment from 'moment'; interface IndexEntryUser { id: number; @@ -103,11 +105,9 @@ export function createChatLogLineDOM(clickLabel: ClickHandler, clickName: ClickH line.root = element('div', 'chat-line', [ element('span', 'chat-line-lead'), line.time = element('span', 'chat-line-name', [ - textNode(`[`), line.timeContent = element( 'span', 'chat-line-time-content', [textNode('')], undefined), line.index = element('span', 'chat-line-time-index', [line.indexText = textNode('')]), - textNode('] '), ]), line.label = element( 'span', 'chat-line-label mr-1', [line.labelText = textNode('')], undefined, { click: () => clickLabel(line.entry) }), @@ -127,7 +127,7 @@ export function createChatLogLineDOM(clickLabel: ClickHandler, clickName: ClickH return line; } -export function updateChatLogLine(line: ChatLogLineDOM, entry: ChatLogMessage) { +export function updateChatLogLine(line: ChatLogLineDOM, entry: ChatLogMessage, hourMode?: '12' | '24') { const { classes, label, message, prefix, suffix } = entry; const hasSpace = message.indexOf(' ') !== -1; @@ -137,27 +137,23 @@ export function updateChatLogLine(line: ChatLogLineDOM, entry: ChatLogMessage) { line.labelText.nodeValue = label ? `[${label}]` : ''; updateChatLogName(line, entry); - updateTime(line); + updateTime(line, hourMode); line.prefixText.nodeValue = prefix || ''; line.suffixText.nodeValue = suffix ? ` ${suffix}: ` : ': '; replaceNodes(line.message, message); } -function updateTime(line: ChatLogLineDOM) { +function updateTime(line: ChatLogLineDOM, hourMode?: '12' | '24') { line.time.style.display = 'inline'; - replaceNodes(line.timeContent, getCurrentTime()); + if (!hourMode) return; + if (hourMode === '24') + replaceNodes(line.timeContent, `[${moment().format('HH:mm:ss')}] `); + if (hourMode === '12') + replaceNodes(line.timeContent, `[${moment().format('LTS')}] `); } -function getCurrentTime() { - const date = new Date(); - const hours = date.getHours().toString(); - const minutes = date.getMinutes().toString(); - const seconds = date.getSeconds().toString(); - return `${hours.length === 1 ? `0${hours}` : hours}:${minutes.length === 1 ? `0${minutes}` : minutes}:${seconds.length === 1 ? `0${seconds}` : seconds}`; -} - -function setNameColors(line: ChatLogLineDOM | undefined, colors?: string[] | null) { +function setNameColors(line: ChatLogLineDOM | undefined, colors?: string[]) { if (!colors || !line) return; if (colors[1]) line.name.style.color = colors[1]; if (colors[0]) line.nameContent.style.color = colors[0]; @@ -232,6 +228,7 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { local: ChatLogMessage[] = []; party: ChatLogMessage[] = []; whisper: ChatLogMessage[] = []; + filterColor = this.inactiveBg; unread = 0; private subscriptions: Subscription[] = []; private startX = 0; @@ -243,9 +240,8 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { private indexes = new Map(); private messageCounter = 0; private lastOpacity = 0; - private autoClear: null | NodeJS.Timeout = null; - private autoUnfocus: null | NodeJS.Timeout = null; - filterColor = this.inactiveBg; + private autoClear?: NodeJS.Timeout; + private autoUnfocus?: NodeJS.Timeout; constructor( private game: PonyTownGame, private settingsService: SettingsService, @@ -460,7 +456,7 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { if (!value) { this.clearTimeOutAutoClear(); this.unFocus(); - this.showHideChatLogLines('', false); + this.filterChatLogLines('', false); return; } else this.filterColor = this.bg; @@ -482,9 +478,10 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { value = value.slice(1); try { const regExp = new RegExp(value); - this.showHideChatLogLines(regExp, toLowerCase); + this.filterChatLogLines(regExp, toLowerCase); this.filterTab.nativeElement.style.color = ''; - } catch (err) { + } catch (err) {// If the user inputs invalid regExp we just notify him by changing text color to red + if (DEVELOPMENT) console.error(err); this.filterTab.nativeElement.style.color = '#ff6666'; } return; @@ -493,10 +490,10 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { value = value.toLowerCase(); toLowerCase = true; } - this.showHideChatLogLines(value, toLowerCase); + this.filterChatLogLines(value, toLowerCase); } - showHideChatLogLines(content: string | RegExp, caseSensitive: boolean) { + filterChatLogLines(content: string | RegExp, caseSensitive: boolean) { const lines = this.linesElement.getElementsByTagName('div'); for (let i = 0; i < lines.length; i++) { @@ -507,11 +504,12 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { if (typeof content === 'string') { if (caseSensitive) - textContent.toLowerCase().includes(content) ? lines[i].hidden = false : lines[i].hidden = true; + lines[i].hidden = !textContent.toLowerCase().includes(content); else - textContent.includes(content) ? lines[i].hidden = false : lines[i].hidden = true; + lines[i].hidden = !textContent.includes(content); + } else { - textContent.match(content) ? lines[i].hidden = false : lines[i].hidden = true; + lines[i].hidden = !textContent.match(content); } } } @@ -523,79 +521,45 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { lines[i].hidden = false; } } - private getRGB(hex: string) { - const bigint = parseInt(hex, 16); - const r = (bigint >> 16) & 255; - const g = (bigint >> 8) & 255; - const b = bigint & 255; - return [r, g, b]; - } - private RGBToHSL(rgb: number[]) { - let r = rgb[0] / 255; - let g = rgb[1] / 255; - let b = rgb[2] / 255; - let max = Math.max(r, g, b); - let min = Math.min(r, g, b); - let delta = max - min; - let h = 0; - let s; - let l; - - if (max === min) h = 0; - else if (r === max) h = (g - b) / delta; - else if (g === max) h = 2 + (b - r) / delta; - else if (b === max) h = 4 + (r - g) / delta; - - h = Math.min(h * 60, 360); - - if (h < 0) h += 360; - - l = (min + max) / 2; - - if (max === min) s = 0; - else if (l <= 0.5) s = delta / (max + min); - else s = delta / (2 - max - min); - h = Math.floor(h); - s = Math.floor(s * 100); - l = Math.floor(l * 100); - - if (l < 40) { - if (l > 20 && l < 40) { - l += 20; - if (s > 11) s -= 11; + brightenDarkColors(hsl: HSL) { + if (hsl.l < 40) { + if (hsl.l > 20 && hsl.l < 40) { + hsl.l += 20; + if (hsl.s > 11) hsl.s -= 11; } else { - l = 40; - if (s > 11) s = 0; + hsl.l = 40; + if (hsl.s > 11) hsl.s = 0; } } - - return `hsl(${h}, ${s}%, ${l}%)`; + return hsl; } + fixColor(color: string) { while (color.length <= 7) { color = `0${color}`; } - color = color.replace(/0/g, '1'); return color.substr(0, 6); } - private getCharaterColors(id: number | undefined) { - if (!id) return null; + + private getCharacterColors(id: number | undefined) { + if (!id) return; const entity = findEntityById(this.game.map, id) as Pony; - if (!entity || !entity.palettePonyInfo) return null; + if (!entity || !entity.palettePonyInfo) return; let colors = []; - let body = entity.palettePonyInfo.body; - let mane = entity.palettePonyInfo.mane; + let { body, mane } = entity.palettePonyInfo; if (body && body.palette && body.palette.colors[1]) { - let bodyColor = this.fixColor(body.palette.colors[1].toString(16)); - const RGB = this.getRGB(bodyColor); - colors.push(this.RGBToHSL(RGB)); + const rgb = colorToRGBA(body.palette.colors[1]); + const hsl = rgb2hsl(rgb); + this.brightenDarkColors(hsl); + colors.push(hsl2CSS(hsl)); } if (mane && mane.palette && mane.palette.colors[1]) { - let maneColor = this.fixColor(mane.palette.colors[1].toString(16)); - const RGB = this.getRGB(maneColor); - colors.push(this.RGBToHSL(RGB)); + const rgb = colorToRGBA(mane.palette.colors[1]); + const hsl = rgb2hsl(rgb); + this.brightenDarkColors(hsl); + colors.push(hsl2CSS(hsl)); } else if (colors && colors[0]) { colors.push((colors[0])); } @@ -604,12 +568,12 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { } clearTimeOutAutoClear() { if (this.autoClear) clearTimeout(this.autoClear); - this.autoClear = null; + this.autoClear = undefined; this.filterColor = this.inactiveBg; } clearTimeOutAutoUnfocus() { if (this.autoUnfocus) clearTimeout(this.autoUnfocus); - this.autoUnfocus = null; + this.autoUnfocus = undefined; } unFocus() { this.clearTimeOutAutoUnfocus(); @@ -624,9 +588,7 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { const open = this.open; const scrolledToEnd = open ? this.scrolledToEnd : false; const tab = this.activeTab; - let colors: string[] | null = null; - colors = this.getCharaterColors(message.id); - + const colors = this.getCharacterColors(message.id); this.addEntryToList(this.local, GENERAL_CHAT_LIMIT, open && tab === 'local', entry); setNameColors(entry.dom, colors); @@ -686,7 +648,7 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { if (isOpen) { entry.dom = removedDom || createChatLogLineDOM(this.clickLabel, this.clickNameHandler); - updateChatLogLine(entry.dom, entry); + updateChatLogLine(entry.dom, entry, this.settings.timestamp); this.linesElement.appendChild(entry.dom.root); } } @@ -702,6 +664,7 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { this.regenerateList(); this.scrollToEnd(); this.updateTabs(); + this.filterChat(); } } private updateTabs() { @@ -749,8 +712,8 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { this.messages.forEach(entry => { if (!entry.dom) { entry.dom = createChatLogLineDOM(this.clickLabel, this.clickNameHandler); - setNameColors(entry.dom, this.getCharaterColors(entry.entityId)); - updateChatLogLine(entry.dom, entry); + setNameColors(entry.dom, this.getCharacterColors(entry.entityId)); + updateChatLogLine(entry.dom, entry, this.settings.timestamp); } lines.appendChild(entry.dom.root); @@ -767,7 +730,8 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { } if (resizeX) { - this.settings.chatlogWidth = clamp(x - this.startX, 200 + 74.7, 2000); + const filterBoxWidth = 80; + this.settings.chatlogWidth = clamp(x - this.startX, 200 + filterBoxWidth, 2000); } if (resizeY) { diff --git a/src/ts/components/shared/settings-modal/settings-modal.pug b/src/ts/components/shared/settings-modal/settings-modal.pug index db4c1b1..6633b88 100644 --- a/src/ts/components/shared/settings-modal/settings-modal.pug +++ b/src/ts/components/shared/settings-modal/settings-modal.pug @@ -71,6 +71,17 @@ [(checked)]="account.ignoreNonFriendWhispers" help="Don't show any whispers from players who are not on your friends list") | Only allow whispers from friends + .form-group + .form-group + label#chatlog-opacity-label Message timestamp + div + .btn-group.ml-2(btnCheckbox) + button.btn.btn-outline-secondary.d-none.d-sm-block([class.active]='off' (click)='switchTimestamp()') Off + button.btn.btn-outline-secondary.d-none.d-sm-block([class.active]='twelve' (click)='switchTimestamp("12")') 12 + button.btn.btn-outline-secondary.d-none.d-sm-block([class.active]='twentyFour' (click)='switchTimestamp("24")') 24 + span.ml-2 {{timestampText}} + //small.form-text.text-muted.mt-0 Shows message time + .form-group label#chatlog-opacity-label Chatlog background opacity div @@ -78,7 +89,6 @@ [(value)]="account.chatlogOpacity" style="max-width: 300px" labelledBy="chatlog-opacity-label") | {{(account.chatlogOpacity / 100) | percent}} small.form-text.text-muted.mt-0 Changes chatlog background to make it more readable or less obtrusive. - .form-group label#chatlog-range-label Chatlog range div slider-bar.mr-2( diff --git a/src/ts/components/shared/settings-modal/settings-modal.ts b/src/ts/components/shared/settings-modal/settings-modal.ts index fe5a292..e4bcb84 100644 --- a/src/ts/components/shared/settings-modal/settings-modal.ts +++ b/src/ts/components/shared/settings-modal/settings-modal.ts @@ -26,6 +26,10 @@ export class SettingsModal implements OnInit, OnDestroy { readonly graphicsIcon = faImage; readonly exportIcon = faDownload; readonly importIcon = faUpload; + off = false; + twelve = false; + twentyFour = false; + timestampText: 'Disabled' | '24 Hour mode' | '12 Hour mode' = 'Disabled'; @Output() close = new EventEmitter(); account: AccountSettings = {}; browser: BrowserSettings = {}; @@ -59,6 +63,7 @@ export class SettingsModal implements OnInit, OnDestroy { this.browser = this.settingsService.browser; this.setupDefaults(); this.subscription = this.game.onLeft.subscribe(() => this.cancel()); + this.updateTimestampRadios(); } ngOnDestroy() { this.finishChatlogRange(); @@ -100,6 +105,37 @@ export class SettingsModal implements OnInit, OnDestroy { this.settingsService.saveBrowserSettings(this.browser); this.close.emit(); } + switchTimestamp(state?: string) { + if (!state) this.browser.timestamp = undefined; + else if (state === '12') this.browser.timestamp = '12'; + else if (state === '24') this.browser.timestamp = '24'; + this.updateTimestampRadios(); + } + turnOffTimestampRadioButtons() { + this.off = false; + this.twelve = false; + this.twentyFour = false; + } + + updateTimestampRadios() { + this.turnOffTimestampRadioButtons(); + switch (this.browser.timestamp) { + case '12': + this.twelve = true; + this.timestampText = '12 Hour mode'; + break; + case '24': + this.twentyFour = true; + this.timestampText = '24 Hour mode'; + break; + default: + this.off = true; + this.timestampText = 'Disabled'; + break; + } + } + + updateChatlogRange(range: number | undefined) { document.body.classList.add('translucent-modals'); updateRangeIndicator(range, this.game); From 0f4d2c36f75a83b0a2637eb59e3ef26537789a83 Mon Sep 17 00:00:00 2001 From: Terncode Date: Sun, 8 Sep 2019 19:08:01 +0200 Subject: [PATCH 06/17] fixed css for input --- src/ts/components/shared/chat-box/chat-box.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ts/components/shared/chat-box/chat-box.scss b/src/ts/components/shared/chat-box/chat-box.scss index dd74296..d08ac38 100644 --- a/src/ts/components/shared/chat-box/chat-box.scss +++ b/src/ts/components/shared/chat-box/chat-box.scss @@ -33,7 +33,7 @@ z-index: 1; padding: 8px; font-size: 14px; - padding-right: 35px; + padding-right: 65px; padding-left: 90px; border-radius: $border-radius-base; outline: none; From 4eeaf3994c04687e9fa5c318c6ba9ed0346d8b5f Mon Sep 17 00:00:00 2001 From: Stubenhocker1399 Date: Sun, 8 Sep 2019 20:44:52 +0200 Subject: [PATCH 07/17] Fix timestamp setting not appearing on mobile --- .../shared/settings-modal/settings-modal.pug | 13 ++++++------- .../shared/settings-modal/settings-modal.ts | 4 ---- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/ts/components/shared/settings-modal/settings-modal.pug b/src/ts/components/shared/settings-modal/settings-modal.pug index 6633b88..853c495 100644 --- a/src/ts/components/shared/settings-modal/settings-modal.pug +++ b/src/ts/components/shared/settings-modal/settings-modal.pug @@ -73,14 +73,13 @@ | Only allow whispers from friends .form-group .form-group - label#chatlog-opacity-label Message timestamp + label#chatlog-opacity-label Timestamp div - .btn-group.ml-2(btnCheckbox) - button.btn.btn-outline-secondary.d-none.d-sm-block([class.active]='off' (click)='switchTimestamp()') Off - button.btn.btn-outline-secondary.d-none.d-sm-block([class.active]='twelve' (click)='switchTimestamp("12")') 12 - button.btn.btn-outline-secondary.d-none.d-sm-block([class.active]='twentyFour' (click)='switchTimestamp("24")') 24 - span.ml-2 {{timestampText}} - //small.form-text.text-muted.mt-0 Shows message time + .btn-group.mb-2(btnCheckbox) + button.btn.btn-outline-secondary.d-sm-block([class.active]='off' (click)='switchTimestamp()') None + button.btn.btn-outline-secondary.d-sm-block([class.active]='twelve' (click)='switchTimestamp("12")') 12-hour format + button.btn.btn-outline-secondary.d-sm-block([class.active]='twentyFour' (click)='switchTimestamp("24")') 24-hour format + small.form-text.text-muted.mt-0 Displays a timestamp in front of chatlog messages .form-group label#chatlog-opacity-label Chatlog background opacity diff --git a/src/ts/components/shared/settings-modal/settings-modal.ts b/src/ts/components/shared/settings-modal/settings-modal.ts index 222e8ca..99e79a3 100644 --- a/src/ts/components/shared/settings-modal/settings-modal.ts +++ b/src/ts/components/shared/settings-modal/settings-modal.ts @@ -29,7 +29,6 @@ export class SettingsModal implements OnInit, OnDestroy { off = false; twelve = false; twentyFour = false; - timestampText: 'Disabled' | '24 Hour mode' | '12 Hour mode' = 'Disabled'; @Output() close = new EventEmitter(); account: AccountSettings = {}; browser: BrowserSettings = {}; @@ -121,15 +120,12 @@ export class SettingsModal implements OnInit, OnDestroy { switch (this.browser.timestamp) { case '12': this.twelve = true; - this.timestampText = '12 Hour mode'; break; case '24': this.twentyFour = true; - this.timestampText = '24 Hour mode'; break; default: this.off = true; - this.timestampText = 'Disabled'; break; } } From 299619bb7995a553de57be6d3aba5524d4647035 Mon Sep 17 00:00:00 2001 From: Stubenhocker1399 Date: Sun, 8 Sep 2019 20:50:39 +0200 Subject: [PATCH 08/17] Cleanup diff --- src/ts/components/shared/chat-box/chat-box.scss | 13 +++++++------ src/ts/components/shared/chat-log/chat-log.ts | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/ts/components/shared/chat-box/chat-box.scss b/src/ts/components/shared/chat-box/chat-box.scss index 96e0e9a..1ac7665 100644 --- a/src/ts/components/shared/chat-box/chat-box.scss +++ b/src/ts/components/shared/chat-box/chat-box.scss @@ -1,4 +1,5 @@ @import '../../../../styles/partials/variables'; + .chat-box { max-width: 500px; height: 37px; @@ -51,27 +52,27 @@ .chat-party > &, .chat-party-think > & { color: $chat-party; } - + .chat-say > &, .chat-think > & { color: $chat-color; } - + .chat-sup > & { color: $supporter-1; } - + .chat-sup1 > & { color: $supporter-1; } - + .chat-sup2 > & { color: $supporter-2; } - + .chat-sup3 > & { color: $supporter-3; } - + .chat-whisper > & { color: $chat-whisper; } diff --git a/src/ts/components/shared/chat-log/chat-log.ts b/src/ts/components/shared/chat-log/chat-log.ts index d3d11d7..6739f47 100644 --- a/src/ts/components/shared/chat-log/chat-log.ts +++ b/src/ts/components/shared/chat-log/chat-log.ts @@ -112,7 +112,7 @@ export function createChatLogLineDOM(clickLabel: ClickHandler, clickName: ClickH 'span', 'chat-line-label mr-1', [line.labelText = textNode('')], undefined, { click: () => clickLabel(line.entry) }), line.prefixText = textNode(''), line.name = element('span', 'chat-line-name', [ - textNode(`[`), + textNode('['), line.nameContent = element( 'span', 'chat-line-name-content', [textNode('')], undefined, { click: () => clickName(line.entry) }), line.index = element('span', 'chat-line-name-index', [line.indexText = textNode('')], { title: 'duplicate name' }), From e212d5e7c4bfb66753c836e4a5d73cfff6f54790 Mon Sep 17 00:00:00 2001 From: Terncode Date: Tue, 10 Sep 2019 12:28:09 +0200 Subject: [PATCH 09/17] Improved code --- src/ts/components/shared/chat-box/chat-box.ts | 4 +-- .../components/shared/chat-log/chat-log.pug | 1 - .../shared/settings-modal/settings-modal.pug | 6 ++--- .../shared/settings-modal/settings-modal.ts | 25 +------------------ 4 files changed, 6 insertions(+), 30 deletions(-) diff --git a/src/ts/components/shared/chat-box/chat-box.ts b/src/ts/components/shared/chat-box/chat-box.ts index df7b8eb..878920a 100644 --- a/src/ts/components/shared/chat-box/chat-box.ts +++ b/src/ts/components/shared/chat-box/chat-box.ts @@ -290,9 +290,9 @@ export class ChatBox implements AfterViewInit, OnDestroy { this.open(); } } - onMouseEnter(event: MouseEvent) { + onMouseEnterEmojiButton(event: MouseEvent) { if (!event.target) return; - const emoji = _.sample(emojis) || emojis[0]; + const emoji = _.sample(emojis)!; this.btnEmoji = emoji.names[0]; } toggleChatType() { diff --git a/src/ts/components/shared/chat-log/chat-log.pug b/src/ts/components/shared/chat-log/chat-log.pug index 6a3b75a..2d1aa0e 100644 --- a/src/ts/components/shared/chat-log/chat-log.pug +++ b/src/ts/components/shared/chat-log/chat-log.pug @@ -26,4 +26,3 @@ button.game-button.chat-log-toggle(#toggleButton (click)="toggle()" title="Toggl path.main-bubble(fill="currentColor" d="M416 192c0-88.4-93.1-160-208-160S0 103.6 0 192c0 34.3 14.1 65.9 38 92-13.4 30.2-35.5 54.2-35.8 54.5-2.2 2.3-2.8 5.7-1.5 8.7S4.8 352 8 352c36.6 0 66.9-12.3 88.7-25 32.2 15.7 70.3 25 111.3 25 114.9 0 208-71.6 208-160z") path(fill="currentColor" d="M538 412c23.9-26 38-57.7 38-92 0-66.9-53.5-124.2-129.3-148.1.9 6.6 1.3 13.3 1.3 20.1 0 105.9-107.7 192-240 192-10.8 0-21.3-.8-31.7-1.9C207.8 439.6 281.8 480 368 480c41 0 79.1-9.2 111.3-25 21.8 12.7 52.1 25 88.7 25 3.2 0 6.1-1.9 7.3-4.8 1.3-2.9.7-6.3-1.5-8.7-.3-.3-22.4-24.2-35.8-54.5z") .whispers-count(#count) - \ No newline at end of file diff --git a/src/ts/components/shared/settings-modal/settings-modal.pug b/src/ts/components/shared/settings-modal/settings-modal.pug index 853c495..7dcf473 100644 --- a/src/ts/components/shared/settings-modal/settings-modal.pug +++ b/src/ts/components/shared/settings-modal/settings-modal.pug @@ -76,9 +76,9 @@ label#chatlog-opacity-label Timestamp div .btn-group.mb-2(btnCheckbox) - button.btn.btn-outline-secondary.d-sm-block([class.active]='off' (click)='switchTimestamp()') None - button.btn.btn-outline-secondary.d-sm-block([class.active]='twelve' (click)='switchTimestamp("12")') 12-hour format - button.btn.btn-outline-secondary.d-sm-block([class.active]='twentyFour' (click)='switchTimestamp("24")') 24-hour format + button.btn.btn-outline-secondary.d-sm-block([class.active]='!browser.timestamp' (click)='switchTimestamp()') None + button.btn.btn-outline-secondary.d-sm-block([class.active]='browser.timestamp === "12"' (click)='switchTimestamp("12")') 12-hour format + button.btn.btn-outline-secondary.d-sm-block([class.active]='browser.timestamp === "24"' (click)='switchTimestamp("24")') 24-hour format small.form-text.text-muted.mt-0 Displays a timestamp in front of chatlog messages .form-group diff --git a/src/ts/components/shared/settings-modal/settings-modal.ts b/src/ts/components/shared/settings-modal/settings-modal.ts index 99e79a3..41ee245 100644 --- a/src/ts/components/shared/settings-modal/settings-modal.ts +++ b/src/ts/components/shared/settings-modal/settings-modal.ts @@ -26,9 +26,7 @@ export class SettingsModal implements OnInit, OnDestroy { readonly graphicsIcon = faImage; readonly exportIcon = faDownload; readonly importIcon = faUpload; - off = false; - twelve = false; - twentyFour = false; + @Output() close = new EventEmitter(); account: AccountSettings = {}; browser: BrowserSettings = {}; @@ -62,7 +60,6 @@ export class SettingsModal implements OnInit, OnDestroy { this.browser = this.settingsService.browser; this.setupDefaults(); this.subscription = this.game.onLeft.subscribe(() => this.cancel()); - this.updateTimestampRadios(); } ngOnDestroy() { this.finishChatlogRange(); @@ -108,26 +105,6 @@ export class SettingsModal implements OnInit, OnDestroy { if (!state) this.browser.timestamp = undefined; else if (state === '12') this.browser.timestamp = '12'; else if (state === '24') this.browser.timestamp = '24'; - this.updateTimestampRadios(); - } - turnOffTimestampRadioButtons() { - this.off = false; - this.twelve = false; - this.twentyFour = false; - } - updateTimestampRadios() { - this.turnOffTimestampRadioButtons(); - switch (this.browser.timestamp) { - case '12': - this.twelve = true; - break; - case '24': - this.twentyFour = true; - break; - default: - this.off = true; - break; - } } updateChatlogRange(range: number | undefined) { document.body.classList.add('translucent-modals'); From cd27246069b3401de2e85a2f6f4008b8e4dd6a5a Mon Sep 17 00:00:00 2001 From: Stubenhocker1399 Date: Tue, 10 Sep 2019 15:08:12 +0200 Subject: [PATCH 10/17] Remove new line --- src/ts/components/shared/settings-modal/settings-modal.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ts/components/shared/settings-modal/settings-modal.ts b/src/ts/components/shared/settings-modal/settings-modal.ts index 41ee245..57cadd4 100644 --- a/src/ts/components/shared/settings-modal/settings-modal.ts +++ b/src/ts/components/shared/settings-modal/settings-modal.ts @@ -26,7 +26,6 @@ export class SettingsModal implements OnInit, OnDestroy { readonly graphicsIcon = faImage; readonly exportIcon = faDownload; readonly importIcon = faUpload; - @Output() close = new EventEmitter(); account: AccountSettings = {}; browser: BrowserSettings = {}; From 70eed8c686cf75e2b7f66cbe8b5ddcd1a4b5c28c Mon Sep 17 00:00:00 2001 From: Stubenhocker1399 Date: Tue, 10 Sep 2019 15:39:09 +0200 Subject: [PATCH 11/17] Tweak some single line elseifs --- src/ts/components/shared/chat-box/chat-box.ts | 11 +++++++---- src/ts/components/shared/chat-log/chat-log.ts | 16 +++++++++------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/ts/components/shared/chat-box/chat-box.ts b/src/ts/components/shared/chat-box/chat-box.ts index 878920a..30f9217 100644 --- a/src/ts/components/shared/chat-box/chat-box.ts +++ b/src/ts/components/shared/chat-box/chat-box.ts @@ -98,15 +98,18 @@ export class ChatBox implements AfterViewInit, OnDestroy { } addEmoji(emoji: string) { this.toggleEmojiBox(); - if (!this.message) this.message = emoji; - else if (this.input.maxLength > this.message.length) { + if (!this.message) { + this.message = emoji; + } else if (this.input.maxLength > this.message.length) { this.message += emoji; } } toggleEmojiBox() { - if (this.emojiBoxState === 'none') + if (this.emojiBoxState === 'none') { this.emojiBoxState = 'inline-block'; - else this.emojiBoxState = 'none'; + } else { + this.emojiBoxState = 'none'; + } } send(_event: Event | undefined) { let chatType = this.chatType; diff --git a/src/ts/components/shared/chat-log/chat-log.ts b/src/ts/components/shared/chat-log/chat-log.ts index 6739f47..67e56dd 100644 --- a/src/ts/components/shared/chat-log/chat-log.ts +++ b/src/ts/components/shared/chat-log/chat-log.ts @@ -455,8 +455,9 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { this.unFocus(); this.filterChatLogLines('', false); return; + } else { + this.filterColor = this.bg; } - else this.filterColor = this.bg; this.autoClear = setTimeout(() => { this.filterTab.nativeElement.value = ''; @@ -470,8 +471,9 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { let toLowerCase = false; - if (value.startsWith('#')) value = value.slice(1); - else if (value.startsWith('/')) { + if (value.startsWith('#')) { + value = value.slice(1); + } else if (value.startsWith('/')) { value = value.slice(1); try { const regExp = new RegExp(value); @@ -482,8 +484,7 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { this.filterTab.nativeElement.style.color = '#ff6666'; } return; - } - else { + } else { value = value.toLowerCase(); toLowerCase = true; } @@ -499,10 +500,11 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { textContent = textContent.slice(10); if (typeof content === 'string') { - if (caseSensitive) + if (caseSensitive) { lines[i].hidden = !textContent.toLowerCase().includes(content); - else + } else { lines[i].hidden = !textContent.includes(content); + } } else { lines[i].hidden = !textContent.match(content); } From 4a39fb9bec67759cea5915dc5d34d3dfc013790e Mon Sep 17 00:00:00 2001 From: Stubenhocker1399 Date: Wed, 11 Sep 2019 10:42:51 +0200 Subject: [PATCH 12/17] Fix "onMouseEnter" -> "onMouseEnterEmojiButton" --- src/ts/components/shared/chat-box/chat-box.pug | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ts/components/shared/chat-box/chat-box.pug b/src/ts/components/shared/chat-box/chat-box.pug index dd47242..9ea927d 100644 --- a/src/ts/components/shared/chat-box/chat-box.pug +++ b/src/ts/components/shared/chat-box/chat-box.pug @@ -12,7 +12,7 @@ span.emote-sample.mr-2 emote-box([emote]="e.names[0]") - emote-box.game-button.chat-emoji-button([emote]="btnEmoji" (click)="toggleEmojiBox()" (mouseenter)="onMouseEnter($event)") + emote-box.game-button.chat-emoji-button([emote]="btnEmoji" (click)="toggleEmojiBox()" (mouseenter)="onMouseEnterEmojiButton($event)") button.game-button.chat-send-button((click)="send($event)" title="Send message" aria-label="Send message") fa-icon([icon]="sendIcon") From 7deecebe28dd16639b4638a6722d23fa321d315a Mon Sep 17 00:00:00 2001 From: Stubenhocker1399 Date: Wed, 11 Sep 2019 13:40:10 +0200 Subject: [PATCH 13/17] Add search icon to chat filter --- .../components/shared/chat-log/chat-log.pug | 4 +++- .../components/shared/chat-log/chat-log.scss | 8 +++++++ src/ts/components/shared/chat-log/chat-log.ts | 22 ++++++++++++------- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/ts/components/shared/chat-log/chat-log.pug b/src/ts/components/shared/chat-log/chat-log.pug index 2d1aa0e..ba43e59 100644 --- a/src/ts/components/shared/chat-log/chat-log.pug +++ b/src/ts/components/shared/chat-log/chat-log.pug @@ -13,7 +13,9 @@ | Party a.link-plain.chat-log-tab(#whisperTab tabindex (click)="switchTab('whisper')") | Whisper - input.link-plain.chat-log-tab.chat-log-filter(#filterTab type="text" [style.background-color]="filterColor" (keyup.enter)="(unFocus())" (keyup.esc)="(unFocus())" [placeholder]="'Filter'" (keyup)="filterChat()") + a.link-plain.chat-log-tab([style.background-color]="filterColor" (click)="focus()") + fa-icon.search-icon([icon]="searchIcon") + input.chat-log-filter(#filterInput type="text" (keyup.enter)="(unFocus())" (keyup.esc)="(unFocus())" [placeholder]="'Filter'" (keyup)="filterChat()") .chat-log-scroll-outer() .chat-log-scroll-inner(#scroll) .chat-log-scroll-inner-inner(#lines) diff --git a/src/ts/components/shared/chat-log/chat-log.scss b/src/ts/components/shared/chat-log/chat-log.scss index f9cfce1..398cc7b 100644 --- a/src/ts/components/shared/chat-log/chat-log.scss +++ b/src/ts/components/shared/chat-log/chat-log.scss @@ -159,10 +159,18 @@ $resizer-offset: $resizer-size / 2; color: rgba(255, 255, 255, 0.2); } +.search-icon { + padding-right: 5px; +} + .chat-log-filter { padding-bottom: 5px; border: none; width: 100px; + background-color: rgba(0, 0, 0, 0); + border: none; + outline: none; + color: white; } .chat-log-filter::-webkit-input-placeholder { diff --git a/src/ts/components/shared/chat-log/chat-log.ts b/src/ts/components/shared/chat-log/chat-log.ts index 67e56dd..c6c8734 100644 --- a/src/ts/components/shared/chat-log/chat-log.ts +++ b/src/ts/components/shared/chat-log/chat-log.ts @@ -9,7 +9,7 @@ import { SettingsService } from '../../services/settingsService'; import { AgDragEvent } from '../directives/agDrag'; import { element, textNode, removeAllNodes, replaceNodes } from '../../../client/htmlUtils'; import { DEFAULT_CHATLOG_OPACITY, PONY_TYPE, SECOND } from '../../../common/constants'; -import { faCaretUp, faArrowDown } from '../../../client/icons'; +import { faCaretUp, faArrowDown, faSearch } from '../../../client/icons'; import { sampleMessages } from '../../../common/debugData'; import { findEntityById } from '../../../common/worldMap'; import { colorToRGBA, rgb2hsl, HSL, hsl2CSS } from '../../../common/color'; @@ -209,13 +209,14 @@ function findUserIndex(users: IndexEntryUser[], id: number, crc: number | undefi export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { readonly toBottomIcon = faArrowDown; readonly resizeIcon = faCaretUp; + readonly searchIcon = faSearch; @ViewChild('chatLog', { static: true }) chatLog!: ElementRef; @ViewChild('scroll', { static: true }) scroll!: ElementRef; @ViewChild('lines', { static: true }) lines!: ElementRef; @ViewChild('localTab', { static: true }) localTab!: ElementRef; @ViewChild('partyTab', { static: true }) partyTab!: ElementRef; @ViewChild('whisperTab', { static: true }) whisperTab!: ElementRef; - @ViewChild('filterTab', { static: true }) filterTab!: ElementRef; + @ViewChild('filterInput', { static: true }) filterInput!: ElementRef; @ViewChild('toggleButton', { static: true }) toggleButton!: ElementRef; @ViewChild('count', { static: true }) countElement!: ElementRef; @ViewChild('content', { static: true }) contentElement!: ElementRef; @@ -449,7 +450,7 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { filterChat() { this.clearTimeOutAutoClear(); this.clearTimeOutAutoUnfocus(); - let value = this.filterTab.nativeElement.value; + let value = this.filterInput.nativeElement.value; if (!value) { this.clearTimeOutAutoClear(); this.unFocus(); @@ -460,7 +461,7 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { } this.autoClear = setTimeout(() => { - this.filterTab.nativeElement.value = ''; + this.filterInput.nativeElement.value = ''; this.filterChat(); this.unFocus(); }, SECOND * 30); @@ -478,10 +479,10 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { try { const regExp = new RegExp(value); this.filterChatLogLines(regExp, toLowerCase); - this.filterTab.nativeElement.style.color = ''; + this.filterInput.nativeElement.style.color = ''; } catch (err) {// If the user inputs invalid regExp we just notify him by changing text color to red if (DEVELOPMENT) console.error(err); - this.filterTab.nativeElement.style.color = '#ff6666'; + this.filterInput.nativeElement.style.color = '#ff6666'; } return; } else { @@ -566,10 +567,15 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { if (this.autoUnfocus) clearTimeout(this.autoUnfocus); this.autoUnfocus = undefined; } + focus() { + this.clearTimeOutAutoUnfocus(); + if (this.filterInput.nativeElement) + this.filterInput.nativeElement.focus(); + } unFocus() { this.clearTimeOutAutoUnfocus(); - if (this.filterTab.nativeElement) - this.filterTab.nativeElement.blur(); + if (this.filterInput.nativeElement) + this.filterInput.nativeElement.blur(); } addMessage(message: ChatMessage) { if (message.name && message.message) { From b8595dce7f18b58e503e5f83e22af5c6f589e96e Mon Sep 17 00:00:00 2001 From: Stubenhocker1399 Date: Wed, 11 Sep 2019 13:43:10 +0200 Subject: [PATCH 14/17] Fix filter text staying red after invalid search --- src/ts/components/shared/chat-log/chat-log.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ts/components/shared/chat-log/chat-log.ts b/src/ts/components/shared/chat-log/chat-log.ts index c6c8734..151f216 100644 --- a/src/ts/components/shared/chat-log/chat-log.ts +++ b/src/ts/components/shared/chat-log/chat-log.ts @@ -472,6 +472,7 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { let toLowerCase = false; + this.filterInput.nativeElement.style.color = ''; if (value.startsWith('#')) { value = value.slice(1); } else if (value.startsWith('/')) { @@ -479,7 +480,6 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { try { const regExp = new RegExp(value); this.filterChatLogLines(regExp, toLowerCase); - this.filterInput.nativeElement.style.color = ''; } catch (err) {// If the user inputs invalid regExp we just notify him by changing text color to red if (DEVELOPMENT) console.error(err); this.filterInput.nativeElement.style.color = '#ff6666'; From d78bf6b36610458302b055f30a988b31e9bc9458 Mon Sep 17 00:00:00 2001 From: Stubenhocker1399 Date: Wed, 11 Sep 2019 14:24:53 +0200 Subject: [PATCH 15/17] Fix filter bar on mobile & slim layout --- .../components/shared/chat-log/chat-log.pug | 2 +- .../components/shared/chat-log/chat-log.scss | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/ts/components/shared/chat-log/chat-log.pug b/src/ts/components/shared/chat-log/chat-log.pug index ba43e59..a69607d 100644 --- a/src/ts/components/shared/chat-log/chat-log.pug +++ b/src/ts/components/shared/chat-log/chat-log.pug @@ -13,7 +13,7 @@ | Party a.link-plain.chat-log-tab(#whisperTab tabindex (click)="switchTab('whisper')") | Whisper - a.link-plain.chat-log-tab([style.background-color]="filterColor" (click)="focus()") + a.link-plain.chat-log-tab.chat-log-filter-tab([style.background-color]="filterColor" (click)="focus()") fa-icon.search-icon([icon]="searchIcon") input.chat-log-filter(#filterInput type="text" (keyup.enter)="(unFocus())" (keyup.esc)="(unFocus())" [placeholder]="'Filter'" (keyup)="filterChat()") .chat-log-scroll-outer() diff --git a/src/ts/components/shared/chat-log/chat-log.scss b/src/ts/components/shared/chat-log/chat-log.scss index 398cc7b..084592e 100644 --- a/src/ts/components/shared/chat-log/chat-log.scss +++ b/src/ts/components/shared/chat-log/chat-log.scss @@ -160,17 +160,27 @@ $resizer-offset: $resizer-size / 2; } .search-icon { - padding-right: 5px; + position: relative; + float: left; + width: 0; + bottom: -1px; + left: 0; + z-index: 2; +} + +.chat-log-filter-tab { + width: 100px; } .chat-log-filter { padding-bottom: 5px; border: none; - width: 100px; background-color: rgba(0, 0, 0, 0); border: none; outline: none; - color: white; + color: white; + padding-left: 20px; + width: 100%; } .chat-log-filter::-webkit-input-placeholder { @@ -200,11 +210,12 @@ $resizer-offset: $resizer-size / 2; } @media only screen and (max-width: 360px) { - .chat-log-filter { + .chat-log-filter-tab { position: absolute; left: 0; bottom: 35px; width: 100%; + width: calc(100% - 10px); border-radius: 2px; } } From e12f135d364566ef2a3817b06a2278cdab82ebd3 Mon Sep 17 00:00:00 2001 From: Terncode Date: Wed, 11 Sep 2019 15:07:54 +0200 Subject: [PATCH 16/17] removed unused code and improved imports --- src/ts/components/shared/chat-box/chat-box.ts | 4 ++-- src/ts/components/shared/chat-log/chat-log.ts | 6 ------ 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/ts/components/shared/chat-box/chat-box.ts b/src/ts/components/shared/chat-box/chat-box.ts index 30f9217..32748a9 100644 --- a/src/ts/components/shared/chat-box/chat-box.ts +++ b/src/ts/components/shared/chat-box/chat-box.ts @@ -13,7 +13,7 @@ import { AutocompleteState, autocompleteMesssage, replaceEmojis, emojis } from ' import { replaceNodes } from '../../../client/htmlUtils'; import { invalidEnumReturn } from '../../../common/utils'; import { findMatchingEntityNames, findEntityOrMockByAnyMeans, findBestEntityByName } from '../../../client/handlers'; -import * as _ from 'lodash'; +import { sample } from 'lodash'; const chatTypeNames: string[] = []; const chatTypeClasses: string[] = []; @@ -295,7 +295,7 @@ export class ChatBox implements AfterViewInit, OnDestroy { } onMouseEnterEmojiButton(event: MouseEvent) { if (!event.target) return; - const emoji = _.sample(emojis)!; + const emoji = sample(emojis)!; this.btnEmoji = emoji.names[0]; } toggleChatType() { diff --git a/src/ts/components/shared/chat-log/chat-log.ts b/src/ts/components/shared/chat-log/chat-log.ts index 151f216..40d8ef4 100644 --- a/src/ts/components/shared/chat-log/chat-log.ts +++ b/src/ts/components/shared/chat-log/chat-log.ts @@ -530,12 +530,6 @@ export class ChatLog implements AfterViewInit, OnDestroy, DoCheck { } return hsl; } - fixColor(color: string) { - while (color.length <= 7) { - color = `0${color}`; - } - return color.substr(0, 6); - } private getCharacterColors(id: number | undefined) { if (!id) return; const entity = findEntityById(this.game.map, id) as Pony; From b75b2b7b1811a2949438cc209bbc45ec3ba3cdd9 Mon Sep 17 00:00:00 2001 From: Stubenhocker1399 Date: Wed, 11 Sep 2019 17:05:11 +0200 Subject: [PATCH 17/17] Fix settings modal chat log range margin --- src/ts/components/shared/settings-modal/settings-modal.pug | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ts/components/shared/settings-modal/settings-modal.pug b/src/ts/components/shared/settings-modal/settings-modal.pug index 7dcf473..64c0d60 100644 --- a/src/ts/components/shared/settings-modal/settings-modal.pug +++ b/src/ts/components/shared/settings-modal/settings-modal.pug @@ -88,6 +88,7 @@ [(value)]="account.chatlogOpacity" style="max-width: 300px" labelledBy="chatlog-opacity-label") | {{(account.chatlogOpacity / 100) | percent}} small.form-text.text-muted.mt-0 Changes chatlog background to make it more readable or less obtrusive. + .form-group label#chatlog-range-label Chatlog range div slider-bar.mr-2(