icy3dw/src/client/object/chat.ts

185 lines
4.8 KiB
TypeScript

import { isMobileOrTablet, rand } from '../../common/helper';
import seedrandom from 'seedrandom';
const nameColorPallete = {
H: [1, 360],
S: [30, 100],
L: [50, 100],
};
export class Chat {
public element = document.createElement('div');
private _history = document.createElement('div');
private _wrapper = document.createElement('div');
private _mobToggle = document.createElement('button');
private _inpBox = document.createElement('div');
private _input = document.createElement('input');
private _visible = true;
private _rehide = false;
private _keyhandler = true;
private _sendFn?: (message: string) => void;
get visible() {
return this._visible;
}
initialize() {
this.element.classList.add('chat__wrapper');
this._wrapper.classList.add('chat');
this._history.classList.add('chat__history');
this._inpBox.classList.add('chat__input-wrapper');
this._input.classList.add('chat__input');
this._mobToggle.classList.add('chat__toggle');
this._inpBox.append(this._input);
this._wrapper.append(this._history, this._inpBox);
this.element.append(this._mobToggle, this._wrapper);
this._input.setAttribute(
'placeholder',
'Type a message here and press Enter to send...',
);
this._input.setAttribute('maxlength', '260');
this._input.addEventListener('keydown', (e) => {
e.stopPropagation();
if (e.key === 'Enter') {
if (!this._input.value?.trim()) {
this._input.blur();
if (this._rehide) {
this.hide();
this._rehide = false;
}
return;
}
if (this._sendFn) {
this._sendFn(this._input.value);
}
this._input.value = null;
if (this._rehide) {
this.hide();
this._rehide = false;
}
} else if (e.key === 'Escape') {
this._input.blur();
this._input.value = null;
if (this._rehide) {
this.hide();
this._rehide = false;
}
}
});
this._input.addEventListener('focus', () => {
this.element.classList.add('focused');
});
this._input.addEventListener('blur', () => {
this.element.classList.remove('focused');
});
this._mobToggle.addEventListener('click', () => {
if (this._visible) {
this.hide();
} else {
this.focus();
}
});
window.addEventListener('keydown', (e) => {
if (!this._keyhandler) {
return;
}
if (e.key === 'Enter' && (e.target as HTMLElement).tagName !== 'INPUT') {
this.focus(!this.visible);
}
});
document.body.append(this.element);
if (!isMobileOrTablet()) {
this.show();
} else {
this.hide();
}
}
public registerSendFunction(fn: (message: string) => void) {
this._sendFn = fn;
}
public show() {
this._visible = true;
this._wrapper.classList.add('visible');
this._wrapper.classList.remove('invisible');
}
public hide() {
this._visible = false;
this._wrapper.classList.remove('visible');
this._wrapper.classList.add('invisible');
}
public focus(rehide = false) {
if (!this._visible) {
this.show();
}
this._input.focus();
this._rehide = rehide;
}
public addMessage(sender: string, message: string, meta?: any) {
const msg = document.createElement('div');
const msgSender = document.createElement('div');
const msgTime = document.createElement('div');
const msgContent = document.createElement('div');
msg.classList.add('chat__message');
msgTime.classList.add('chat__message-timestamp');
msgSender.classList.add('chat__message-sender');
msgContent.classList.add('chat__message-content');
msg.append(msgTime, msgSender, msgContent);
const stamp = meta?.time ? new Date(meta.time) : new Date();
// TODO: timestamp utility
msgTime.innerText = `${stamp.getHours().toString().padStart(2, '0')}:${stamp
.getMinutes()
.toString()
.padStart(2, '0')}`;
msgSender.innerText = sender;
msgSender.style.setProperty('--name-color', this.getNameColor(sender));
msgContent.innerText = message;
// const bottomed = this._history.scrollTop ,this._history.scrollHeight;
this._history.append(msg);
this._history.scrollTop = this._history.scrollHeight;
setTimeout(() => {
msg.classList.add('chat__message--old');
}, 5000);
}
public getNameColor(name: string) {
const randgen = seedrandom(name);
const h = rand(randgen, nameColorPallete.H[0], nameColorPallete.H[1]);
const s = rand(randgen, nameColorPallete.S[0], nameColorPallete.S[1]);
const l = rand(randgen, nameColorPallete.L[0], nameColorPallete.L[1]);
return 'hsl(' + h + ',' + s + '%,' + l + '%)';
}
public setKeyHandlerEnabled(isEnabled: boolean) {
this._keyhandler = isEnabled;
}
}